1
|
#include "ide.h"
|
2
|
|
3
|
#ifdef _DEBUG
|
4
|
#define LSLOW()
|
5
|
#else
|
6
|
#define LSLOW()
|
7
|
#endif
|
8
|
|
9
|
SelectPackageDlg::SelectPackageDlg(const char *title, bool selectvars_, bool main)
|
10
|
: selectvars(selectvars_)
|
11
|
{
|
12
|
CtrlLayoutOKCancel(*this, title);
|
13
|
Sizeable().Zoomable();
|
14
|
Icon(IdeImg::Package(), IdeImg::PackageLarge());
|
15
|
base.AutoHideSb();
|
16
|
base.NoGrid();
|
17
|
base.AddColumn("Assembly");
|
18
|
base.WhenCursor = THISBACK(OnBase);
|
19
|
base.WhenBar = THISBACK(ToolBase);
|
20
|
base.WhenLeftDouble = THISBACK(OnBaseEdit);
|
21
|
ok <<= clist.WhenLeftDouble = alist.WhenLeftDouble = THISBACK(OnOK);
|
22
|
cancel <<= WhenClose = THISBACK(OnCancel);
|
23
|
clist.Columns(4);
|
24
|
clist.WhenEnterItem = clist.WhenKillCursor = THISBACK(ListCursor);
|
25
|
alist.AddColumn("Package").Add(3);
|
26
|
alist.AddColumn("Nest");
|
27
|
alist.AddColumn("Description");
|
28
|
alist.AddIndex();
|
29
|
alist.ColumnWidths("108 79 317");
|
30
|
alist.WhenCursor = THISBACK(ListCursor);
|
31
|
alist.EvenRowColor();
|
32
|
alist.SetLineCy(max(16, Draw::GetStdFontCy()));
|
33
|
list.Add(clist.SizePos());
|
34
|
list.Add(alist.SizePos());
|
35
|
splitter.Horz(base, list);
|
36
|
splitter.SetPos(2000);
|
37
|
splitter.Zoom(selectvars ? -1 : 1);
|
38
|
newu <<= THISBACK(OnNew);
|
39
|
filter <<= THISBACK(OnFilter);
|
40
|
filter.Add(MAIN|FIRST, "Main packages of first nest");
|
41
|
filter.Add(MAIN, "All main packages");
|
42
|
filter.Add(FIRST, "All packages of first nest");
|
43
|
filter.Add(0, "All packages");
|
44
|
filter <<= main ? MAIN|FIRST : 0;
|
45
|
progress.Hide();
|
46
|
brief <<= THISBACK(SyncBrief);
|
47
|
search.NullText("Search (Ctrl+K)", StdFont().Italic(), SColorDisabled());
|
48
|
search <<= THISBACK(SyncList);
|
49
|
search.SetFilter(CharFilterDefaultToUpperAscii);
|
50
|
SyncBrief();
|
51
|
description.NullText("Package description (Alt+Enter)", StdFont().Italic(), SColorDisabled());
|
52
|
description <<= THISBACK(ChangeDescription);
|
53
|
ActiveFocus(brief ? (Ctrl&)clist : (Ctrl&)alist);
|
54
|
clist.BackPaintHint();
|
55
|
alist.BackPaintHint();
|
56
|
base.BackPaintHint();
|
57
|
loadi = 0;
|
58
|
loading = false;
|
59
|
}
|
60
|
|
61
|
bool SelectPackageDlg::Key(dword key, int count)
|
62
|
{
|
63
|
if(key == K_ALT_ENTER) {
|
64
|
ChangeDescription();
|
65
|
return true;
|
66
|
}
|
67
|
else if(key == K_CTRL_K) {
|
68
|
search.SetFocus();
|
69
|
return true;
|
70
|
}
|
71
|
if((clist.HasFocus() || alist.HasFocus()) && search.Key(key, count))
|
72
|
return true;
|
73
|
return TopWindow::Key(key, count);
|
74
|
}
|
75
|
|
76
|
void SelectPackageDlg::Serialize(Stream& s)
|
77
|
{
|
78
|
SerializePlacement(s);
|
79
|
s % brief;
|
80
|
}
|
81
|
|
82
|
String SelectPackageDlg::GetCurrentName()
|
83
|
{
|
84
|
if(clist.IsShown())
|
85
|
return clist.GetCurrentName();
|
86
|
else
|
87
|
if(alist.IsCursor())
|
88
|
return alist.Get(0);
|
89
|
return Null;
|
90
|
}
|
91
|
|
92
|
int SelectPackageDlg::GetCurrentIndex()
|
93
|
{
|
94
|
String s = GetCurrentName();
|
95
|
for(int i = 0; i < packages.GetCount(); i++)
|
96
|
if(packages[i].package == s)
|
97
|
return i;
|
98
|
return -1;
|
99
|
}
|
100
|
|
101
|
void SelectPackageDlg::ChangeDescription()
|
102
|
{
|
103
|
int ii = GetCurrentIndex();
|
104
|
if(ii >= 0 && ii < packages.GetCount()) {
|
105
|
PkInfo& p = packages[ii];
|
106
|
WithDescriptionLayout<TopWindow> dlg;
|
107
|
CtrlLayoutOKCancel(dlg, "Package description");
|
108
|
String pp = PackagePath(p.package);
|
109
|
Package pkg;
|
110
|
if(!pkg.Load(pp)) {
|
111
|
Exclamation("Package does not exist.");
|
112
|
return;
|
113
|
}
|
114
|
dlg.text <<= pkg.description;
|
115
|
if(dlg.Run() != IDOK)
|
116
|
return;
|
117
|
pkg.description = ~dlg.text;
|
118
|
pkg.Save(pp);
|
119
|
p.description = description <<= ~dlg.text;
|
120
|
if(alist.IsCursor())
|
121
|
alist.Set(2, ~dlg.text);
|
122
|
}
|
123
|
}
|
124
|
|
125
|
void SelectPackageDlg::ListCursor()
|
126
|
{
|
127
|
int c = GetCurrentIndex();
|
128
|
if(c >= 0 && c < packages.GetCount()) {
|
129
|
String pp = PackagePath(GetCurrentName());
|
130
|
Package pkg;
|
131
|
pkg.Load(pp);
|
132
|
description <<= pkg.description;
|
133
|
}
|
134
|
else
|
135
|
description <<= Null;
|
136
|
}
|
137
|
|
138
|
void SelectPackageDlg::SyncBrief()
|
139
|
{
|
140
|
bool b = brief;
|
141
|
alist.Show(!b);
|
142
|
clist.Show(b);
|
143
|
}
|
144
|
|
145
|
String SelectPackageDlg::Run(String startwith)
|
146
|
{
|
147
|
finished = canceled = false;
|
148
|
if(!IsSplashOpen())
|
149
|
Open();
|
150
|
if(selectvars)
|
151
|
SyncBase(GetVarsName());
|
152
|
else
|
153
|
OnBase();
|
154
|
String bkvar = GetVarsName();
|
155
|
if(finished)
|
156
|
return GetCurrentName();
|
157
|
if(canceled)
|
158
|
return Null;
|
159
|
alist.FindSetCursor(startwith);
|
160
|
clist.FindSetCursor(startwith);
|
161
|
ActiveFocus(alist.IsShown() ? (Ctrl&)alist : (Ctrl&)clist);
|
162
|
switch(TopWindow::Run()) {
|
163
|
case IDOK: return GetCurrentName();
|
164
|
case IDYES: return selected;
|
165
|
default:
|
166
|
LoadVars(bkvar);
|
167
|
SyncBase(GetVarsName());
|
168
|
return Null;
|
169
|
}
|
170
|
}
|
171
|
|
172
|
void SelectPackageDlg::OnOK()
|
173
|
{
|
174
|
Package pkg;
|
175
|
int f = ~filter;
|
176
|
String n = GetCurrentName();
|
177
|
if(n.GetCount() && pkg.Load(PackagePath(n)) &&
|
178
|
(!(f & MAIN) || pkg.config.GetCount())) {
|
179
|
loading = false;
|
180
|
finished = true;
|
181
|
AcceptBreak(IDOK);
|
182
|
}
|
183
|
}
|
184
|
|
185
|
void SelectPackageDlg::OnCancel()
|
186
|
{
|
187
|
loading = false;
|
188
|
canceled = true;
|
189
|
RejectBreak(IDCANCEL);
|
190
|
}
|
191
|
|
192
|
void SelectPackageDlg::OnFilter()
|
193
|
{
|
194
|
SyncList();
|
195
|
}
|
196
|
|
197
|
void SelectPackageDlg::OnBase()
|
198
|
{
|
199
|
if(!finished && !canceled)
|
200
|
Load();
|
201
|
}
|
202
|
|
203
|
void SelectPackageDlg::OnNew() {
|
204
|
TemplateDlg dlg;
|
205
|
LoadFromGlobal(dlg, "NewPackage");
|
206
|
int f = ~filter;
|
207
|
dlg.Load(GetUppDirs(), f & MAIN);
|
208
|
while(dlg.Run() == IDOK) {
|
209
|
String nest = ~dlg.nest;
|
210
|
String name = NativePath(String(~dlg.package));
|
211
|
String path = AppendFileName(nest, AppendFileName(name, GetFileName(name) + ".upp"));
|
212
|
if(FileExists(path) && !PromptYesNo("Package [* \1" + path + "\1] already exists.&"
|
213
|
"Do you wish to recreate the files?"))
|
214
|
continue;
|
215
|
RealizePath(path);
|
216
|
if(!SaveFile(path, Null)) {
|
217
|
Exclamation("Error writing the file [* \1" + path + "\1].");
|
218
|
continue;
|
219
|
}
|
220
|
dlg.Create();
|
221
|
selected = name;
|
222
|
Break(IDYES);
|
223
|
break;
|
224
|
}
|
225
|
StoreToGlobal(dlg, "NewPackage");
|
226
|
}
|
227
|
|
228
|
Vector<String> SelectPackageDlg::GetSvnDirs()
|
229
|
{
|
230
|
Vector<String> r;
|
231
|
Vector<String> dirs = SplitDirs(GetVar("UPP"));
|
232
|
for(int i = 0; i < dirs.GetCount(); i++) {
|
233
|
String d = NormalizePath(dirs[i]);
|
234
|
if(IsSvnDir(d))
|
235
|
r.Add(d);
|
236
|
}
|
237
|
return r;
|
238
|
}
|
239
|
|
240
|
void SelectPackageDlg::SyncSvnDir(const String& dir)
|
241
|
{
|
242
|
SvnSyncDirs(Vector<String>() << dir);
|
243
|
Load();
|
244
|
}
|
245
|
|
246
|
void SelectPackageDlg::SyncSvnDirs()
|
247
|
{
|
248
|
SvnSyncDirs(GetSvnDirs());
|
249
|
Load();
|
250
|
}
|
251
|
|
252
|
void SelectPackageDlg::ToolBase(Bar& bar)
|
253
|
{
|
254
|
bar.Add("New assembly..", THISBACK(OnBaseAdd))
|
255
|
.Key(K_INSERT);
|
256
|
bar.Add(base.IsCursor(), "Edit assembly..", THISBACK(OnBaseEdit))
|
257
|
.Key(K_CTRL_ENTER);
|
258
|
bar.Add(base.IsCursor(), "Remove assembly", THISBACK(OnBaseRemove))
|
259
|
.Key(K_CTRL_DELETE);
|
260
|
Vector<String> d = GetSvnDirs();
|
261
|
if(d.GetCount()) {
|
262
|
bar.Separator();
|
263
|
for(int i = 0; i < d.GetCount(); i++)
|
264
|
bar.Add("Synchronize " + d[i], IdeImg::svn_dir(), THISBACK1(SyncSvnDir, d[i]));
|
265
|
bar.Add("Synchronize everything..", IdeImg::svn(), THISBACK(SyncSvnDirs));
|
266
|
}
|
267
|
}
|
268
|
|
269
|
void SelectPackageDlg::OnBaseAdd()
|
270
|
{
|
271
|
String vars;
|
272
|
if(BaseSetup(vars))
|
273
|
SyncBase(vars);
|
274
|
}
|
275
|
|
276
|
void SelectPackageDlg::OnBaseEdit()
|
277
|
{
|
278
|
if(!base.IsCursor())
|
279
|
return;
|
280
|
String vars = base.Get(0), oldvars = vars;
|
281
|
if(BaseSetup(vars)) {
|
282
|
if(vars != oldvars)
|
283
|
DeleteFile(VarFilePath(oldvars));
|
284
|
DeleteFile(CachePath(vars));
|
285
|
SyncBase(vars);
|
286
|
}
|
287
|
}
|
288
|
|
289
|
void SelectPackageDlg::OnBaseRemove()
|
290
|
{
|
291
|
int c = base.GetCursor();
|
292
|
if(c < 0)
|
293
|
return;
|
294
|
String next;
|
295
|
if(c + 1 < base.GetCount())
|
296
|
next = base.Get(c + 1);
|
297
|
else if(c > 0)
|
298
|
next = base.Get(c - 1);
|
299
|
String vars = base.Get(0);
|
300
|
String varpath = VarFilePath(vars);
|
301
|
if(PromptOKCancel(NFormat("Remove base file [* \1%s\1]?", varpath)) && !FileDelete(varpath))
|
302
|
Exclamation(NFormat("Error deleting file [* \1%s\1].", varpath));
|
303
|
SyncBase(next);
|
304
|
}
|
305
|
|
306
|
int DirSep(int c)
|
307
|
{
|
308
|
return c == '\\' || c == '/' ? c : 0;
|
309
|
}
|
310
|
|
311
|
struct PackageDisplay : Display {
|
312
|
Font fnt;
|
313
|
|
314
|
virtual Size GetStdSize(const Value& q) const {
|
315
|
ValueArray va = q;
|
316
|
Size sz = GetTextSize(String(va[0]), fnt);
|
317
|
sz.cx += 20;
|
318
|
sz.cy = max(sz.cy, 16);
|
319
|
return sz;
|
320
|
}
|
321
|
|
322
|
virtual void Paint(Draw& w, const Rect& r, const Value& q, Color ink, Color paper, dword style) const {
|
323
|
ValueArray va = q;
|
324
|
String txt = va[0];
|
325
|
Image icon = va[1];
|
326
|
w.DrawRect(r, paper);
|
327
|
w.DrawImage(r.left, r.top + (r.Height() - 16) / 2, IsNull(icon) ? IdeImg::Package() : icon);
|
328
|
w.DrawText(r.left + 20, r.top + (r.Height() - Draw::GetStdFontCy()) / 2, txt, fnt, ink);
|
329
|
}
|
330
|
|
331
|
PackageDisplay() { fnt = StdFont(); }
|
332
|
};
|
333
|
|
334
|
void SelectPackageDlg::SyncList()
|
335
|
{
|
336
|
String n = GetCurrentName();
|
337
|
int asc = alist.GetScroll();
|
338
|
int csc = clist.GetSbPos();
|
339
|
|
340
|
packages.Clear();
|
341
|
String s = ~search;
|
342
|
int f = ~filter;
|
343
|
Index<String> added;
|
344
|
for(int i = 0; i < min((f & FIRST) ? 1 : data.GetCount(), data.GetCount()); i++) {
|
345
|
const ArrayMap<String, PkData>& nest = data[i];
|
346
|
for(int i = 0; i < nest.GetCount(); i++) {
|
347
|
const PkData& d = nest[i];
|
348
|
if(!nest.IsUnlinked(i) &&
|
349
|
d.ispackage &&
|
350
|
(!(f & MAIN) || d.main) &&
|
351
|
ToUpper(d.package + d.description + d.nest).Find(s) >= 0 &&
|
352
|
added.Find(d.package) < 0) {
|
353
|
packages.Add() = d;
|
354
|
added.Add(d.package);
|
355
|
}
|
356
|
}
|
357
|
}
|
358
|
Sort(packages);
|
359
|
alist.Clear();
|
360
|
clist.Clear();
|
361
|
ListCursor();
|
362
|
static PackageDisplay pd, bpd;
|
363
|
bpd.fnt.Bold();
|
364
|
for(int i = 0; i < packages.GetCount(); i++) {
|
365
|
const PkInfo& pkg = packages[i];
|
366
|
clist.Add(pkg.package, IsNull(pkg.icon) ? IdeImg::Package() : pkg.icon);
|
367
|
alist.Add(pkg.package, pkg.nest, pkg.description, pkg.icon);
|
368
|
alist.SetDisplay(alist.GetCount() - 1, 0, pkg.main ? bpd : pd);
|
369
|
}
|
370
|
if(!alist.FindSetCursor(n))
|
371
|
alist.GoBegin();
|
372
|
if(!clist.FindSetCursor(n) && clist.GetCount())
|
373
|
clist.SetCursor(0);
|
374
|
alist.ScrollTo(asc);
|
375
|
clist.SetSbPos(csc);
|
376
|
}
|
377
|
|
378
|
void SelectPackageDlg::ScanFolder(const String& path, ArrayMap<String, PkData>& nd,
|
379
|
const String& nest, Index<String>& dir_exists,
|
380
|
const String& prefix)
|
381
|
{
|
382
|
for(FindFile ff(AppendFileName(path, "*.*")); ff; ff.Next())
|
383
|
if(ff.IsFolder() && !ff.IsHidden()) {
|
384
|
dir_exists.Add(ff.GetPath());
|
385
|
String p = ff.GetPath();
|
386
|
bool nw = nd.Find(p) < 0;
|
387
|
PkData& d = nd.GetAdd(ff.GetPath());
|
388
|
d.package = prefix + ff.GetName();
|
389
|
d.nest = nest;
|
390
|
if(nw) {
|
391
|
d.ispackage = IsLetter(*d.package) && d.package.Find('.') < 0;
|
392
|
d.main = d.ispackage && prefix.GetCount() == 0;
|
393
|
}
|
394
|
}
|
395
|
}
|
396
|
|
397
|
String SelectPackageDlg::CachePath(const char *vn) const
|
398
|
{
|
399
|
return AppendFileName(ConfigFile("cfg"), String(vn) + ".pkg_cache");
|
400
|
}
|
401
|
|
402
|
void SelectPackageDlg::Load()
|
403
|
{
|
404
|
if(selectvars && !base.IsCursor())
|
405
|
return;
|
406
|
if(loading) {
|
407
|
loadi++;
|
408
|
loading = false;
|
409
|
return;
|
410
|
}
|
411
|
int current_loadi = -1;
|
412
|
while(current_loadi != loadi) {
|
413
|
current_loadi = loadi;
|
414
|
if(selectvars) {
|
415
|
String assembly = (String)base.Get(0);
|
416
|
list.Enable(base.IsCursor());
|
417
|
if(!base.IsCursor())
|
418
|
return;
|
419
|
LoadVars(assembly);
|
420
|
}
|
421
|
Vector<String> upp = GetUppDirs();
|
422
|
packages.Clear();
|
423
|
description.Hide();
|
424
|
progress.Show();
|
425
|
loading = true;
|
426
|
data.Clear();
|
427
|
Index<String> dir_exists;
|
428
|
String cache_path = CachePath(GetVarsName());
|
429
|
LoadFromFile(data, cache_path);
|
430
|
data.SetCount(upp.GetCount());
|
431
|
for(int i = 0; i < upp.GetCount(); i++)
|
432
|
ScanFolder(upp[i], data[i], GetFileName(upp[i]), dir_exists, Null);
|
433
|
int update = msecs();
|
434
|
for(int i = 0; i < data.GetCount() && loading; i++) {
|
435
|
ArrayMap<String, PkData>& nest = data[i];
|
436
|
for(int i = 0; i < nest.GetCount() && loading; i++) {
|
437
|
if(msecs(update) >= 100) {
|
438
|
if(!IsSplashOpen() && !IsOpen())
|
439
|
Open();
|
440
|
progress++;
|
441
|
SyncList();
|
442
|
update = msecs();
|
443
|
}
|
444
|
ProcessEvents();
|
445
|
|
446
|
PkData& d = nest[i];
|
447
|
String path = nest.GetKey(i);
|
448
|
FindFile ff(path);
|
449
|
if(ff && ff.IsFolder()) {
|
450
|
String upp_path = AppendFileName(path, GetFileName(d.package) + ".upp");
|
451
|
LSLOW();
|
452
|
Time tm = FileGetTime(upp_path);
|
453
|
if(IsNull(tm))
|
454
|
d.ispackage = false;
|
455
|
else
|
456
|
if(tm != d.tm) {
|
457
|
Package p;
|
458
|
if(p.Load(upp_path)) {
|
459
|
d.description = p.description;
|
460
|
d.main = p.config.GetCount();
|
461
|
d.tm = tm;
|
462
|
d.ispackage = true;
|
463
|
}
|
464
|
else
|
465
|
d.ispackage = false;
|
466
|
}
|
467
|
else
|
468
|
d.ispackage = true;
|
469
|
if(d.ispackage) {
|
470
|
String icon_path = AppendFileName(path, "icon16x16.png");
|
471
|
tm = FileGetTime(icon_path);
|
472
|
if(IsNull(tm))
|
473
|
d.icon = Null;
|
474
|
else
|
475
|
if(tm != d.itm) {
|
476
|
d.icon = StreamRaster::LoadFileAny(icon_path);
|
477
|
d.itm = tm;
|
478
|
}
|
479
|
}
|
480
|
}
|
481
|
else
|
482
|
nest.Unlink(i);
|
483
|
ScanFolder(path, nest, d.nest, dir_exists, d.package + '/');
|
484
|
}
|
485
|
nest.Sweep();
|
486
|
}
|
487
|
|
488
|
StoreToFile(data, cache_path);
|
489
|
progress.Hide();
|
490
|
while(IsSplashOpen())
|
491
|
ProcessEvents();
|
492
|
if(!IsOpen())
|
493
|
Open();
|
494
|
description.Show();
|
495
|
if(loading) {
|
496
|
loading = false;
|
497
|
SyncList();
|
498
|
}
|
499
|
}
|
500
|
}
|
501
|
|
502
|
void SelectPackageDlg::SyncBase(String initvars)
|
503
|
{
|
504
|
Vector<String> varlist;
|
505
|
for(FindFile ff(ConfigFile("*.var")); ff; ff.Next())
|
506
|
if(ff.IsFile())
|
507
|
varlist.Add(GetFileTitle(ff.GetName()));
|
508
|
Sort(varlist, &PackageLess);
|
509
|
base.Clear();
|
510
|
Append(base, varlist);
|
511
|
if(!base.FindSetCursor(initvars))
|
512
|
if(base.GetCount() > 0)
|
513
|
base.SetCursor(0);
|
514
|
else
|
515
|
OnBase();
|
516
|
}
|
517
|
|
518
|
bool SelectPackageDlg::Pless(const SelectPackageDlg::PkInfo& a, const SelectPackageDlg::PkInfo& b)
|
519
|
{
|
520
|
return PackageLess(a.package, b.package);
|
521
|
}
|
522
|
|
523
|
INITBLOCK
|
524
|
{
|
525
|
RegisterGlobalConfig("SelectPkgMain");
|
526
|
RegisterGlobalConfig("SelectPkg");
|
527
|
}
|
528
|
|
529
|
String SelectPackage(const char *title, const char *startwith, bool selectvars, bool main)
|
530
|
{
|
531
|
SelectPackageDlg dlg(title, selectvars, main);
|
532
|
const char *c = main ? "SelectPkgMain" : "SelectPkg";
|
533
|
LoadFromGlobal(dlg, c);
|
534
|
dlg.SyncBrief();
|
535
|
String b = dlg.Run(startwith);
|
536
|
StoreToGlobal(dlg, c);
|
537
|
return b;
|
538
|
}
|