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

532
LINES

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

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 maximized, alwaysOnTop, autoUpdate, minimizeToTray;
  
  transient JFrame window;
  transient JButton btnMax;
  
  *() {}
  *(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);
  }
  
  bool isMain() { ret this == host.stem; }
  
  void minimize {
    if (!minimizeToTray || host.trayIcon == null || !isMain())
      minimizeWindow(window);
    else
      hideWindow(window);
  }
  
  void deleteMe {
    printAlsoToSystemOut = true;
    print("deleteMe " + isMain());
    if (isMain()) {
      host.cleanExit();
    } else {
      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
      
      "---",
      !isMain() ? null : ll(
        "Restart", rThread { host.restart() },
        "Update Gazelle", rThread { host.upgradeGazelle() },
      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 : rThread { host.showPrintLog() },
        !isMain() ? null : "Copy log to clipboard", !isMain() ? null : rThread {
          copyToClipboard(printLog());
          infoBox("Copied log to clipboard");
        },
      ),
      
      ccallOpt(module, "popDownItems")
    )));
    
    JComponent actualTitle = fontSizePlus(7, jCenteredLabel(title));
    installWindowDragger(actualTitle);
    
    if (/*isMain() &&*/ haveMuricaPassword())
      actualTitle = centerAndEastWithMargin(actualTitle, compileButton());
    
    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;
  }
  
  JComponent compileButton() {
    var gears = resizeImageIcon(imageIcon(#1103061), 16);

    ret jimageButtonScaledToWidth(16, #1101268, "Compile & update",
      buttonActionWithCloseablePre(lambda0 compile,
        btn -> combineAutoCloseables(
          tempSetToolTip(btn, "Compiling on server..."),
          tempDisableButton(btn),
          tempSetButtonImage(btn, gears))));
  }
  
  void compile {
    transpileOnServerWithErrorWindow(programID, true, null);
  }

  void startAndShow() {
    module._host = this;
    setOpt_raw(module, +threadPool); // only if the field exists
    setOpt_raw(module, concepts := host.concepts);
    copyLocalLog(module, mc());
  
    var vis, title = unpair makeVisAndTitle();
    printWithMS("Show frame");

    JFrame frame = makeUndecoratedFrame(title, vis);
    setFrameIcon(frame, host.trayIconImageID);
    setWindow(frame);
    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 {
  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;
  
  *(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 (containsOneOf(argsSet, "upgrade", "update"))
      ret with upgradeGazelle();
  
    makeTrayIcon();
    
    initAutoUpdate();
    
    // Test classFinder sanity
    
    set flag defaultDefaultClassFinder_debug.
    assertEquals(callF(_defaultClassFinder(), "main$Stem"), Stem.class);

    // Start DB
    
    concepts = newConceptsWithClassFinder(programID);
    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;

    for (stem : list Stem(concepts)) {
      stem.host = this;
      stem.startAndShow();
    }
    
    printWithMS("Dudadoneski");
  }
  
  void showPrintLog {
    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 {
    thread {
      print("Saving DB for exit");
      dispose concepts;
      System.exit(0);
    }
  }
  
  File myJar() { ret getBytecodePathForClass(this); }
  
  void upgradeGazelle {
    try {
      printAlsoToSystemOut = true;
      
      File myJar = myJar();
      print(+myJar);
      
      S existingFilesComp = null;
      if (incrementalDownloads) {
        L<Map> fingerprints = zipFileToJSONFingerprint_md5(myJar);
        existingFilesComp = base64encode(gzipString(jsonEncode(fingerprints)));
      }
      
      S date = ymdMinusHMS();
      File f = javaxCodeDir("Downloaded Updates/" + "gazelle-" + date + ".jar");
      temp progress = tempProgressBar_addToWindowIfPossible(mainWindow(), "Updating Gazelle");

      progress.setText("Downloading Update...");
      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));
        renameFile(myJar, myJarSaved);
          
        Set<S> toKeep = asSet(tlft(loadTextFileFromZip(f, "to-keep")));
        if (nempty(toKeep)) {
          progress.setText("Keeping " + nFiles(toKeep));
          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));
        } else
          moveFile(f, 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)
            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"
      + (!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(); }
} // end of GazelleHost

Author comment

Began life as a copy of #1033540

download  show line numbers  debug dex  old transpilations   

Travelled to 3 computer(s): bhatertpkbcr, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1033891
Snippet name: GazelleHost + Stem [dev]
Eternal ID of this version: #1033891/47
Text MD5: 88571701a0e20bfdd4621e824721d036
Author: stefan
Category: javax / gazelle v
Type: JavaX (incomplete)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-01-25 21:31:18
Source code size: 15194 bytes / 532 lines
Pitched / IR pitched: No / No
Views / Downloads: 95 / 757
Version history: 46 change(s)
Referenced in: [show references]