Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

1217
LINES

< > BotCompany Repo | #1033891 // GazelleHost + Stem [dev]

JavaX (incomplete)

1  
lib 1400521 // FlatLAF
2  
3  
set flag PingV3.
4  
set flag NotifyingPrintLog.
5  
set flag SymbolAsString.
6  
7  
// Do the JavaX init
8  
svoid standaloneInit {
9  
  __javax = x30.class;
10  
  x30.__javax = x30.class; // for hotwire
11  
  x30_pkg.x30_util.__setJavaX(x30.class);
12  
  x30.cleanKillMsg = "";
13  
  callOnLoadMethods(mc());
14  
}
15  
16  
concept PrintLogModule > DynPrintLog {
17  
  start { setModuleName("Log"); }
18  
  
19  
  S getPrintLog() {
20  
    ret printLog();
21  
  }
22  
  
23  
  bool useErrorHandling() { false; }
24  
}
25  
26  
concept Stem extends ConceptWithChangeListeners is AutoCloseable {
27  
  transient GazelleHost host;
28  
  transient LoadedDB db;
29  
  DynModule module;
30  
  settableWithVar Rect frameRect;
31  
  bool minimized, maximized, alwaysOnTop, minimizeToTray;
32  
  
33  
  transient JFrame window;
34  
  transient JButton btnMax;
35  
  transient JLabel titleComponent;
36  
  transient gettable JButton compileButton;
37  
  //transient bool autoUpdateDisabled;
38  
  transient bool started;
39  
40  
  *() {}
41  
  *(LoadedDB *db) { host = db.host; }
42  
  *(LoadedDB db, DynModule *module) { this(db); }
43  
  
44  
  transient Component selfVis; // how the module visualized itself
45  
  
46  
  // Not sure why we use LazyVar here instead of simplyCached
47  
  
48  
  transient LazyVar<SingleComponentPanel> scpMainWindowContents = new(-> scp());
49  
  SingleComponentPanel scpMainWindowContents() { ret scpMainWindowContents!; }
50  
51  
  transient LazyVar<SingleComponentPanel> scpMainWindowWithTitle = new(-> scp());
52  
  SingleComponentPanel scpMainWindowWithTitle() { ret scpMainWindowWithTitle!; }
53  
54  
  transient LazyVar<SingleComponentPanel> scpFrameIcon = new(-> scp());
55  
  SingleComponentPanel scpFrameIcon() { ret scpFrameIcon!; }
56  
57  
  Rect grabFrameRect() {
58  
    ret toRect(getBounds(window));
59  
  }
60  
  
61  
  void saveFrameRect {
62  
    frameRect(grabFrameRect());
63  
  }
64  
  
65  
  void restoreFrameRect {
66  
    if (frameRect != null)  
67  
      setBounds(window, frameRect);
68  
  }
69  
  
70  
  void setAlwaysOnTop(bool alwaysOnTop) {
71  
    this.alwaysOnTop = alwaysOnTop;
72  
    change();
73  
    alwaysOnTop(window, alwaysOnTop);
74  
  }
75  
  
76  
  void setMinimizeToTray(bool minimizeToTray) {
77  
    cset(this, +minimizeToTray);
78  
  }
79  
80  
  void setWindow(JFrame window) {  
81  
    this.window = window;
82  
    restoreFrameRect();
83  
    //onWindowClosing(window, -> host.cleanExit());
84  
    onBoundsChange(window, r saveFrameRect);
85  
    
86  
    if (host.restrictWindowsToScreenSize)
87  
      restrictWindowToScreenSize(window);
88  
    
89  
    alwaysOnTop(window, alwaysOnTop);
90  
  }
91  
  
92  
  void activateWindow {
93  
    print("activateWindow: " + window);
94  
    if (window != null)
95  
      activateFrame_v3(window);
96  
    else
97  
      startAndShow(false);
98  
  }
99  
  
100  
  bool isMain() { ret this == db.mainStem; }
101  
  
102  
  void minimize {
103  
    cset(this, minimized := true);
104  
    if (!minimizeToTray || host.trayIcon == null || !isMain())
105  
      minimizeWindow(window);
106  
    else
107  
      hideWindow(window);
108  
  }
109  
  
110  
  void deleteMe {
111  
    temp tempPrintAlsoToSystemOut();
112  
    print("deleteMe " + isMain());
113  
    if (isMain())
114  
      host.closeDatabase(db);
115  
    else
116  
      delete();
117  
  }
118  
  
119  
  close {
120  
    disposeWindow(window);
121  
    cleanUp(module);
122  
  }
123  
  
124  
  void delete :: before {
125  
    close();
126  
  }
127  
  
128  
  void grabWindowState {
129  
    setField(maximized := !isExtendedStateNormal(window));
130  
  }
131  
  
132  
  void updateBtnMax {
133  
    if (!isShowing(btnMax)) ret;
134  
    grabWindowState();
135  
    setText(btnMax, maximized ? "NORM" : "MAX");
136  
  }
137  
  
138  
  JComponent makeWindowBorderAndTitle(JComponent contents, S title) {
139  
    //ret jCenteredSection_fontSizePlus(10, title, vis);
140  
    
141  
    var icons = jline();
142  
    if (host.allowFrameMaximization) {
143  
      icons.add(btnMax = jbutton("", rThread {
144  
        maximizeOrRestoreFrame(window);
145  
        updateBtnMax();
146  
      }));
147  
      onFirstShowing(btnMax, r updateBtnMax);
148  
    }
149  
    
150  
    icons.add(toolTip("Minimize this window", jbutton("MIN", r minimize)));
151  
    icons.add(toolTip("Close this window", jimageButtonScaledToWidth(16, #1103067, rThread deleteMe)));
152  
      
153  
    //setHorizontalMarginForAllButtons(icons, 4);
154  
    icons.add(new JPopDownButton(menu -> fillJPopupMenu(menu, flattenToList(
155  
              
156  
      // always on top
157  
      
158  
      jCheckBoxMenuItem/*_dyn*/("Always on top",
159  
        /*->*/ alwaysOnTop,
160  
        alwaysOnTop -> setAlwaysOnTop(alwaysOnTop)),
161  
        
162  
      // quit, restart + update
163  
      
164  
      "---",
165  
      "Exit Gazelle", rThread { host.cleanExit() },
166  
      "Restart", rThread { host.restart() },
167  
      "Re-open project", rThread { host.reopenDB(db) },
168  
      "Hide project", rThread { db.hide() },
169  
      "Update Gazelle", rThread { host.upgradeGazelle() },
170  
      !isMain() ? null : jCheckBoxMenuItem/*_dyn*/("Auto-Update",
171  
        /*->*/ print(autoUpdate := db.g22utils.autoUpdateEnabled()),
172  
        b -> {
173  
          // save flag
174  
          db.g22utils.setAutoUpdate(b);
175  
          
176  
          // if user just turned on auto-update, do the update
177  
          if (b) thread { host.upgradeGazelle(); }
178  
        }),
179  
180  
      // debugging + screenshooting gazelle
181  
      
182  
      "---",
183  
      !isMain() ? null : ll(
184  
        "Screenshoot this window", rThread shootWindow,
185  
        "Dump threads", rThread { showText("User threads", renderUserThreadsWithStackTraces()); },
186  
        "Log", !isMain() ? null : r { db.showPrintLog() },
187  
        "Copy log to clipboard", !isMain() ? null : rThread {
188  
          copyToClipboard(printLog());
189  
          infoBox("Copied log to clipboard");
190  
        },
191  
        "10 Second Profiler", rThread runTenSecondProfiler,
192  
      ),
193  
      
194  
      ccallOpt(module, "popDownItems")
195  
    ))));
196  
    
197  
    JComponent actualTitle = titleComponent = fontSizePlus(7, jCenteredLabel(title));
198  
    installWindowDragger(actualTitle);
199  
    
200  
    if (/*isMain() &&*/ host.devMode())
201  
      actualTitle = centerAndEastWithMargin(actualTitle,
202  
        jline(
203  
          compileButton = makeCompileButton(),
204  
          installWindowDragger(lblComputerAndUserCount()),
205  
        ));
206  
        
207  
    updateFrameIcon();
208  
    
209  
    var spacer = gazelle_wavySpacer(color1(), color2());
210  
    var titleBarMain = setOpaqueBackground(color1(),
211  
      jtransparent_recursive(westCenterAndEastWithMargin(
212  
        scpFrameIcon(),
213  
        actualTitle,
214  
        setOpaqueBackground(color2(), spacer)));
215  
    
216  
    installWindowDragger(spacer);
217  
    
218  
    var titleBar = setBackground(color2(), centerAndEast(
219  
      titleBarMain,
220  
      icons));
221  
    
222  
    var border =
223  
      // createBevelBorder();
224  
      BorderFactory.createLineBorder(color1(), host.borderSize);
225  
      
226  
    var outerPanel = withBorder(border,
227  
      northAndCenter(titleBar, contents));
228  
      
229  
    installWindowResizeDraggerOnBorder(outerPanel);
230  
    ret markVisualizer(this, outerPanel);
231  
  }
232  
  
233  
  swappable S frameIconID() { ret host.trayIconImageID; }
234  
  swappable int frameIconHeight() { ret 24; }
235  
  
236  
  selfType frameIconID(S iconID) {
237  
    frameIconID = -> iconID;
238  
    updateFrameIcon();
239  
    this;
240  
  }
241  
  
242  
  swappable JComponent makeFrameIcon() {
243  
    ret jImage_scaledToHeight(frameIconHeight(), frameIconID());
244  
  }
245  
  
246  
  void updateFrameIcon {
247  
    scpFrameIcon().set(makeFrameIcon());
248  
  }
249  
  
250  
  swappable Color color1() { ret host.color1; }
251  
  swappable Color color2() { ret host.color2; }
252  
253  
  JLabel lblComputerAndUserCount() {
254  
    JLabel label = jlabel();
255  
    Runnable update = -> {
256  
      Int computerCount = host.computerCount();
257  
      Int userCount = host.lvGazelleUserCount()!;
258  
      setText(label, 
259  
        (computerCount == null ? "" : n2(computerCount))
260  
        + appendSquareBracketed(
261  
          userCount == null ? "" : n2(userCount)));
262  
    };
263  
    bindChangeListenerToComponent(label, host.lvComputerCount(), update);
264  
    bindChangeListenerToComponent(label, host.lvGazelleUserCount(), update);
265  
    ret label;
266  
  }
267  
  
268  
  JButton makeCompileButton() {
269  
    var gears = resizeImageIcon(imageIcon(#1103061), 16);
270  
271  
    var btn = jimageButtonScaledToWidth(16, #1101268, "Compile & update",
272  
      rThread { host.compile() });
273  
    //enableComponentAccordingToVar(host.compileButtonEnabled, btn);
274  
    
275  
    componentPopupMenuItems(btn,
276  
      "Compile all", rThread { host.compileAll() },
277  
      "Compile main library", rThread { host.compileUtilsAndRepackage() },
278  
      "Repackage", rThread { host.repackage() },
279  
    );
280  
    
281  
    ret btn;
282  
  }
283  
  
284  
  JComponent wrapVis(JComponent vis) {
285  
    //ret jMinSize0(vis);
286  
    ret vis;
287  
  }
288  
  
289  
  void startAndShow(bool hidden default false) {
290  
    if (module._host != this) {
291  
      module._host = this;
292  
      setOpt_raw(module, +threadPool); // only if the field exists
293  
      setOpt_raw(module, concepts := db.concepts);
294  
      setOpt_raw(module, g22utils := db.g22utils);
295  
      copyLocalLog(module, mc());
296  
    }
297  
  
298  
    var vis, title = unpair startAndVisualize();
299  
    
300  
    if (!hidden) {
301  
      printWithMS("Show frame");
302  
  
303  
      JFrame frame = makeUndecoratedFrame(title, wrapVis(vis));
304  
      setFrameIcon(frame, host.trayIconImageID);
305  
      setWindow(frame);
306  
      
307  
      frame.addPropertyChangeListener("title", evt ->
308  
        setText(titleComponent, frame.getTitle()));
309  
      
310  
      if (minimized) minimize();
311  
      onWindowDeiconified(frame, -> cset(this, minimized := false));
312  
      
313  
      showWindow(window);
314  
      if (maximized && host.allowFrameMaximization) maximizeFrame(window);
315  
    }
316  
  }
317  
  
318  
  Pair<JComponent, S> startAndVisualize() {
319  
    JComponent vis = null;
320  
    {
321  
      printWithMS("Starting " + module);
322  
      try {
323  
        if (!started) {
324  
          set started;
325  
          temp module.enter();
326  
          module.start();
327  
        }
328  
      
329  
        printWithMS("Visualize");
330  
        vis = swing(-> {
331  
          temp module.enter();
332  
          ret module.visualize();
333  
        });
334  
      } on fail e {
335  
        waitForFrameClose(showErrorFrame(e));
336  
      }
337  
    }
338  
    
339  
    selfVis = vis;
340  
    
341  
    var scp1 = scpMainWindowContents();
342  
    scp1.set(vis);
343  
    
344  
    S title = createTitleText();
345  
    var vis2 = makeWindowBorderAndTitle(scp1, title);
346  
    
347  
    var scp2 = scpMainWindowWithTitle();
348  
    scp2.set(vis2);
349  
    ret pair(scp2, title);
350  
  }
351  
    
352  
  S createTitleText() {
353  
    S moduleName = takeFirst_unnull(800, module.moduleName());
354  
    
355  
    if (isMain())
356  
      // OLD: ret host.windowTitle + appendWithColon(moduleName);
357  
      ret joinNemptiesWithVBar(moduleName, host.windowTitle);
358  
    else
359  
      ret moduleName;
360  
  }
361  
  
362  
  void revisualize {
363  
    if (window == null) ret;
364  
    
365  
    pcall {
366  
      module.unvisualize();
367  
    }
368  
    
369  
    var vis, title = unpair startAndVisualize();
370  
    setFrameContents(window, wrapVis(vis));
371  
  }
372  
  
373  
  void shootWindow {
374  
    var img = renderComponentToImage(window);
375  
    copyImageToClipboard(img);
376  
    File imgFile = saveInImageDirectoryWithCounter(gazelle22_imagesSubDirName() + "/Gazelle", img);
377  
    pcallOpt(module, "addToGallery", imgFile);
378  
  }
379  
  
380  
  // Breaking change 2022 Dec 10 (is this even used?)
381  
  // old: Component vis() { ret getFrameContents(window); }
382  
  Component vis() { ret scpMainWindowContents()!; }
383  
  
384  
  S tenSecondProfilerScript = [[
385  
    temp profiler <- new AllThreadsProfiler
386  
    infoBox "Profiling..."
387  
    profiler start
388  
    sleepSeconds 10
389  
    showText "10 Second Profile" < profiler renderFullResults false
390  
  ]];
391  
  
392  
  File byteCodePath() {
393  
    ret assertNotNull(getBytecodePathForClass(this));
394  
  }
395  
  
396  
  ClassNameResolver classNameResolver() {
397  
    ret new ClassNameResolver().byteCodePath(byteCodePath()).init();
398  
  }
399  
  
400  
  GazelleV_LeftArrowScriptParser leftArrowParser() {
401  
    new GazelleV_LeftArrowScriptParser parser;
402  
    parser.classNameResolver(classNameResolver());
403  
    parser.allowTheWorld(mc(), utils.class);
404  
    ret parser;
405  
  }
406  
  
407  
  void runTenSecondProfiler {
408  
    leftArrow(leftArrowParser(), tenSecondProfilerScript);
409  
  }
410  
} // end of Stem
411  
412  
sclass LoadedDB is AutoCloseable, IG22LoadedDB {
413  
  GazelleHost host;
414  
  gettable Concepts concepts;
415  
  gettable new G22Utils g22utils;
416  
  Stem mainStem;
417  
  gettable bool hidden;
418  
  
419  
  *(GazelleHost *host, Concepts *concepts, bool *hidden) {
420  
    g22utils.concepts(concepts);
421  
    g22utils.masterStuff(host);
422  
  }
423  
  
424  
  S name() {
425  
    ret fileName(conceptsDir(concepts));
426  
  }
427  
  
428  
  void start {
429  
    concepts.grabThroughSocket(false);
430  
    concepts.makeStructureData = -> {
431  
      structure_Data data = concepts.makeStructureData_base();
432  
      data.realShortName = name -> {
433  
        S n = dropPrefixOrNull("userCode.", name);
434  
        if (n != null)
435  
          ret takeFirst(n, indexOf(n, '_'));
436  
        ret data.realShortName_base(name);
437  
      };
438  
      data.mcDollar = mcDollar();
439  
      ret data;
440  
    };
441  
    var lock = concepts.fileLock();
442  
    try {
443  
      lock.contentsForLockFile("Locked by computer " + computerID() + "\n");
444  
      lock.lockOrFail();
445  
    } catch print e {
446  
      if (cic(str(e), "Couldn't aquire lock")) {
447  
        if (!lock.hasExpectedContents()) {
448  
          infoBox("Overriding project lock (" + lock.actualContents() + ")");
449  
          lock.forceLock();
450  
        } else {
451  
          S msg = "This project is already opened in another process";
452  
          infoBox(msg, 10.0);
453  
          sleepSeconds(1);
454  
          fail(msg);
455  
        }
456  
      } else
457  
        throw rethrow(e);
458  
    }
459  
    concepts.fileLock().deleteOnExit();
460  
    thinAProgramsBackups(concepts.conceptsDir(), true);
461  
    
462  
    //concepts.persist();
463  
    concepts.loadConcepts();
464  
    
465  
    // Check that we are not loading with an old program version
466  
    var projectInfo = optimizedUniq(concepts, G22ProjectInfo);
467  
    S compilationDate = compilationDateFromClassPath(this);
468  
    print("Compilation date in project: " + projectInfo.compilationDate);
469  
    
470  
    if (nempty(projectInfo.compilationDate)
471  
      && lessThan(compilationDate, projectInfo.compilationDate)) {
472  
        messageBoxAndFail("Trying to open project with old Gazelle version - please update Gazelle first (" + compilationDate + " vs " + projectInfo.compilationDate + ")");
473  
        }
474  
        
475  
    if (cset(projectInfo, +compilationDate) != 0)
476  
      print("Bumped compilation date in project to " + compilationDate);
477  
478  
    concepts.autoSaveConcepts();
479  
    
480  
    //db_setMainConcepts(concepts);
481  
    
482  
    //print("Concepts loaded: " + map className(allConcepts(concepts));
483  
    
484  
    var stems = stems();
485  
    print("Stems in DB: " + l(stems));
486  
    mainStem = first(stems);
487  
    if (mainStem == null) {
488  
      print("Starting new module");
489  
      var module = host.makeModule();
490  
      mainStem = registerConcept(concepts, new Stem(this, module));
491  
      print("Stems in DB: " + l(stems()));
492  
    }
493  
494  
    for (stem : stems()) {
495  
      stem.db = this;
496  
      stem.host = host;
497  
      stem.startAndShow(hidden);
498  
    }
499  
    
500  
    print("Stems in DB: " + l(stems()));
501  
  }
502  
  
503  
  L<Stem> stems() { ret list Stem(concepts); }
504  
  
505  
  Q systemQ() { ret host.systemQ; }
506  
507  
  Stem findPrintLog() {  
508  
    ret firstThat(list(concepts, Stem),
509  
      stem -> stem.module instanceof PrintLogModule);
510  
  }
511  
  
512  
  void showPrintLog {
513  
    systemQ().add(-> {
514  
      var logModule = findPrintLog();
515  
      if (logModule != null)
516  
        logModule.activateWindow();
517  
      else
518  
        registerConcept(concepts, new Stem(this, new PrintLogModule)).startAndShow();
519  
    });
520  
  }
521  
  
522  
  void hidePrintLog {
523  
    systemQ().add(-> deleteConcept(findPrintLog()));
524  
  }
525  
  
526  
  void activate {
527  
    print("Activating DB: " + conceptsFile(concepts));
528  
    if (hidden) {
529  
      hidden = false;
530  
      host.loadedDBsChange();
531  
    }
532  
    mainStem?.activateWindow();
533  
  }
534  
  
535  
  void hide {
536  
    hideWindow(mainWindow());
537  
    if (!hidden) {
538  
      hidden = true;
539  
      host.loadedDBsChange();
540  
    }
541  
  }
542  
  
543  
  public JFrame mainWindow() {
544  
    ret mainStem?.window;
545  
  }
546  
547  
  close {  
548  
    print("Cleaning up " + concepts);
549  
    print("Stems in DB: " + l(stems()));
550  
    
551  
    for (Concept c : allConcepts(concepts))
552  
      cleanUp(c);
553  
      
554  
    print("Releasing DB (" + n2(list(concepts, Stem), "stem") + ")");
555  
    dispose concepts;
556  
557  
    host.loadedDBs.remove(this);
558  
    host.loadedDBsChange();
559  
    
560  
    print("Remaining DBs: " + l(host.loadedDBs));
561  
  }
562  
  
563  
  toString { ret name(); }
564  
  
565  
  DynModule module() {
566  
    ret mainStem?.module;
567  
  }
568  
  
569  
  public G22ProjectActions projectActions() {
570  
    ret (G22ProjectActions) module();
571  
  }
572  
} // end of LoadedDB
573  
574  
// This replaces the Stefan's OS main class. It is not persisted
575  
// and there is only one instance.
576  
577  
transient sclass GazelleHost is G22MasterStuff {
578  
  Set<LoadedDB> loadedDBs = syncLinkedHashSet();
579  
  event loadedDBsChange;
580  
  event newClassesDefined;
581  
  
582  
  transient S repackageURL = "https://botcompany.de/jar/1033860?withX30=1&withLibs=1&noSrc=1&mainClassForManifest=Starter&repackage=1";
583  
584  
  // Title of this Gazelle instance
585  
  transient S windowTitle = "Gazelle 22";
586  
  
587  
  transient S trayIconImageID = #1103047;
588  
  transient int borderSize = 5;
589  
  transient Color color1 = awtColor("ADD8E6");
590  
  transient Color color2 = awtColor("EEEEEE");
591  
  transient Color color3 = awtColor("A3C0AA");
592  
  transient IF0<DynModule> moduleMaker;
593  
  transient ThreadPool threadPool;
594  
  
595  
  transient File dbMotherDir;
596  
  
597  
  transient TrayIcon trayIcon;
598  
  transient TrayIconLastPosition trayIconLastPosition;
599  
  
600  
  transient S[] args;
601  
  transient Set<S> argsSet;
602  
  transient bool incrementalDownloads = true;
603  
  transient volatile bool shuttingDown;
604  
  
605  
  transient bool restrictWindowsToScreenSize /*= true*/;
606  
  
607  
  // This caused problems, disabled for now
608  
  transient bool allowFrameMaximization;
609  
  
610  
  transient G22Utils g22utils;
611  
  transient StefansOS_ConnectToServer serverConnector;
612  
  transient ComputerCountListener computerCount;
613  
  transient GazellePresenceListener gazellePresenceListener;
614  
  
615  
  transient gettable Q systemQ = startQ("System Q");
616  
  
617  
  transient AutoCloseable pimpedPopups;
618  
  
619  
  // Let's use one of these centrally because it blocks a thread
620  
  // and does next to nothing most of the time.
621  
  gettable new RunnablesReferenceQueue runnablesReferenceQueue;
622  
  
623  
  transient gettable ILASClassLoader lasClassLoader =
624  
    //new LASClassLoader(getClass());
625  
    new LASMultiClassLoader(mc()).runnablesReferenceQueue(assertNotNull(runnablesReferenceQueue));
626  
  
627  
  //transient BoolVarWithNotify compileButtonEnabled = new(true);
628  
  
629  
  gettable EphemeralObjectIDs ephemeralObjectIDs = new()
630  
    .runnablesReferenceQueue(assertNotNull(runnablesReferenceQueue));
631  
    
632  
  transient bool autoExitDisabled;
633  
  
634  
  event fillingTrayIconMenu(PopupMenu menu);
635  
  
636  
  // add fields here
637  
  
638  
  *(ThreadPool *threadPool, IF0<DynModule> *moduleMaker) {
639  
    g22utils = new G22Utils().masterStuff(this);
640  
    
641  
    onLoadedDBsChange(-> {
642  
      if (shuttingDown) ret;
643  
      var dbs = getLoadedDBs();
644  
      if (nempty(dbs))
645  
        g22utils.setOpenDBs(dbs);
646  
      updateTrayIconMenu();
647  
    });
648  
  }
649  
  
650  
  // Reminder: We are in GazelleHost
651  
  
652  
  <A> A inSystemQ(IF0<A> f) {
653  
    ret evalInQ(systemQ(), f);
654  
  }
655  
  
656  
  JFrame mainWindow() {
657  
    ret firstNonNull(loadedDBs(), db -> db.mainWindow());
658  
  }
659  
660  
  void trayIconLeftClick {
661  
    first(loadedDBs()).activate();
662  
  }
663  
  
664  
  void makeTrayIcon {
665  
    pcall-short {
666  
      trayIcon_imageAutoSize = false;
667  
      trayIcon = installTrayIcon(trayIconImageID, windowTitle,
668  
        r trayIconLeftClick,
669  
        /*"Show " + windowTitle, r trayIconLeftClick,
670  
        "Exit " + windowTitle, r cleanExit*/
671  
      );
672  
      
673  
      updateTrayIconMenu();
674  
      trayIconLastPosition = new TrayIconLastPosition(trayIcon);
675  
    }
676  
  }
677  
  
678  
  void updateTrayIconMenu { rstUpdateTrayIconMenu.trigger(); }
679  
  
680  
  transient ReliableSingleThread rstUpdateTrayIconMenu = rstWithPostDelay(1000, l0 updateTrayIconMenuImpl);
681  
  
682  
  void updateTrayIconMenuImpl {
683  
    if (trayIcon == null) ret;
684  
    
685  
    new PopupMenu menu;
686  
    var projects = openProjects();
687  
    printVars("updateTrayIconMenuImpl", +projects);
688  
    for (IG22LoadedDB otherDB : projects) {
689  
      S name = otherDB.g22utils().projectName();
690  
      S status = otherDB.hidden() ? "Hidden" : "";
691  
      addMenuItem(menu, name + appendSquareBracketed(status), rThread { otherDB.activate() });
692  
    }
693  
    
694  
    fillingTrayIconMenu(menu);
695  
696  
    addMenuItem(menu, "Exit " + windowTitle, rThread cleanExit);
697  
    trayIcon.setPopupMenu(menu);
698  
  }
699  
  
700  
  void run(S[] args) {
701  
    try {
702  
      this.args = args;
703  
      run2(args);
704  
    } catch print e {
705  
      //messageBox(e);
706  
      hideTrayIcon(trayIcon);
707  
      onWindowClosing(-> systemExit(1), getWindow(
708  
        showText_fast_noWrap("Gazelle Error", renderStackTrace(e))));
709  
    }
710  
  }
711  
  
712  
  void run2(S[] args) {
713  
    argsSet = asSet(args);
714  
    
715  
    S s = first(args);
716  
    bool isDirectory = isDirectory(s);
717  
    if (isDirectory)
718  
      dbMotherDir = canonicalFile(s);
719  
    printVars(args := asList(args), +s, +isDirectory, +dbMotherDir);
720  
      
721  
    print("Using mother directory: " + databasesMotherDir());
722  
    
723  
    windowTitle = or2(loadTextFile(newFile(dbMotherDir, "Gazelle Name")), windowTitle);
724  
    
725  
    if (!argsSet.contains("noflatlaf"))
726  
      com.formdev.flatlaf.FlatLightLaf.setup();
727  
    
728  
    if (contains(args, "profile"))
729  
      profileToConsole(() -> actualMain(args));
730  
    else
731  
      actualMain(args);
732  
      
733  
    if (argsSet.contains("brexit")) System.exit(0);
734  
  }
735  
  
736  
  void actualMain(S... args) {
737  
    vm_generalMap_put(stefansOS := this);
738  
    
739  
    System.out.println(hmsWithColonsAndMS() + ": Init");
740  
    //x30.coreInit();
741  
    
742  
    // Ready to roll
743  
    
744  
    printJavaVersion();
745  
    
746  
    //tempAddGlobalCtrlKeyListener(b -> print("Ctrl key: " + b));
747  
    
748  
    if (contains(argsSet, "profile"))
749  
      doEvery(1.0, r printRunningThreads);
750  
    
751  
    if (containsOneOf(argsSet, "upgrade", "update"))
752  
      ret with upgradeGazelle();
753  
      
754  
    makeTrayIcon();
755  
    
756  
    initAutoUpdate();
757  
    
758  
    if (devMode()) {
759  
      print("Pimping popup menus");
760  
      PopupMenuMaker.fix();
761  
      pimpedPopups = tempGlobalPopupMenu((c, menu) -> {
762  
        printVars("pimpedPopups", c := className(c));
763  
        
764  
        // Skip linux tray icon popups
765  
        if (contains(className(c), "XTrayIcon")) ret;
766  
        
767  
        // This is for popup menus displayed via setComponentPopupMenu
768  
        // which are re-used instances
769  
        if (any(getMenuItems(menu), menuItem
770  
          -> cicOneOf(menuItem.getText(), "Component: ", "src: "))) ret;
771  
          
772  
        O src = componentMetaSrc(c);
773  
        menu.add(commaCombine(
774  
          classNameAndEphString(c),
775  
          src == null ?: "src: " + classNameAndEphString(src)));
776  
      });
777  
    }
778  
    
779  
    // Start DB
780  
    
781  
    LS dbNames = g22utils.dbsToOpen();
782  
    for (S dbName : dbNames) {
783  
      S name2 = dropPrefix("*", dbName);
784  
      openDB(name2, !eq(dbName, name2));
785  
    }
786  
    
787  
    exitIfAllDBsClosed();
788  
    
789  
    printWithMS("Dudadoneski");
790  
  }
791  
  
792  
  public bool projectExists(S dbName) {
793  
    File conceptsFile = newFile(newFile(databasesMotherDir(), dbName), conceptsFileName());
794  
    ret isFile(conceptsFile);
795  
  }
796  
  
797  
  LoadedDB openDB(S dbName, bool hidden default false) {
798  
    File conceptsFile = newFile(newFile(databasesMotherDir(), dbName), conceptsFileName());
799  
    ret openDB(conceptsFile, hidden);
800  
  }
801  
  
802  
  public IG22LoadedDB getLoadedDB(Concepts concepts) {
803  
    ret firstThat(cloneList(loadedDBs), db -> db.concepts == concepts);
804  
  }
805  
  
806  
  IG22LoadedDB getLoadedDBForConceptDir(File dir) {
807  
    ret findLoadedDBForConceptsDir(dir);
808  
  }
809  
810  
  LoadedDB findLoadedDBForConceptsDir(File conceptsDir) {
811  
    ret firstThat(cloneList(loadedDBs), db -> sameFile(
812  
      conceptsDir(db.concepts), conceptsDir));
813  
  }
814  
  
815  
  LoadedDB findLoadedDBForConceptsFile(File conceptsFile) {
816  
    ret firstThat(cloneList(loadedDBs), db -> sameFile(
817  
      conceptsFile(db.concepts), conceptsFile));
818  
  }
819  
  
820  
  public IG22LoadedDB reopenDB(IG22LoadedDB db) {
821  
    ret reopenDB((LoadedDB) db);
822  
  }
823  
  
824  
  LoadedDB reopenDB(LoadedDB db) {
825  
    File conceptsFile = db.concepts.conceptsFile();
826  
    try {
827  
      autoExitDisabled = true;
828  
      closeDatabase(db);
829  
      ret openDB(conceptsFile);
830  
    } finally {
831  
      autoExitDisabled = false;
832  
    }
833  
  }
834  
  
835  
  LoadedDB openDB(File conceptsFile, bool hidden default false) {
836  
    ret inSystemQ(-> {
837  
      var loadedDB = findLoadedDBForConceptsFile(conceptsFile);
838  
      if (loadedDB != null) {
839  
        if (!hidden)
840  
          loadedDB.activate();
841  
        ret loadedDB;
842  
      }
843  
        
844  
      temp tempInfoBoxNoHide("Opening Gazelle project " + quote(fileName(dirOfFile(conceptsFile))));
845  
      
846  
      // profile project opening
847  
      //temp tempProfileSingleThreadToConsole();
848  
  
849  
      print("Loading new DB: " + f2s(conceptsFile));
850  
      g22utils.addToRecentDBNames(parentName(conceptsFile), hidden);
851  
      Concepts concepts = newConceptsWithClassFinder(conceptsFile, makeClassFinder());
852  
      
853  
      concepts.onSaveError(l1 infoBox);
854  
      
855  
      // to clean-up resources in project variables
856  
      concepts.closeConceptsOnExit(true);
857  
      
858  
      var db = new LoadedDB(this, concepts, hidden);
859  
      loadedDBs.add(db);
860  
      try {
861  
        db.start();
862  
        loadedDBsChange();
863  
      } catch print e {
864  
        loadedDBs.remove(db);
865  
        _close(db);
866  
      }
867  
      ret db;
868  
    });
869  
  }
870  
  
871  
  public Cl<File> openConceptDirs() {
872  
    ret cloneMap(loadedDBs, _db -> conceptsDir(_db.concepts));
873  
  }
874  
  
875  
  O resolveModule(O moduleOrStem) {
876  
    ret moduleOrStem cast Stem ? moduleOrStem.module : moduleOrStem;
877  
  }
878  
  
879  
  void cleanExit {
880  
    set shuttingDown;
881  
    print("Closing " + n2(loadedDBs, "database"));
882  
    closeAndClear(loadedDBs);
883  
    System.exit(0);
884  
  }
885  
  
886  
  File myJar() { ret getBytecodePathForClass(this); }
887  
  
888  
  AutoCloseable tempDisableCompileButtons() {
889  
    ret tempDisableButtons(compileButtons());
890  
  }
891  
892  
  swappable void upgradeGazelleForeplay { 
893  
    infoBox("Updating Gazelle in 10...");
894  
    sleepSeconds(10);
895  
    upgradeGazelle();
896  
  }
897  
  
898  
  void upgradeGazelle {
899  
    try {
900  
      temp tempPrintAlsoToSystemOut();
901  
      
902  
      // Show an infoBox to make sure the code for infoBox is loaded
903  
      temp tempInfoBox("Updating Gazelle...");
904  
      
905  
      //temp tempSetBoolVar(compileButtonEnabled, false);
906  
      temp tempDisableCompileButtons();
907  
      //for (f : allJFrames()) setFrameTitle(f, "Updating...");
908  
      
909  
      File myJar = myJar();
910  
      print(+myJar);
911  
      
912  
      S existingFilesComp = !incrementalDownloads ? null
913  
        : existingFilesInfo();
914  
      
915  
      S date = ymdMinusHMS();
916  
      File f = javaxCodeDir("Downloaded Updates/" + "gazelle-" + date + ".jar");
917  
      temp progress = tempProgressBar_addToWindowIfPossible(mainWindow(), "Updating Gazelle");
918  
919  
      progress.setText("Downloading Update...");
920  
      time "Downloading zip" {
921  
        postBinaryPageToFile(downloadURL(), f, +existingFilesComp);
922  
      }
923  
      printFileInfo(f);
924  
      if (!isNonEmptySingleZip_byMagicHeader(f))
925  
        ret with infoBox("Bad file downloaded... :(");
926  
        
927  
      bool replaced;
928  
      if (isFile(myJar)) {
929  
        // load all my classes to be sure (TODO: could do this in parallel to downloading)
930  
        //print("Loaded " + nClasses(loadAllClassesInByteCodePath(myJar)));
931  
        
932  
        progress.setText("Replacing with new version: " + renderFileInfo(myJar));
933  
        File myJarSaved = fileInSubDir("old-code",
934  
          appendToBaseName(myJar, ".bak." + date));
935  
        File myJarNew = appendToFileName(myJar, ".new");
936  
          
937  
        Set<S> toKeep = asSet(tlft(loadTextFileFromZip(f, "to-keep")));
938  
        if (nempty(toKeep)) {
939  
          int toUpdate = countFilesInZip(f)-1;
940  
          //progress.setText("Keeping " + nFiles(toKeep));
941  
          progress.setText("Updating " + nFiles(toUpdate));
942  
        
943  
          // Do we have anything to updatE?
944  
          
945  
          int have = countFilesInZip(myJar);
946  
          if (l(toKeep) == have && countFilesInZip(f) == 1) {
947  
            infoBox("Nothing to update - Gazelle is up to date!");
948  
            deleteFile(myJarNew);
949  
            deleteFile(myJarSaved);
950  
            ret;
951  
          }
952  
          
953  
          temp Zip4j_MergeZipFilesWithFilter merger = new(myJarNew);
954  
          merger.addZipFile(myJar, name -> contains(toKeep, name));
955  
          merger.addZipFile(f, name -> !eq(name, "to-keep"));
956  
          merger.finish();
957  
        } else
958  
          myJarNew = f;
959  
960  
        if (isWindows()) {
961  
          copyFileVerbose(myJar, myJarSaved);
962  
          copyFileVerbose(myJarNew, myJar);
963  
          deleteFileVerbose_assertSuccess(myJarNew);
964  
        } else {
965  
          renameFileVerbose_assertSuccess(myJar, myJarSaved);
966  
          renameFileVerbose_assertSuccess(myJarNew, myJar);
967  
        }
968  
969  
        printFileInfo(myJar);
970  
        set replaced;
971  
      }
972  
        
973  
      progress.setText("Done");
974  
      
975  
      if (replaced)
976  
        infoBox("Installed update, replaced " + f2s(myJar) + " - now starting");
977  
      else
978  
        infoBox("Updated but could not replace originally downloaded jar");
979  
        
980  
      restart(replaced ? myJar : f);
981  
    } on fail e { printStackTrace(e); }
982  
  }
983  
  
984  
  void restart(File jar default myJar()) {
985  
    temp tempPrintAlsoToSystemOut();
986  
    
987  
    S javaCmd = or2(currentProcessCommand(), "java");
988  
    S cmd = platformQuoteArgs(flattenToList(
989  
      javaCmd, "-jar", jar, args));
990  
    print(cmd);
991  
    nohup(cmd);
992  
    cleanExit();
993  
  }
994  
  
995  
  DynModule makeModule() {
996  
    ret callF(moduleMaker);
997  
  }
998  
  
999  
  void reloadModuleInBackground(Stem mod) {
1000  
    restart();
1001  
  }
1002  
1003  
  void initAutoUpdate {  
1004  
    print("Making server connection for updates.");
1005  
    serverConnector = snippetUpdateConnector(/*verbose := true*/);
1006  
    //serverConnector.verbose = true;
1007  
    
1008  
    vmBus_onMessage snippetUpdate(voidfunc(L l) {
1009  
      S uri = getString(l, 1);
1010  
      new Matches m;
1011  
      if (swic(uri, "/transpileOK/", m)) {
1012  
        if (sameSnippetID(programID(), firstIntAsString(m.rest()))) {
1013  
          if (g22utils.autoUpdateEnabled() /*&& autoUpdateDisabled*/) {
1014  
            upgradeGazelleForeplay();
1015  
          }
1016  
          //infoBox("Gazelle can be updated!");
1017  
        }
1018  
      } else if (swic(uri, "/edit/", m)) {
1019  
        S snippetID = fsI(firstIntAsString(m.rest());
1020  
        if (contains(stdFunctionListSnippetIDs(), snippetID))
1021  
          stdFunctions_clearCache();
1022  
        if (contains(standardClassesSnippetIDs(), snippetID))
1023  
          standardClassesMap_clearCache();
1024  
      }
1025  
    });
1026  
    
1027  
    pcall {
1028  
      computerCount = new ComputerCountListener(serverConnector);
1029  
      computerCount.init();
1030  
    }
1031  
    
1032  
    pcall {
1033  
      gazellePresenceListener = GazellePresenceListener(serverConnector);
1034  
      gazellePresenceListener.init();
1035  
    }
1036  
  }
1037  
  
1038  
  S downloadURL() {
1039  
    ret "https://botcompany.de/jar/" 
1040  
      + psI(programID()) + "?withLibs=1&withX30=1"
1041  
      + "&mainClassForManifest=Starter"
1042  
      + (!downloadJarWithSrc() ? "&noSrc=1" : "")
1043  
      + (downloadUncompressedJAR() ? "&uncompressed=1" : "");
1044  
  }
1045  
  
1046  
  bool downloadJarWithSrc() { true; }
1047  
  bool downloadUncompressedJAR() { false; }
1048  
  
1049  
  // called by DynModule
1050  
  void revisualizeModule(Stem stem) {
1051  
    stem.revisualize();
1052  
  }
1053  
  
1054  
  Int computerCount() { ret computerCount == null ? (Int) 0 : computerCount!; }
1055  
  LiveValue<Int> lvComputerCount() { ret computerCount?.liveValue(); }
1056  
  
1057  
  public IGetterWithNotify<Int> lvGazelleUserCount() { ret gazellePresenceListener?.userCount; }
1058  
  
1059  
  L<JButton> compileButtons() { ret mapNonNulls(allStems(), s -> s.compileButton()); }
1060  
  
1061  
  L<Stem> allStems() {
1062  
    ret concatLists(cloneMap(loadedDBs, db -> list(db.concepts, Stem)));
1063  
  }
1064  
  
1065  
  // compile main program
1066  
  void compile {
1067  
    compile(programID, null);
1068  
  }
1069  
  
1070  
  void resetNeedLatest {
1071  
    editSnippet(#1035306, "need latest .");
1072  
  }
1073  
  
1074  
  void compileAll {
1075  
    resetNeedLatest();
1076  
    compile(utilsSnippetID(), l0 compile);
1077  
  }
1078  
  
1079  
  void compileUtilsAndRepackage {
1080  
    compile(utilsSnippetID(), l0 repackage);
1081  
  }
1082  
  
1083  
  void compile(S snippetID, Runnable onSuccess) {
1084  
    print("Compiling " + snippetID);
1085  
    
1086  
    var gears = resizeImageIcon(imageIcon(#1103061), 16);
1087  
    
1088  
    temp tempDisableCompileButtons();
1089  
    temp tempSetButtonImages(compileButtons(), gears);
1090  
    
1091  
    thread { existingFilesInfo(); } // precompute
1092  
          
1093  
    var tr = TranspileWithErrorWindow().snippetID(snippetID);
1094  
    /*tr.transpileAction(->
1095  
      new TranspileForServer_v2(snippetID).run());*/
1096  
    tr.transpileAction(-> {
1097  
      var p = transpileOnNewServer(snippetID, "medium");
1098  
      if (!p.a) fail(p.b);
1099  
    });
1100  
    tr.onSuccess(onSuccess);
1101  
    tr.run();
1102  
1103  
    print("Done transpilation of " + snippetID);
1104  
  }
1105  
  
1106  
  void repackage {
1107  
    File f = javaxCachesDir("Gazelle-22/repackaged.jar");
1108  
    deleteFile(f);
1109  
    loadBinaryPageToFile(appendParamsToURL(repackageURL, uniq := randomID()), f);
1110  
    if (isJAR(f))
1111  
      infoBox("Repackaged.");
1112  
    else
1113  
      messageBox("Oh shit");
1114  
  }
1115  
  
1116  
  public void closeDatabase(LoadedDB db) {
1117  
    db.close();
1118  
    exitIfAllDBsClosed();
1119  
  }
1120  
  
1121  
  void exitIfAllDBsClosed {
1122  
    if (!autoExitDisabled && empty(loadedDBs))
1123  
      cleanExit();
1124  
  }
1125  
  
1126  
  Cl<? extends IG22LoadedDB> getLoadedDBs aka loadedDBs() {
1127  
    ret cloneList(loadedDBs);
1128  
  }
1129  
  
1130  
  public void closeDatabase(File conceptsDir) {
1131  
    for (db : cloneList(loadedDBs))
1132  
      if (sameFile(conceptsDir, conceptsDir(db.concepts)))
1133  
        db.close();
1134  
  }
1135  
  
1136  
  public void switchToDatabase(File conceptsDir) {
1137  
    if (conceptsDir == null) ret;
1138  
    // open/activate the desired database first
1139  
    var db = openDatabase(conceptsDir);
1140  
    
1141  
    if (db == null) ret; // probably impossible but whatever
1142  
    
1143  
    closeAllDBsExcept(db);
1144  
  }
1145  
  
1146  
  void closeAllDBsExcept(LoadedDB db) {
1147  
    closeAll(listMinus(loadedDBs, db));
1148  
  }
1149  
  
1150  
  public LoadedDB openDatabase(File conceptsDir, bool hidden default false) {
1151  
    temp tempPrintAlsoToSystemOut();
1152  
    
1153  
    File conceptsFile = newFile(conceptsDir, conceptsFileName());
1154  
    if (!fileExists(conceptsFile))
1155  
      fail(infoBox("Database not found: " + conceptsFile));
1156  
      
1157  
    var db = openDB(conceptsFile, hidden);
1158  
    
1159  
    print("Database opening complete");
1160  
    ret db;
1161  
  }
1162  
  
1163  
  Map<S, Class> classMigrations() {
1164  
    ret litmap(
1165  
      G22RecognizerScript := G22Analyzer,
1166  
      GalleryImage := G22GalleryImage);
1167  
  }
1168  
1169  
  public IF1<S, Class> makeClassFinder() {
1170  
    IF1<S, Class> defaultClassFinder = toIF1(_defaultClassFinder());
1171  
    var migrations = classMigrations();
1172  
    IF1<S, Class> classFinder = name -> {
1173  
      // class migration
1174  
      S shortName = dropPrefixOrNull("main$", name);
1175  
      if (shortName != null) {
1176  
        Class c = migrations.get(shortName);
1177  
        if (c != null) {
1178  
          S newName = className(c);
1179  
          print("Migrating legacy class " + name + " to " + newName);
1180  
          name = newName;
1181  
        }
1182  
      }
1183  
      
1184  
      ret defaultClassFinder.get(name);
1185  
    };
1186  
    
1187  
    // Test classFinder sanity
1188  
    
1189  
    assertEquals(callF(classFinder, "main$Stem"), Stem.class);
1190  
    
1191  
    ret classFinder;
1192  
  }
1193  
  
1194  
  transient cached S existingFilesInfo() {
1195  
    L<Map> fingerprints =  zipFileToJSONFingerprint_md5(myJar());
1196  
    S s = base64encode(gzipString(jsonEncode(fingerprints)));
1197  
    print(existingFilesInfo := nBytes(l(s)));
1198  
    ret s;
1199  
  }
1200  
  
1201  
  bool devMode() { ret g22_devMode(); }
1202  
  
1203  
  // remember ephemeral object, return script code to get it back
1204  
  S ephString(O o) {
1205  
    ret o == null ? "" : "eph " + ephemeralObjectIDs.remember(o);
1206  
  }
1207  
  
1208  
  S classNameAndEphString(O o) {
1209  
    ret o == null ?: spaceCombine(ephString(o), className(o));
1210  
  }
1211  
  
1212  
  public File databasesMotherDir() {
1213  
    if (dbMotherDir == null)
1214  
      dbMotherDir = javaxDataDir("Gazelle-22");
1215  
    ret dbMotherDir;
1216  
  }
1217  
} // end of GazelleHost [G22MasterStuff]

Author comment

Began life as a copy of #1033540

download  show line numbers  debug dex  old transpilations   

Travelled to 6 computer(s): bhatertpkbcr, ekrmjmnbrukm, iveijnkanddl, mowyntqkapby, mqqgnosmbjvj, wnsclhtenguj

No comments. add comment

Snippet ID: #1033891
Snippet name: GazelleHost + Stem [dev]
Eternal ID of this version: #1033891/366
Text MD5: f40e7bbf5635c05ba56c7fa4aef23ff0
Author: stefan
Category: javax / gazelle 22
Type: JavaX (incomplete)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2023-05-07 13:36:56
Source code size: 36016 bytes / 1217 lines
Pitched / IR pitched: No / No
Views / Downloads: 735 / 3594
Version history: 365 change(s)
Referenced in: [show references]