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

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