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

711
LINES

< > BotCompany Repo | #1034637 // GazelleHost + Stem [backup before multiple databases]

JavaX (incomplete)

lib 1400521 // FlatLAF

set flag PingV3.
set flag NotifyingPrintLog.
set flag SymbolAsString.

// Do the JavaX init
svoid standaloneInit {
  __javax = x30.class;
  x30.__javax = x30.class; // for hotwire
  x30_pkg.x30_util.__setJavaX(x30.class);
  x30.cleanKillMsg = "";
  callOnLoadMethods(mc());
}

concept PrintLogModule > DynPrintLog {
  start { setModuleName("Log"); }
  
  S getPrintLog() {
    ret printLog();
  }
  
  bool useErrorHandling() { false; }
}

concept Stem {
  transient GazelleHost host;
  DynModule module;
  Rect frameRect;
  bool minimized, maximized, alwaysOnTop, autoUpdate, minimizeToTray;
  
  LS fieldsToShareBetweenDatabases() {
    ret identifiers("frameRect, minimized, maximized, alwaysOnTop, autoUpdate, minimizeToTray");
  }
  
  transient JFrame window;
  transient JButton btnMax;
  transient JLabel titleComponent;
  transient gettable JButton compileButton;
  //transient bool autoUpdateDisabled;
  
  *() {}
  *(GazelleHost *host) {}
  *(GazelleHost *host, DynModule *module) {}
  
  Rect getFrameRect() {
    ret toRect(getBounds(window));
  }
  
  void saveFrameRect {
    setField(frameRect := getFrameRect());
  }
  
  void setAlwaysOnTop(bool alwaysOnTop) {
    this.alwaysOnTop = alwaysOnTop;
    change();
    alwaysOnTop(window, alwaysOnTop);
  }
  
  void setMinimizeToTray(bool minimizeToTray) {
    cset(this, +minimizeToTray);
  }

  void setWindow(JFrame window) {  
    this.window = window;
    if (frameRect != null)  
      setBounds(window, frameRect);
    //onWindowClosing(window, -> host.cleanExit());
    onBoundsChange(window, r saveFrameRect);
    alwaysOnTop(window, alwaysOnTop);
  }
  
  void activateWindow {
    activateFrame_v3(window);
  }
  
  bool isMain() { ret this == host.stem; }
  
  void minimize {
    cset(this, minimized := true);
    if (!minimizeToTray || host.trayIcon == null || !isMain())
      minimizeWindow(window);
    else
      hideWindow(window);
  }
  
  void deleteMe {
    printAlsoToSystemOut = true;
    print("deleteMe " + isMain());
    if (isMain()) {
      host.cleanExit();
    } else {
      cleanMeUp();
    }
  }
  
  void cleanMeUp {
    disposeWindow(window);
    dispose module;
    cdelete(this);
  }
  
  void grabWindowState {
    setField(maximized := !isExtendedStateNormal(window));
  }
  
  void updateBtnMax {
    if (!isShowing(btnMax)) ret;
    grabWindowState();
    setText(btnMax, maximized ? "NORM" : "MAX");
  }
  
  JComponent makeWindowBorderAndTitle(JComponent contents, S title) {
    //ret jCenteredSection_fontSizePlus(10, title, vis);
    
    var icons = jline();
    if (host.allowFrameMaximization) {
      icons.add(btnMax = jbutton("", rThread {
        maximizeOrRestoreFrame(window);
        updateBtnMax();
      }));
      onFirstShowing(btnMax, r updateBtnMax);
    }
    
    icons.add(toolTip("Minimize this window", jbutton("MIN", r minimize)));
    
    if (isMain())
      icons.add(toolTip("Exit Gazelle", jbutton("QUIT", rThread {
        if (swingConfirm(window, "Really quit Gazelle?"))
          deleteMe();
      })));
    else
      icons.add(toolTip("Close this window", jbutton("X", rThread deleteMe)));
      
    //setHorizontalMarginForAllButtons(icons, 4);
    icons.add(jPopDownButton_noText(flattenToList(
              
      // always on top
      
      jCheckBoxMenuItem_dyn("Always on top",
        -> alwaysOnTop,
        alwaysOnTop -> setAlwaysOnTop(alwaysOnTop)),
        
      // restart + update
      
      "---",
      "Restart", rThread { host.restart() },
      "Update Gazelle", rThread { host.upgradeGazelle() },
      !isMain() ? null : jCheckBoxMenuItem_dyn("Auto-Update",
        -> autoUpdate,
        b -> cset(Stem.this, autoUpdate := b)),

      // debugging + screenshooting gazelle
      
      "---",
      !isMain() ? null : ll(
        "Screenshoot this window", rThread shootWindow,
        "Dump threads", rThread { showText("User threads", renderUserThreadsWithStackTraces()); },
        !isMain() ? null : "Log", !isMain() ? null : r { host.showPrintLog() },
        !isMain() ? null : "Copy log to clipboard", !isMain() ? null : rThread {
          copyToClipboard(printLog());
          infoBox("Copied log to clipboard");
        },
      ),
      
      ccallOpt(module, "popDownItems")
    )));
    
    JComponent actualTitle = titleComponent = fontSizePlus(7, jCenteredLabel(title));
    installWindowDragger(actualTitle);
    
    if (/*isMain() &&*/ haveMuricaPassword())
      actualTitle = centerAndEastWithMargin(actualTitle,
        jline(
          compileButton = makeCompileButton(),
          jLiveValueLabel(host.lvComputerCount())
        ));
    
    var spacer = gazelle_wavySpacer();
    var titleBarMain = setOpaqueBackground(host.color1,
      jtransparent_recursive(westCenterAndEastWithMargin(
        jImage_scaledToHeight(24, host.trayIconImageID),
        actualTitle,
        setOpaqueBackground(host.color2, spacer)));
    
    installWindowDragger(spacer);
    
    var titleBar = setBackground(host.color2, centerAndEast(
      titleBarMain,
      icons));
    
    var border =
      // createBevelBorder();
      BorderFactory.createLineBorder(host.color1, host.borderSize);
      
    var outerPanel = withBorder(border,
      northAndCenter(titleBar, contents));
      
    installWindowResizeDraggerOnBorder(outerPanel);
    ret outerPanel;
  }
  
  JButton makeCompileButton() {
    var gears = resizeImageIcon(imageIcon(#1103061), 16);

    var btn = jimageButtonScaledToWidth(16, #1101268, "Compile & update",
      rThread { host.compile() });
    //enableComponentAccordingToVar(host.compileButtonEnabled, btn);
    
    componentPopupMenuItem(btn, "Compile main library", rThread { host.compileUtils() });
    
    ret btn;
  }
  
  void startAndShow() {
    module._host = this;
    setOpt_raw(module, +threadPool); // only if the field exists
    setOpt_raw(module, concepts := host.concepts);
    setOpt_raw(module, g22utils := host.g22utils);
    copyLocalLog(module, mc());
  
    var vis, title = unpair makeVisAndTitle();
    printWithMS("Show frame");

    JFrame frame = makeUndecoratedFrame(title, vis);
    setFrameIcon(frame, host.trayIconImageID);
    setWindow(frame);
    
    frame.addPropertyChangeListener("title", evt ->
      setText(titleComponent, frame.getTitle()));
    
    if (minimized) minimize();
    onWindowDeiconified(frame, -> cset(this, minimized := false));
    
    showWindow(window);
    if (maximized && host.allowFrameMaximization) maximizeFrame(window);
  }
  
  Pair<JComponent, S> makeVisAndTitle() {
    JComponent vis;
    {
      printWithMS("Starting " + module);
      temp module.enter();
      module.start();
    
      printWithMS("Visualize");
      vis = swing(-> {
        temp module.enter();
        ret module.visualize();
      });
    }
    
    S title = host.windowTitle;
    if (!isMain())
      // title += appendWithColon(module.moduleName());
      title = unnull(module.moduleName());
    vis = makeWindowBorderAndTitle(vis, title);
    ret pair(vis, title);
  }
  
  void revisualize {
    if (window == null) ret;
    
    pcall {
      module.unvisualize();
    }
    
    var vis, title = unpair makeVisAndTitle();
    setFrameContents(window, vis);
  }
  
  void shootWindow {
    var img = renderComponentToImage(window);
    copyImageToClipboard(img);
    saveInImageDirectoryWithCounter(gazelle22_imagesSubDirName() + "/Gazelle", img);
  }
} // end of Stem

// This replaces the Stefan's OS main class. It is not persisted
transient sclass GazelleHost is G22MasterStuff {
  Stem stem;
  DynModule gazelle;
  
  transient S windowTitle = "November Gazelle v1";
  transient S trayIconImageID = #1103047;
  transient int borderSize = 5;
  transient Color color1 = awtColor("ADD8E6");
  transient Color color2 = awtColor("EEEEEE");
  transient Color color3 = awtColor("A3C0AA");
  transient IF0<DynModule> moduleMaker;
  transient ThreadPool threadPool;
  
  transient TrayIcon trayIcon;
  transient TrayIconLastPosition trayIconLastPosition;
  
  transient Set<S> argsSet;
  transient bool incrementalDownloads = true;
  
  transient Concepts concepts;
  
  // This caused problems, disabled for now
  transient bool allowFrameMaximization;
  
  transient StefansOS_ConnectToServer serverConnector;
  transient ComputerCountListener computerCount;
  
  transient Q systemQ = startQ("System Q");
  
  //transient BoolVarWithNotify compileButtonEnabled = new(true);
  
  transient new G22Utils g22utils;
  
  transient MapSO importedFieldsForMainStem;
  
  *(ThreadPool *threadPool, IF0<DynModule> *moduleMaker) {}

  void trayIconLeftClick {
    activateFrame_v3(mainWindow());
  }
  
  void makeTrayIcon {
    pcall-short {
      trayIcon_imageAutoSize = false;
      trayIcon = installTrayIcon(trayIconImageID, windowTitle,
        r trayIconLeftClick,
        "Show Gazelle", r trayIconLeftClick,
        "Exit Gazelle", r cleanExit
      );
      trayIconLastPosition = new TrayIconLastPosition(trayIcon);
    }
  }
  
  void run(S[] args) {
    try {
      run2(args);
    } catch print e {
      //messageBox(e);
      hideTrayIcon(trayIcon);
      onWindowClosing(-> systemExit(1), getWindow(
        showText_fast_noWrap("Gazelle Error", renderStackTrace(e))));
      //AutoVMExit.install();
    }
  }
  
  void run2(S[] args) {
    argsSet = asSet(args);
    
    if (!argsSet.contains("noflatlaf"))
      com.formdev.flatlaf.FlatLightLaf.setup();
    
    if (contains(args, "profile"))
      profileToConsole(() -> actualMain(args));
    else
      actualMain(args);
      
    if (argsSet.contains("brexit")) System.exit(0);
  }
  
  void actualMain(S... args) {
    vm_generalMap_put(stefansOS := this);
    
    System.out.println(hmsWithColonsAndMS() + ": Init");
    //x30.coreInit();
    
    // Ready to roll
    
    printJavaVersion();
    
    if (contains(argsSet, "profile"))
      doEvery(1.0, r printRunningThreads);
    
    if (containsOneOf(argsSet, "upgrade", "update"))
      ret with upgradeGazelle();
      
    g22utils.masterStuff = this;
  
    makeTrayIcon();
    
    initAutoUpdate();
    
    IF1<S, Class> classFinder = makeClassFinder();
    
    // Start DB
    
    S dbName = g22utils.dbToOpen();
    File conceptsFile = newFile(newFile(g22utils.databasesMotherDir(), dbName), conceptsFileName());
    concepts = newConceptsWithClassFinder(conceptsFile, classFinder);
    startDBAndModules();
  }
  
  void startDBAndModules {
    concepts.makeStructureData = -> {
      structure_Data data = concepts.makeStructureData_base();
      data.mcDollar = mcDollar();
      ret data;
    };
    try {
      concepts.fileLock().lockOrFail();
    } catch print e {
      if (cic(str(e), "Couldn't aquire lock")) {
        infoBox("Gazelle is still running, please exit it first!", 10.0);
        sleepSeconds(10);
        System.exit(1);
      }
      
    }
    concepts.fileLock().deleteOnExit();
    concepts.persist();
    
    //db_setMainConcepts(concepts);
    
    //print("Concepts loaded: " + map className(allConcepts(concepts));
    
    var stems = findConcepts(concepts, Stem);
    print("Stems in DB: " + l(stems));
    stem = first(stems);
    if (stem == null) {
      print("Starting new module");
      makeModule();
      stem = registerConcept(concepts, new Stem(this, gazelle));
    }
    gazelle = stem.module;
    
    print(+importedFieldsForMainStem);
    csetAll(stem, importedFieldsForMainStem);
    importedFieldsForMainStem = null;

    for (stem : list Stem(concepts)) {
      stem.host = this;
      stem.startAndShow();
    }
    
    printWithMS("Dudadoneski");
  }
  
  void showPrintLog {
    systemQ.add(-> {
      var logModule = firstThat(list(concepts, Stem),
        stem -> stem.module instanceof PrintLogModule);
      if (logModule != null)
        logModule.activateWindow();
      else
        registerConcept(concepts, new Stem(this, new PrintLogModule)).startAndShow();
    });
  }
  
  JFrame mainWindow() {
    ret stem?.window;
  }
  
  O dm_getStem(O moduleOrID) {
    ret stem;
  }
  
  O resolveModule(O moduleOrID) { ret moduleOrID == stem ? gazelle : moduleOrID; }
  
  void cleanExit {
    // e.g. JPaintTool does clean-up when removed (through bindToComponent)
    /*print("Removing all components");
    for (window : allWindows())
      setWindowContents(window, jcenteredlabel("Exiting..."));*/
    
    print("Saving DB for exit");
    dispose concepts;
    System.exit(0);
  }
  
  File myJar() { ret getBytecodePathForClass(this); }
  
  AutoCloseable tempDisableCompileButtons() {
    ret tempDisableButtons(compileButtons());
  }
  
  void upgradeGazelle {
    try {
      printAlsoToSystemOut = true;
      
      // Show an infoBox to make sure the code for infoBox is loaded
      temp tempInfoBox("Updating Gazelle...");
      
      //temp tempSetBoolVar(compileButtonEnabled, false);
      temp tempDisableCompileButtons();
      for (f : allJFrames()) setFrameTitle(f, "Updating...");
      
      File myJar = myJar();
      print(+myJar);
      
      S existingFilesComp = !incrementalDownloads ? null
        : existingFilesInfo();
      
      S date = ymdMinusHMS();
      File f = javaxCodeDir("Downloaded Updates/" + "gazelle-" + date + ".jar");
      temp progress = tempProgressBar_addToWindowIfPossible(mainWindow(), "Updating Gazelle");

      progress.setText("Downloading Update...");
      time "Downloading zip" {
        postBinaryPageToFile(downloadURL(), f, +existingFilesComp);
      }
      printFileInfo(f);
      if (!isNonEmptySingleZip_byMagicHeader(f))
        ret with infoBox("Bad file downloaded... :(");
        
      bool replaced;
      if (isFile(myJar)) {
        // load all my classes to be sure (TODO: could do this in parallel to downloading)
        //print("Loaded " + nClasses(loadAllClassesInByteCodePath(myJar)));
        
        progress.setText("Replacing with new version: " + renderFileInfo(myJar));
        File myJarSaved = fileInSubDir("old-code",
          appendToBaseName(myJar, ".bak." + date));
        File myJarNew = appendToFileName(myJar, ".new");
          
        Set<S> toKeep = asSet(tlft(loadTextFileFromZip(f, "to-keep")));
        if (nempty(toKeep)) {
          progress.setText("Keeping " + nFiles(toKeep));
          int have = countFilesInZip(myJar);
          if (l(toKeep) == have && countFilesInZip(f) == 1) {
            infoBox("Nothing to update - will just restart");
            deleteFile(myJarNew);
            sleepSeconds(1);
            restart();
          }
          
          /*
          temp ZipOutputStream out = zipOutputStream(myJar);
          zip2zip_withPredicate(myJarSaved, out, name -> toKeep.contains(name));
          progress.setText("Adding new files");
          int n = zip2zip_withPredicate(f, out, name -> !eq(name, "to-keep"));
          progress.setText("Added " + nFiles(n));
          */
          
          temp Zip4j_MergeZipFilesWithFilter merger = new(myJarNew);
          merger.addZipFile(myJar, name -> contains(toKeep, name));
          merger.addZipFile(f, name -> !eq(name, "to-keep"));
          merger.finish();
        } else
          myJarNew = f;

        if (isWindows()) {
          copyFileVerbose(myJar, myJarSaved);
          copyFileVerbose(myJarNew, myJar);
          deleteFileVerbose_assertSuccess(myJarNew);
        } else {
          renameFileVerbose_assertSuccess(myJar, myJarSaved);
          renameFileVerbose_assertSuccess(myJarNew, myJar);
        }

        printFileInfo(myJar);
        set replaced;
      }
        
      progress.setText("Done");
      
      if (replaced)
        infoBox("Installed update, replaced " + f2s(myJar) + " - now starting");
      else
        infoBox("Updated but could not replace originally downloaded jar");
        
      restart(replaced ? myJar : f);
    } on fail e { printStackTrace(e); }
  }
  
  void restart(File jar default myJar()) {
    S javaCmd = or2(currentProcessCommand(), "java");
    S cmd = pqO(javaCmd) + " -jar " + pqO(jar);
    print(cmd);
    nohup(cmd);
    cleanExit();
  }
  
  void makeModule() {
    if (gazelle == null)
      gazelle = callF(moduleMaker);
  }
  
  void reloadModuleInBackground(Stem mod) {
    restart();
  }

  void initAutoUpdate {  
    print("Making server connection for updates.");
    serverConnector = snippetUpdateConnector(/*verbose := true*/);
    //serverConnector.verbose = true;
    
    vmBus_onMessage snippetUpdate(voidfunc(L l) {
      S uri = getString(l, 1);
      new Matches m;
      if (swic(uri, "/transpileOK/", m))
        if (sameSnippetID(programID(), firstIntAsString(m.rest()))) {
          if (stem.autoUpdate /*&& autoUpdateDisabled*/)
            upgradeGazelle();
          //infoBox("Gazelle can be updated!");
        }
    });
    
    pcall {
      computerCount = new ComputerCountListener(serverConnector);
      computerCount.init();
    }
  }
  
  S downloadURL() {
    ret "https://botcompany.de/jar/" 
      + psI(programID()) + "?withLibs=1&withX30=1"
      + "&mainClassForManifest=Starter"
      + (!downloadJarWithSrc() ? "&noSrc=1" : "")
      + (downloadUncompressedJAR() ? "&uncompressed=1" : "");
  }
  
  bool downloadJarWithSrc() { false; }
  bool downloadUncompressedJAR() { false; }
  
  // called by DynModule
  void revisualizeModule(Stem stem) {
    stem.revisualize();
  }
  
  Int computerCount() { ret computerCount == null ? (Int) 0 : computerCount!; }
  LiveValue<Int> lvComputerCount() { ret computerCount.liveValue(); }
  
  L<JButton> compileButtons() { ret mapNonNulls(list(Stem), s -> s.compileButton()); }
  
  // compile main program
  void compile {
    compile(programID, null);
  }
  
  void compileUtils {
    compile(utilsSnippetID(), l0 compile);
  }
  
  void compile(S snippetID, Runnable onSuccess) {
    print("Compiling " + snippetID);
    
    var gears = resizeImageIcon(imageIcon(#1103061), 16);
    
    temp tempDisableCompileButtons();
    temp tempSetButtonImages(compileButtons(), gears);
    
    thread { existingFilesInfo(); } // precompute
          
    transpileOnServerWithErrorWindow(snippetID, true, onSuccess);
    
    print("Done transpilation of " + snippetID);
  }
  
  public void switchDatabase(File conceptsDir) {
    printAlsoToSystemOut = true;
    
    temp tempInfoBoxNoHide("Switching database...");
    
    // copy some things that should really be global
    // like auto-update flag and main window position
    
    importedFieldsForMainStem = cgetAll(stem, stem.fieldsToShareBetweenDatabases());
    print(+importedFieldsForMainStem);
    
    File newConceptsFile = newFile(conceptsDir, conceptsFileName());
    if (!fileExists(newConceptsFile))
      fail(infoBox("Database not found: " + newConceptsFile));
      
    print("Cleaning up concepts");
    
    for (Concept c : allConcepts(concepts))
      cleanUp(c);
      
    print("Releasing DB");
    gazelle = null;
    dispose concepts;

    //print("Safety sleep (1s)");
    //sleepSeconds(1);
    
    var classFinder = makeClassFinder();
    
    print("Loading new DB: " + f2s(newConceptsFile));
    concepts = newConceptsWithClassFinder(newConceptsFile, classFinder);
    startDBAndModules();
    
    g22utils.openedDB(conceptsDir);
    
    print("Database switch complete, stopping System.out");
    printAlsoToSystemOut = false;
  }

  IF1<S, Class> makeClassFinder() {  
    IF1<S, Class> defaultClassFinder = toIF1(_defaultClassFinder());
    IF1<S, Class> classFinder = name -> {
      // class migration
      if (eq(name, "main$G22RecognizerScript")) {
        S newName = "main$G22Analyzer";
        print("Migrating legacy class " + name + " to " + newName);
        name = newName;
      }
      ret defaultClassFinder.get(name);
    };
    
    // Test classFinder sanity
    
    assertEquals(callF(classFinder, "main$Stem"), Stem.class);
    
    ret classFinder;
  }
  
  transient cached S existingFilesInfo() {
    L<Map> fingerprints =  zipFileToJSONFingerprint_md5(myJar());
    S s = base64encode(gzipString(jsonEncode(fingerprints)));
    print(existingFilesInfo := nBytes(l(s)));
    ret s;
  }
} // end of GazelleHost

Author comment

Began life as a copy of #1033891

download  show line numbers  debug dex  old transpilations   

Travelled to 2 computer(s): bhatertpkbcr, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1034637
Snippet name: GazelleHost + Stem [backup before multiple databases]
Eternal ID of this version: #1034637/1
Text MD5: 37065f8a6fb74a1468991d51fdaaedf5
Author: stefan
Category: javax / gazelle v
Type: JavaX (incomplete)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-02-25 21:24:49
Source code size: 20888 bytes / 711 lines
Pitched / IR pitched: No / No
Views / Downloads: 76 / 85
Referenced in: [show references]