SelectPkg.cpp

CTRL+K insted of CTRL+Q for search - Zbigniew Rebacz, 11/28/2013 01:11 AM

Download (13.4 KB)

 
1
#include "ide.h"
2

    
3
#ifdef _DEBUG
4
#define LSLOW()    // Sleep(20) // Simulate HD seeks to test package cache
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; // Do we have any info loaded about this package?
387
                        PkData& d = nd.GetAdd(ff.GetPath());
388
                        d.package = prefix + ff.GetName();
389
                        d.nest = nest;
390
                        if(nw) { // No cached info available about the folder
391
                                d.ispackage = IsLetter(*d.package) && d.package.Find('.') < 0; // First heuristic guess
392
                                d.main = d.ispackage && prefix.GetCount() == 0; // Expect it is main
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) { // If we are called recursively from ProcessEvents, stop current loading and change loadi
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++) // Scan nest folders for subfolders (package candidates)
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++) { // Now investigate individual sub folders
435
                        ArrayMap<String, PkData>& nest = data[i];
436
                        for(int i = 0; i < nest.GetCount() && loading; i++) {
437
                                if(msecs(update) >= 100) { // each 100 ms update the list (and open select dialog after splash screen is closed)
438
                                        if(!IsSplashOpen() && !IsOpen())
439
                                                Open();
440
                                        progress++;
441
                                        SyncList();
442
                                        update = msecs();
443
                                }
444
                                ProcessEvents(); // keep GUI running
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)) // .upp file does not exist - not a package
454
                                                d.ispackage = false;
455
                                        else
456
                                        if(tm != d.tm) { // cached info is outdated
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)) // package icon does not exist
473
                                                        d.icon = Null;
474
                                                else
475
                                                if(tm != d.itm) { // chached package icon outdated
476
                                                        d.icon = StreamRaster::LoadFileAny(icon_path);
477
                                                        d.itm = tm;
478
                                                }
479
                                        }
480
                                }
481
                                else 
482
                                        nest.Unlink(i); // cached folder was deleted
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
}