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 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 moduleMaker; transient ThreadPool threadPool; transient TrayIcon trayIcon; transient TrayIconLastPosition trayIconLastPosition; transient Set 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 *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 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 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 lvComputerCount() { ret computerCount.liveValue(); } L 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 makeClassFinder() { IF1 defaultClassFinder = toIF1(_defaultClassFinder()); IF1 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 fingerprints = zipFileToJSONFingerprint_md5(myJar()); S s = base64encode(gzipString(jsonEncode(fingerprints))); print(existingFilesInfo := nBytes(l(s))); ret s; } } // end of GazelleHost