\ No newline at end of file
diff --git a/rev2.png b/rev2.png
new file mode 100644
index 0000000..3e78417
Binary files /dev/null and b/rev2.png differ
diff --git a/src/main/java/com/rdesk/Main.java b/src/main/java/com/rdesk/Main.java
index 2fba796..831bc02 100644
--- a/src/main/java/com/rdesk/Main.java
+++ b/src/main/java/com/rdesk/Main.java
@@ -1,5 +1,8 @@
package com.rdesk;
+import com.rdesk.applications.productivity.Calculator;
+import com.rdesk.applications.productivity.browsing.TabbedBrowser;
+import com.rdesk.applications.productivity.code.CodeDesk;
import com.rdesk.applications.system.Exit;
import com.rdesk.applications.productivity.Notes;
import com.rdesk.applications.system.TaskManager;
@@ -19,11 +22,10 @@ public class Main {
}
private static void boot() {
-
Kernel kernel = Kernel.get();
kernel.boot();
+ JFrame frame = new JFrame("rDesk");
- JFrame frame = new JFrame("Java OS");
frame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
frame.addWindowListener(new java.awt.event.WindowAdapter() {
@Override
@@ -80,7 +82,11 @@ public class Main {
}
private static void registerSystemApps(AppLauncher launcher) {
+
launcher.addApp(new Notes(), "Productivity");
+ launcher.addApp(new TabbedBrowser(), "Productivity");
+ launcher.addApp(new CodeDesk(), "Productivity");
+ launcher.addApp(new Calculator(), "Productivity");
launcher.addApp(new Exit(), "System");
launcher.addApp(new TaskManager(), "System");
launcher.addApp(new FileExplorerApp(), "System");
diff --git a/src/main/java/com/rdesk/applications/productivity/Calculator.java b/src/main/java/com/rdesk/applications/productivity/Calculator.java
new file mode 100644
index 0000000..031ee03
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/Calculator.java
@@ -0,0 +1,457 @@
+package com.rdesk.applications.productivity;
+import com.rdesk.kernel.*;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.math.BigInteger;
+
+public class Calculator implements DesktopApp {
+
+ @Override
+ public String getId() { return "calculator"; }
+
+ @Override
+ public String getName() { return "Calculator"; }
+
+ @Override
+ public JInternalFrame createWindow(Kernel kernel) {
+
+ JInternalFrame frame = new JInternalFrame(
+ "Calculator",
+ true, true, true, true
+ );
+
+ frame.setSize(420, 480);
+ frame.setLayout(new BorderLayout(6,6));
+
+ JPanel top = new JPanel(new BorderLayout(6,6));
+ String[] modes = {"Standard", "Scientific", "Programmer"};
+ JComboBox" + exception.getMessage() + "
" + + ""
+ + sw.toString().replace("&", "&").replace("<", "<")
+ + ""
+ + "";
+ Platform.runLater(() -> engine.loadContent(errorHtml));
+ }
+
+ private static void logError(String message, Throwable t) {
+ System.err.println("[BrowserUI ERROR] " + message);
+ if (t != null) {
+ t.printStackTrace(System.err);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rdesk/applications/productivity/browsing/TabbedBrowser.java b/src/main/java/com/rdesk/applications/productivity/browsing/TabbedBrowser.java
new file mode 100644
index 0000000..12cc90c
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/browsing/TabbedBrowser.java
@@ -0,0 +1,61 @@
+package com.rdesk.applications.productivity.browsing;
+
+import com.rdesk.kernel.DesktopApp;
+import com.rdesk.kernel.Kernel;
+import javafx.application.Platform;
+import javafx.embed.swing.JFXPanel;
+import javafx.scene.Scene;
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+
+public class TabbedBrowser implements DesktopApp {
+
+ private static final String HOME_URL = "https://www.google.com";
+
+ @Override
+ public String getId() {
+ return "sharkbrowser";
+ }
+
+ @Override
+ public String getName() {
+ return "SharkBrowser";
+ }
+
+ @Override
+ public JInternalFrame createWindow(Kernel kernel) {
+ JInternalFrame frame = new JInternalFrame(
+ "SharkBrowser", true, true, true, false);
+ frame.setSize(1200, 800);
+ frame.setLayout(new BorderLayout());
+
+ JFXPanel fxPanel = new JFXPanel();
+ frame.add(fxPanel, BorderLayout.CENTER);
+
+ Platform.runLater(() -> {
+ BrowserUI ui = new BrowserUI(HOME_URL);
+ Scene scene = ui.createScene();
+ fxPanel.setScene(scene);
+
+ frame.addComponentListener(new ComponentAdapter() {
+ @Override
+ public void componentResized(ComponentEvent e) {
+ Platform.runLater(() -> {
+ double w = fxPanel.getWidth();
+ double h = fxPanel.getHeight();
+ if (w > 0 && h > 0) {
+ scene.getWindow().setWidth(w);
+ scene.getWindow().setHeight(h);
+ }
+ });
+ }
+ });
+ });
+
+ frame.setVisible(true);
+ return frame;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rdesk/applications/productivity/code/CodeDesk.java b/src/main/java/com/rdesk/applications/productivity/code/CodeDesk.java
new file mode 100644
index 0000000..5ecda8d
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/code/CodeDesk.java
@@ -0,0 +1,23 @@
+package com.rdesk.applications.productivity.code;
+
+import com.rdesk.kernel.*;
+import javax.swing.*;
+
+public class CodeDesk implements DesktopApp {
+
+ @Override
+ public String getId() {
+ return "CodeDesk";
+ }
+
+ @Override
+ public String getName() {
+ return "CodeDesk";
+ }
+
+ @Override
+ public JInternalFrame createWindow(Kernel kernel) {
+ EditorWindow window = new EditorWindow();
+ return window.getFrame();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rdesk/applications/productivity/code/EditorTab.java b/src/main/java/com/rdesk/applications/productivity/code/EditorTab.java
new file mode 100644
index 0000000..39bd009
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/code/EditorTab.java
@@ -0,0 +1,153 @@
+package com.rdesk.applications.productivity.code;
+
+import org.fife.rsta.ac.AbstractLanguageSupport;
+import org.fife.ui.rsyntaxtextarea.*;
+import org.fife.ui.rtextarea.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.io.*;
+
+public class EditorTab {
+
+ private final TabManager tabManager;
+ private RSyntaxTextArea textArea;
+ private RTextScrollPane scrollPane;
+ private File file;
+ private boolean dirty;
+ private AbstractLanguageSupport langSupport;
+ private String title; // base title without dirty marker
+ private JPanel tabHeaderComponent;
+
+ public EditorTab(String title, TabManager tabManager) {
+ this.tabManager = tabManager;
+ this.title = title;
+ this.file = null;
+ this.dirty = false;
+ buildTextArea();
+ buildScrollPane();
+ installDocumentListener();
+ installLanguageSupport(null);
+ }
+
+
+ public RSyntaxTextArea getTextArea() { return textArea; }
+ public RTextScrollPane getScrollPane() { return scrollPane; }
+ public File getFile() { return file; }
+ public boolean isDirty() { return dirty; }
+ public String getTitle() { return title; }
+
+ public void setTitle(String title) {
+ this.title = title;
+ tabManager.updateTabTitle(this);
+ }
+
+
+ public void loadFile(File file) throws IOException {
+ try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+ textArea.read(reader, null);
+ }
+ this.file = file;
+ this.dirty = false;
+ setTitle(file.getName());
+ String style = LanguageSupport.syntaxStyleFor(file.getName());
+ textArea.setSyntaxEditingStyle(style);
+ installLanguageSupport(style);
+ tabManager.updateTabTitle(this);
+ }
+
+ public void saveToFile(File file) {
+ try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+ textArea.write(writer);
+ this.file = file;
+ this.dirty = false;
+ setTitle(file.getName());
+ tabManager.updateTabTitle(this);
+ } catch (IOException ex) {
+ JOptionPane.showMessageDialog(tabManager.window.getFrame(),
+ "Error saving file: " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+ }
+ }
+
+ public void performSaveAs(Component parent) {
+ JFileChooser fc = tabManager.window.buildFileChooser();
+ if (fc.showSaveDialog(parent) != JFileChooser.APPROVE_OPTION) return;
+ File chosen = fc.getSelectedFile();
+ saveToFile(chosen);
+ String style = LanguageSupport.syntaxStyleFor(chosen.getName());
+ textArea.setSyntaxEditingStyle(style);
+ installLanguageSupport(style);
+ }
+
+
+ public JPanel getTabHeaderComponent() {
+ if (tabHeaderComponent == null) {
+ tabHeaderComponent = buildTabHeader();
+ }
+ return tabHeaderComponent;
+ }
+
+ private JPanel buildTabHeader() {
+ JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
+ panel.setOpaque(false);
+ JLabel label = new JLabel(title);
+ JButton close = new JButton("✕");
+ close.setBorder(BorderFactory.createEmptyBorder(0, 4, 0, 0));
+ close.setContentAreaFilled(false);
+ close.setFocusable(false);
+ close.addActionListener(e -> tabManager.closeTab(this));
+ panel.add(label);
+ panel.add(close);
+ return panel;
+ }
+
+ public void dispose() {
+ if (langSupport != null) {
+ langSupport.uninstall(textArea);
+ langSupport = null;
+ }
+ file = null;
+ }
+
+
+ private void buildTextArea() {
+ textArea = new RSyntaxTextArea(25, 80);
+ textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE);
+ textArea.setCodeFoldingEnabled(true);
+ textArea.setAntiAliasingEnabled(true);
+ textArea.setBracketMatchingEnabled(true);
+ textArea.setPaintMatchedBracketPair(true);
+ textArea.setMarkOccurrences(true);
+ textArea.setAutoIndentEnabled(true);
+ textArea.setTabSize(4);
+ textArea.setTabsEmulated(true);
+ }
+
+ private void buildScrollPane() {
+ scrollPane = new RTextScrollPane(textArea);
+ scrollPane.setFoldIndicatorEnabled(true);
+ scrollPane.setLineNumbersEnabled(true);
+ }
+
+ private void installDocumentListener() {
+ textArea.getDocument().addDocumentListener(new DocumentListener() {
+ private void markDirty() {
+ if (!dirty) {
+ dirty = true;
+ tabManager.updateTabTitle(EditorTab.this);
+ }
+ }
+ @Override public void insertUpdate(DocumentEvent e) { markDirty(); }
+ @Override public void removeUpdate(DocumentEvent e) { markDirty(); }
+ @Override public void changedUpdate(DocumentEvent e) { markDirty(); }
+ });
+ }
+
+ private void installLanguageSupport(String style) {
+ if (langSupport != null) {
+ langSupport.uninstall(textArea);
+ langSupport = null;
+ }
+ langSupport = LanguageSupport.install(textArea, style);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rdesk/applications/productivity/code/EditorWindow.java b/src/main/java/com/rdesk/applications/productivity/code/EditorWindow.java
new file mode 100644
index 0000000..020ddf9
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/code/EditorWindow.java
@@ -0,0 +1,122 @@
+package com.rdesk.applications.productivity.code;
+
+import org.fife.ui.rtextarea.*;
+import javax.swing.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.io.*;
+
+public class EditorWindow {
+
+ private JInternalFrame frame;
+ final TabManager tabManager;
+ private JToolBar toolbar;
+
+ public EditorWindow() {
+ frame = new JInternalFrame("CodeDesk", true, true, true, true);
+ frame.setSize(960, 680);
+ frame.setLayout(new BorderLayout());
+
+ tabManager = new TabManager(this);
+
+ toolbar = buildToolBar();
+ frame.add(toolbar, BorderLayout.NORTH);
+ frame.add(tabManager.getTabbedPane(), BorderLayout.CENTER);
+
+ installGlobalShortcuts();
+ tabManager.addTab("Untitled");
+
+ frame.setVisible(true);
+ }
+
+ public JInternalFrame getFrame() {
+ return frame;
+ }
+
+ private JToolBar buildToolBar() {
+ JToolBar bar = new JToolBar();
+ bar.setFloatable(false);
+
+ JButton newTabBtn = new JButton("New Tab");
+ JButton openBtn = new JButton("Open");
+ JButton saveBtn = new JButton("Save");
+ JButton saveAsBtn = new JButton("Save As");
+
+ newTabBtn.addActionListener(e -> tabManager.addTab("Untitled"));
+ openBtn.addActionListener(e -> actionOpen());
+ saveBtn.addActionListener(e -> actionSave());
+ saveAsBtn.addActionListener(e -> actionSaveAs());
+
+ bar.add(newTabBtn);
+ bar.add(openBtn);
+ bar.add(saveBtn);
+ bar.add(saveAsBtn);
+ return bar;
+ }
+
+ private void installGlobalShortcuts() {
+ InputMap im = frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+ ActionMap am = frame.getRootPane().getActionMap();
+
+ bind(im, am, "open", KeyStroke.getKeyStroke(KeyEvent.VK_O, InputEvent.CTRL_DOWN_MASK),
+ e -> actionOpen());
+ bind(im, am, "save", KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK),
+ e -> actionSave());
+ bind(im, am, "saveAs", KeyStroke.getKeyStroke(KeyEvent.VK_S,
+ InputEvent.CTRL_DOWN_MASK | InputEvent.SHIFT_DOWN_MASK),
+ e -> actionSaveAs());
+ bind(im, am, "closeTab", KeyStroke.getKeyStroke(KeyEvent.VK_W, InputEvent.CTRL_DOWN_MASK),
+ e -> tabManager.closeCurrentTab());
+ bind(im, am, "newTab", KeyStroke.getKeyStroke(KeyEvent.VK_T, InputEvent.CTRL_DOWN_MASK),
+ e -> tabManager.addTab("Untitled"));
+ }
+
+ private void bind(InputMap im, ActionMap am, String key, KeyStroke ks, ActionListener handler) {
+ im.put(ks, key);
+ am.put(key, new AbstractAction() {
+ @Override public void actionPerformed(ActionEvent e) {
+ handler.actionPerformed(e);
+ }
+ });
+ }
+
+
+ private void actionOpen() {
+ JFileChooser fc = buildFileChooser();
+ if (fc.showOpenDialog(frame) != JFileChooser.APPROVE_OPTION) return;
+ tabManager.openFile(fc.getSelectedFile());
+ }
+
+ private void actionSave() {
+ EditorTab tab = tabManager.getCurrentTab();
+ if (tab == null) return;
+ if (tab.getFile() != null) {
+ tab.saveToFile(tab.getFile());
+ } else {
+ tab.performSaveAs(frame);
+ }
+ }
+
+ private void actionSaveAs() {
+ EditorTab tab = tabManager.getCurrentTab();
+ if (tab != null) tab.performSaveAs(frame);
+ }
+
+
+ JFileChooser buildFileChooser() {
+ JFileChooser fc = new JFileChooser();
+ fc.setFileFilter(new javax.swing.filechooser.FileNameExtensionFilter(
+ "Source Files (java, js, ts, html, css, php, c, cpp, py, rb, pl, sh, sql, xml)",
+ "java", "js", "ts", "html", "htm", "css", "php",
+ "c", "h", "cpp", "cc", "cxx", "hpp",
+ "py", "rb", "pl", "sh", "bash", "sql", "xml"));
+ fc.setAcceptAllFileFilterUsed(true);
+ return fc;
+ }
+
+ void showError(String prefix, Exception ex) {
+ JOptionPane.showMessageDialog(frame,
+ prefix + ": " + ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rdesk/applications/productivity/code/LanguageSupport.java b/src/main/java/com/rdesk/applications/productivity/code/LanguageSupport.java
new file mode 100644
index 0000000..95787be
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/code/LanguageSupport.java
@@ -0,0 +1,86 @@
+package com.rdesk.applications.productivity.code;
+
+import org.fife.rsta.ac.AbstractLanguageSupport;
+import org.fife.rsta.ac.css.CssLanguageSupport;
+import org.fife.rsta.ac.html.HtmlLanguageSupport;
+import org.fife.rsta.ac.java.JavaLanguageSupport;
+import org.fife.rsta.ac.js.JavaScriptLanguageSupport;
+import org.fife.ui.autocomplete.*;
+import org.fife.ui.rsyntaxtextarea.*;
+import javax.swing.*;
+import java.awt.event.InputEvent;
+import java.awt.event.KeyEvent;
+import java.io.IOException;
+
+public class LanguageSupport {
+ public static String syntaxStyleFor(String fileName) {
+ if (fileName == null) return SyntaxConstants.SYNTAX_STYLE_NONE;
+ String n = fileName.toLowerCase();
+ if (n.endsWith(".java")) return SyntaxConstants.SYNTAX_STYLE_JAVA;
+ if (n.endsWith(".js") || n.endsWith(".ts")) return SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT;
+ if (n.endsWith(".html") || n.endsWith(".htm")) return SyntaxConstants.SYNTAX_STYLE_HTML;
+ if (n.endsWith(".css")) return SyntaxConstants.SYNTAX_STYLE_CSS;
+ if (n.endsWith(".php")) return SyntaxConstants.SYNTAX_STYLE_PHP;
+ if (n.endsWith(".c") || n.endsWith(".h")) return SyntaxConstants.SYNTAX_STYLE_C;
+ if (n.endsWith(".cpp") || n.endsWith(".cc")
+ || n.endsWith(".cxx") || n.endsWith(".hpp")) return SyntaxConstants.SYNTAX_STYLE_CPLUSPLUS;
+ if (n.endsWith(".py")) return SyntaxConstants.SYNTAX_STYLE_PYTHON;
+ if (n.endsWith(".rb")) return SyntaxConstants.SYNTAX_STYLE_RUBY;
+ if (n.endsWith(".pl")) return SyntaxConstants.SYNTAX_STYLE_PERL;
+ if (n.endsWith(".sh") || n.endsWith(".bash")) return SyntaxConstants.SYNTAX_STYLE_UNIX_SHELL;
+ if (n.endsWith(".sql")) return SyntaxConstants.SYNTAX_STYLE_SQL;
+ if (n.endsWith(".xml")) return SyntaxConstants.SYNTAX_STYLE_XML;
+ return SyntaxConstants.SYNTAX_STYLE_NONE;
+ }
+
+ public static AbstractLanguageSupport install(RSyntaxTextArea area, String style) {
+ if (style == null) style = area.getSyntaxEditingStyle();
+
+ AbstractLanguageSupport ls = buildLanguageSupport(style);
+ if (ls != null) {
+ try {
+ configureSupport(ls);
+ ls.install(area);
+ return ls;
+ } catch (Exception ex) {
+ System.err.println("CodeDesk: could not install language support for "
+ + style + ": " + ex.getMessage());
+ installFallbackCompletion(area);
+ return null;
+ }
+ } else {
+ installFallbackCompletion(area);
+ return null;
+ }
+ }
+
+
+ private static AbstractLanguageSupport buildLanguageSupport(String style) {
+ return switch (style) {
+ case SyntaxConstants.SYNTAX_STYLE_JAVA -> new JavaLanguageSupport();
+ case SyntaxConstants.SYNTAX_STYLE_JAVASCRIPT -> new JavaScriptLanguageSupport();
+ case SyntaxConstants.SYNTAX_STYLE_HTML -> new HtmlLanguageSupport();
+ case SyntaxConstants.SYNTAX_STYLE_CSS -> new CssLanguageSupport();
+ default -> null;
+ };
+ }
+
+ private static void configureSupport(AbstractLanguageSupport ls) throws IOException {
+ ls.setAutoActivationEnabled(true);
+ ls.setAutoActivationDelay(400);
+ ls.setAutoCompleteEnabled(true);
+ ls.setParameterAssistanceEnabled(true);
+ ls.setShowDescWindow(true);
+ if (ls instanceof JavaLanguageSupport jls) {
+ jls.getJarManager().addCurrentJreClassFileSource();
+ }
+ }
+
+ private static void installFallbackCompletion(RSyntaxTextArea area) {
+ AutoCompletion ac = new AutoCompletion(new DefaultCompletionProvider());
+ ac.setAutoCompleteEnabled(true);
+ ac.setAutoActivationEnabled(false);
+ ac.setTriggerKey(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, InputEvent.CTRL_DOWN_MASK));
+ ac.install(area);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/rdesk/applications/productivity/code/TabManager.java b/src/main/java/com/rdesk/applications/productivity/code/TabManager.java
new file mode 100644
index 0000000..40e9ca1
--- /dev/null
+++ b/src/main/java/com/rdesk/applications/productivity/code/TabManager.java
@@ -0,0 +1,135 @@
+package com.rdesk.applications.productivity.code;
+
+import org.fife.ui.rsyntaxtextarea.*;
+import org.fife.ui.rtextarea.RTextScrollPane;
+
+import javax.swing.*;
+import java.awt.*;
+import java.io.*;
+import java.util.*;
+import java.util.List;
+
+public class TabManager {
+
+ final EditorWindow window;
+ private final JTabbedPane tabbedPane;
+ private final List{@code
- * Kernel kernel = Kernel.get();
- * kernel.registerSystemApp(new MyCalculatorApp());
- * }
- *
- * @param app the {@link DesktopApp} implementation to register
- * @throws IllegalStateException if {@link #attachIconManager} has not been called yet
- */
public void registerSystemApp(DesktopApp app) {
if (iconManager == null) {
throw new IllegalStateException(
@@ -96,10 +76,6 @@ public class Kernel {
System.exit(0);
}
- // ------------------------------------------------------------------ //
- // Accessors //
- // ------------------------------------------------------------------ //
-
public AppManager apps() { return appManager; }
public WindowManager windows() { return windowManager; }
public EventBus events() { return eventBus; }