From a01c0e998b90254e206267c05b7c61161a55fcef Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Mon, 12 May 2025 01:34:42 +0200 Subject: [PATCH 1/2] editor: Changed the layout to use a dockable style --- src/main/java/org/editor/AccessFrame.java | 2 + src/main/java/org/editor/CanvasFrame.java | 5 +- src/main/java/org/editor/CodeEditor.java | 103 ++++- src/main/java/org/editor/DockablePanel.java | 42 ++ src/main/java/org/editor/EditorWindow.java | 392 ++++++++++-------- src/main/java/org/editor/events/Actions.java | 2 +- .../java/org/editor/events/ListAction.java | 77 ++++ .../java/org/editor/events/MenuEvents.java | 47 +-- src/main/java/org/editor/fs/FileFilter.java | 13 + .../java/org/editor/fs/FilePersistance.java | 88 ++++ src/main/java/org/editor/menu/Menus.java | 65 +-- .../org/editor/panels/DashboardPanel.form | 103 ++++- .../org/editor/panels/DashboardPanel.java | 125 +++++- 13 files changed, 807 insertions(+), 257 deletions(-) create mode 100644 src/main/java/org/editor/DockablePanel.java create mode 100644 src/main/java/org/editor/events/ListAction.java create mode 100644 src/main/java/org/editor/fs/FileFilter.java create mode 100644 src/main/java/org/editor/fs/FilePersistance.java diff --git a/src/main/java/org/editor/AccessFrame.java b/src/main/java/org/editor/AccessFrame.java index bddba0b..00177e4 100644 --- a/src/main/java/org/editor/AccessFrame.java +++ b/src/main/java/org/editor/AccessFrame.java @@ -1,5 +1,7 @@ package org.editor; +import com.vlsolutions.swing.docking.DockKey; +import com.vlsolutions.swing.docking.Dockable; import org.editor.events.Actions; import java.awt.BorderLayout; import java.awt.Color; diff --git a/src/main/java/org/editor/CanvasFrame.java b/src/main/java/org/editor/CanvasFrame.java index b7d6929..9a9d077 100644 --- a/src/main/java/org/editor/CanvasFrame.java +++ b/src/main/java/org/editor/CanvasFrame.java @@ -1,8 +1,11 @@ package org.editor; +import com.vlsolutions.swing.docking.DockKey; +import com.vlsolutions.swing.docking.Dockable; import java.awt.BasicStroke; import java.awt.BorderLayout; import java.awt.Color; +import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; @@ -54,6 +57,7 @@ public class CanvasFrame extends JPanel implements MouseListener, MouseMotionLis private Point selectionEnd = null; private static CanvasFrame _the = null; + private DockKey key = new DockKey("canvas"); private CanvasFrame() { super(new BorderLayout()); @@ -319,5 +323,4 @@ private void drawCrosshair(Graphics2D g2) { g2.fillOval(mouseX - radius, mouseY - radius, radius * 2, radius * 2); } } - } diff --git a/src/main/java/org/editor/CodeEditor.java b/src/main/java/org/editor/CodeEditor.java index 3f5d5d5..e554135 100644 --- a/src/main/java/org/editor/CodeEditor.java +++ b/src/main/java/org/editor/CodeEditor.java @@ -1,6 +1,11 @@ package org.editor; +import com.vlsolutions.swing.docking.DockKey; +import com.vlsolutions.swing.docking.Dockable; import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; import java.io.File; import java.io.IOException; import java.nio.file.Path; @@ -10,6 +15,8 @@ import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.text.BadLocationException; +import org.editor.fs.FileFilter; +import org.editor.fs.FilePersistance; import org.editor.icons.Icons; import org.fife.ui.autocomplete.AutoCompletion; import org.fife.ui.autocomplete.BasicCompletion; @@ -20,6 +27,8 @@ import org.fife.ui.rsyntaxtextarea.CodeTemplateManager; import org.fife.ui.rsyntaxtextarea.FileLocation; import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; +import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaHighlighter; +import org.fife.ui.rsyntaxtextarea.SyntaxConstants; import org.fife.ui.rsyntaxtextarea.TextEditorPane; import org.fife.ui.rsyntaxtextarea.TokenMakerFactory; import org.fife.ui.rsyntaxtextarea.templates.CodeTemplate; @@ -30,13 +39,19 @@ * * @author hexaredecimal */ -public class CodeEditor extends JPanel { +public class CodeEditor extends JPanel implements Dockable { public TextEditorPane textArea; public Path file = null; private boolean isTmp; + private DockKey key; // = new DockKey("textEditor"); + public int tabIndex =0; public CodeEditor() { + this(null); + } + + public CodeEditor(Path path) { super(new BorderLayout()); textArea = new TextEditorPane(); textArea.setCodeFoldingEnabled(true); @@ -61,17 +76,55 @@ public CodeEditor() { gutter.setBookmarkingEnabled(true); gutter.setBookmarkIcon(Icons.getIcon("bookmark")); + var self = this; + textArea.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + EditorWindow.setSelectedEditor(self); + getCursorPositionText(self); + } + + @Override + public void focusLost(FocusEvent e) { + } + }); + + this.addFocusListener(new FocusListener() { + @Override + public void focusGained(FocusEvent e) { + EditorWindow.setSelectedEditor(self); + getCursorPositionText(self); + } + + @Override + public void focusLost(FocusEvent e) { + } + }); + try { - var fp = File.createTempFile("piccasso-", "-tmp"); - file = fp.toPath(); - fp.deleteOnExit(); - isTmp = true; + String tip = "Source code editor"; + var icon = Icons.getIcon("code-file"); + if (path == null) { + var fp = File.createTempFile("piccasso-", "-tmp"); + + key = new DockKey(fp.getName(), fp.getName(), tip, icon); + file = fp.toPath(); + isTmp = true; + fp.deleteOnExit(); + } else { + key = new DockKey(path.toFile().getName(), path.toFile().getName(), tip, icon); + file = path; + } + key.setCloseEnabled(true); + key.setAutoHideEnabled(true); + this.putClientProperty("dockKey", key); } catch (IOException ex) { Logger.getLogger(CodeEditor.class.getName()).log(Level.SEVERE, null, ex); } textArea .addCaretListener(e -> { + EditorWindow.setSelectedEditor(this); getCursorPositionText(this); }); @@ -85,6 +138,8 @@ public boolean saveFile() { try { textArea.save(); + FilePersistance.persistFile(file); + EditorWindow.setSeletedTabTitle(file.toFile().getName()); EditorWindow.current_file.setText("Written to " + file); return true; } catch (IOException e) { @@ -102,6 +157,9 @@ public void setIsTmp(boolean isTmp) { public boolean saveFileAs() { var fileChooser = new JFileChooser("."); + fileChooser.setFileFilter(FileFilter.mdFilter); + fileChooser.setFileFilter(FileFilter.picsFilter); + int status = fileChooser.showSaveDialog(EditorWindow.win); if (status != JFileChooser.APPROVE_OPTION) { EditorWindow.current_file.setText("Save cancelled"); @@ -113,8 +171,11 @@ public boolean saveFileAs() { textArea.saveAs(loc); textArea.load(loc); file = path.toPath(); + FilePersistance.persistFile(file); getCursorPositionText(this); + EditorWindow.setSeletedTabTitle(path.getName()); EditorWindow.current_file.setText("Written to " + path); + isTmp = false; return true; } catch (IOException ex) { JOptionPane.showMessageDialog(EditorWindow.win, ex); @@ -192,4 +253,36 @@ public static void createTemplateManager() { ctm.addTemplate(ct); } } + + public boolean load(File fp) { + setIsTmp(false); + var loc = FileLocation.create(fp); + FilePersistance.persistFile(fp.toPath()); + try { + textArea.load(loc); + + if (fp.getName().endsWith(".pics")) { + textArea.setSyntaxEditingStyle("text/piccode"); + } else if (fp.getName().endsWith(".md")) { + textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_MARKDOWN); + } else { + textArea.setSyntaxEditingStyle(SyntaxConstants.SYNTAX_STYLE_NONE); + } + + return true; + } catch (IOException ex) { + JOptionPane.showMessageDialog(EditorWindow.win, ex); + return false; + } + } + + @Override + public DockKey getDockKey() { + return key; + } + + @Override + public Component getComponent() { + return this; + } } diff --git a/src/main/java/org/editor/DockablePanel.java b/src/main/java/org/editor/DockablePanel.java new file mode 100644 index 0000000..e753f1d --- /dev/null +++ b/src/main/java/org/editor/DockablePanel.java @@ -0,0 +1,42 @@ +package org.editor; + +import com.vlsolutions.swing.docking.DockKey; +import com.vlsolutions.swing.docking.Dockable; +import java.awt.Component; +import java.awt.LayoutManager; +import javax.swing.JPanel; +import org.editor.icons.Icons; + +/** + * + * @author hexaredecimal + */ +public class DockablePanel extends JPanel implements Dockable { + private DockKey key; + + public DockablePanel(LayoutManager layout) { + super(layout); + key = new DockKey("dock-" + System.nanoTime()); + } + + public DockablePanel(LayoutManager layout, String id) { + super(layout); + key = new DockKey(id); + } + + public DockablePanel(LayoutManager layout, String id, String name, String tip, String icon) { + super(layout); + key = new DockKey(id, name, tip, Icons.getIcon(icon)); + } + + @Override + public DockKey getDockKey() { + return key; + } + + @Override + public Component getComponent() { + return this; + } + +} diff --git a/src/main/java/org/editor/EditorWindow.java b/src/main/java/org/editor/EditorWindow.java index 0dd5816..1afc5c9 100644 --- a/src/main/java/org/editor/EditorWindow.java +++ b/src/main/java/org/editor/EditorWindow.java @@ -2,6 +2,16 @@ import org.editor.panels.DashboardPanel; import com.formdev.flatlaf.FlatLightLaf; +import com.vlsolutions.swing.docking.DockKey; +import com.vlsolutions.swing.docking.DockView; +import com.vlsolutions.swing.docking.Dockable; +import com.vlsolutions.swing.docking.DockableState; +import com.vlsolutions.swing.docking.DockingConstants; +import com.vlsolutions.swing.docking.DockingDesktop; +import com.vlsolutions.swing.docking.DockingPreferences; +import com.vlsolutions.swing.docking.event.DockableStateWillChangeEvent; +import com.vlsolutions.swing.docking.event.DockableStateWillChangeListener; +import com.vlsolutions.swing.docking.ui.DockingUISettings; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; @@ -11,15 +21,11 @@ import java.awt.GridLayout; import java.awt.Insets; import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.io.File; import java.nio.file.Path; -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; -import javax.imageio.ImageIO; import javax.swing.Action; import javax.swing.BorderFactory; +import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JLabel; @@ -38,22 +44,13 @@ import org.editor.events.Actions; import org.editor.icons.Icons; import org.editor.menu.Menus; -import org.editor.util.It; import org.fife.rsta.ui.CollapsibleSectionPanel; //import org.fife.rsta.ui.DocumentMap; -import org.fife.rsta.ui.GoToDialog; -import org.fife.rsta.ui.SizeGripIcon; import org.fife.rsta.ui.search.FindDialog; import org.fife.rsta.ui.search.ReplaceDialog; -import org.fife.rsta.ui.search.ReplaceToolBar; import org.fife.rsta.ui.search.SearchEvent; import org.fife.rsta.ui.search.SearchListener; -import org.fife.rsta.ui.search.FindToolBar; -import org.fife.ui.rsyntaxtextarea.ErrorStrip; -import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea; -import org.fife.ui.rsyntaxtextarea.SyntaxConstants; -import org.fife.ui.rtextarea.RTextScrollPane; import org.fife.ui.rtextarea.SearchContext; import org.fife.ui.rtextarea.SearchEngine; import org.fife.ui.rtextarea.SearchResult; @@ -72,10 +69,13 @@ public final class EditorWindow extends JFrame implements SearchListener { public static JLabel line_perc = new JLabel(); public static JLabel charset = new JLabel(); public static JProgressBar seekBar = new JProgressBar(); + private DockablePanel dashboard; private CollapsibleSectionPanel csp; public static FindDialog findDialog; public static ReplaceDialog replaceDialog; + private DockingDesktop desk = new DockingDesktop(); + private static CodeEditor selected = null; public static EditorWindow the() { if (win == null) { @@ -88,27 +88,72 @@ public static EditorWindow the() { public EditorWindow() { super("Piccode - DashBoard"); - + var _ =new CodeEditor(); root = getRootPane(); Icons.loadIcons(); - tabs = new JTabbedPane(); tabEditors = new HashMap<>(); CodeEditor.createTemplateManager(); - - addTab(null); - Actions.loadActions(); initSearchDialogs(); + DockingUISettings.getInstance().installUI(); + customizeDock(); + try { UIManager.setLookAndFeel(new FlatLightLaf()); } catch (Exception ex) { System.err.println("Failed to initialize LaF"); } - var width = 900; - var height = 600; + int width = 900; + int height = 600; + + desk.addDockableStateWillChangeListener(event -> { + var current = event.getCurrentState(); + + if (current == null) { + return; + } + + if (current.getDockable() instanceof CodeEditor ed) { + if (event.getFutureState().isClosed()) { + if (removeIfDirty(ed.tabIndex, ed) == false) { + event.cancel(); + } + } + } + }); JPanel main_panel = new JPanel(new BorderLayout()); + //main_panel.add(desk, BorderLayout.CENTER); + + JToolBar tool_bar = makeToolBar( + Actions.newProjectAction, + Actions.newFileAction, + Actions.openFileAction, + null, + Actions.saveAction, + null, + Actions.undoAction, + Actions.redoAction, + Actions.compileAction, + Actions.renderAction, + null, + Actions.exitAction + ); + main_panel.add(tool_bar, BorderLayout.PAGE_START); + + current_file = new JLabel("[NONE]"); + line_info = new JLabel(); + line_perc = new JLabel(); + charset = new JLabel(); + seekBar = new JProgressBar(); + seekBar.setValue(50); + + JToolBar bottom_bar = makeLRToolBar( + new Component[]{current_file, null}, + new Component[]{line_info, line_perc, seekBar, null, charset} + ); + main_panel.add(bottom_bar, BorderLayout.PAGE_END); Action[] app_actions = { Actions.showFileTreeAction, @@ -117,32 +162,25 @@ public EditorWindow() { Actions.exportAction, Actions.AIAction, Actions.communityAction, - Actions.pluginsAction,}; - var side_panel = makeCoolbar(height, app_actions); - - main_panel.add(side_panel, BorderLayout.WEST); - - JSplitPane editor_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - editor_split.setDividerLocation(width - 300); + Actions.pluginsAction + }; - var pluginSpace = new JPanel(); - JSplitPane plugin_split = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); - plugin_split.setLeftComponent(editor_split); - plugin_split.setDividerLocation(width - 100); - plugin_split.setRightComponent(pluginSpace); - main_panel.add(plugin_split, BorderLayout.CENTER); + var bar = makeCoolbar(height, app_actions); - editor_split.setLeftComponent(tabs); + JMenuBar menu_bar = new JMenuBar(); + this.setJMenuBar(menu_bar); - JSplitPane canvas_split = new JSplitPane(JSplitPane.VERTICAL_SPLIT); - canvas_split.setDividerLocation(height - 250); - editor_split.setRightComponent(canvas_split); + Actions.loadActions(); + Menus.addMenus(menu_bar); + this.setIconImage(Icons.getIcon("appicon").getImage()); + // Canvas and Access Panels var canvas_panel = CanvasFrame.the(); - JScrollPane scrollPane = new JScrollPane(canvas_panel); - - JPanel render_panel = new JPanel(new BorderLayout()); + var access_panel = new DockablePanel(new BorderLayout(), "Run"); + access_panel.add(new AccessFrame(width)); + var render_panel = new DockablePanel(new BorderLayout(), "Render"); + render_panel.add(canvas_panel, BorderLayout.CENTER); Action[] render_actions = { Actions.normalAction, Actions.gridAction, @@ -153,96 +191,36 @@ public EditorWindow() { Actions.thickBrushAction, Actions.paintBucketAction, Actions.effectsAction,}; + var short_cuts = makeCoolbar(canvas_panel.getHeight(), render_actions); short_cuts.setBorder(BorderFactory.createEmptyBorder()); render_panel.add(short_cuts, BorderLayout.EAST); - render_panel.add(scrollPane, BorderLayout.CENTER); - canvas_split.setLeftComponent(render_panel); + render_panel.add(new JScrollPane(canvas_panel), BorderLayout.CENTER); - var access_panel = new AccessFrame(width); - canvas_split.setRightComponent(access_panel); - - JMenuBar menu_bar = new JMenuBar(); - this.setJMenuBar(menu_bar); + var cool_bar = new DockablePanel(new BorderLayout(), "Quick Access"); + cool_bar.add(bar, BorderLayout.CENTER); - Menus.addMenus(menu_bar); - - Action[] tool_actions = { - Actions.newProjectAction, - Actions.newFileAction, - Actions.openFileAction, - Actions.openProjectAction, - null, - Actions.saveAction, - Actions.saveAsAction, - Actions.saveAllAction, - null, - Actions.undoAction, - Actions.redoAction, - Actions.copyAction, - Actions.cutAction, - Actions.pasteAction, - null, - Actions.compileAction, - Actions.renderAction, - null, - Actions.exportAction, - Actions.exitAction, - null, - Actions.normalAction, - Actions.gridAction, - Actions.pointAction, - Actions.rulerAction, - Actions.snapAction, - Actions.brushAction, - Actions.thickBrushAction, - Actions.paintBucketAction, - Actions.effectsAction, - null, - Actions.docsAction, - Actions.websiteAction, - Actions.aboutAction - }; + DockingPreferences.setDottedDesktopStyle(); + getContentPane().add(desk, BorderLayout.CENTER); + getContentPane().add(render_panel, BorderLayout.WEST); + getContentPane().add(access_panel, BorderLayout.SOUTH); + getContentPane().add(cool_bar, BorderLayout.EAST); + getContentPane().add(tool_bar, BorderLayout.PAGE_START); + getContentPane().add(bottom_bar, BorderLayout.PAGE_END); - var tool_bar = makeToolBar(tool_actions); - main_panel.add(tool_bar, BorderLayout.PAGE_START); + dashboard = new DockablePanel(new BorderLayout(), "Piccasso DashBoard", "DashBoard", "Home page", "file"); + dashboard.add(new JScrollPane(new DashboardPanel()), BorderLayout.CENTER); + getContentPane().add(access_panel, BorderLayout.EAST); + + desk.addDockable(dashboard); + desk.addDockable(cool_bar); + desk.setAutoHide(cool_bar, true); - current_file = new JLabel(); - line_info = new JLabel(); - line_perc = new JLabel(); - charset = new JLabel(); - seekBar = new JProgressBar(); - seekBar.setValue(50); + desk.split(dashboard, render_panel, DockingConstants.SPLIT_RIGHT, 0.7); + desk.split(render_panel, access_panel, DockingConstants.SPLIT_BOTTOM); - var file = getSelectedEditor().file; + win = this; - if (file != null) { - current_file.setText(file.toString()); - } else { - current_file.setText("[NONE]"); - } - - var bottom_bar = makeLRToolBar(new Component[]{ - current_file, - null - }, new Component[]{ - line_info, - line_perc, - seekBar, - null, - charset,}); - main_panel.add(bottom_bar, BorderLayout.PAGE_END); - - tabs.addChangeListener(c -> { - var ed = getSelectedEditor(); - if (ed == null) { - return; - } - CodeEditor.getCursorPositionText(ed); - }); - - this.setIconImage(Icons.getIcon("appicon").getImage()); - this.add(main_panel); this.setSize(width, height); this.setLocationRelativeTo(null); this.setVisible(true); @@ -257,42 +235,58 @@ private void initSearchDialogs() { } public static void addTab(ActionEvent e) { - var index = tabs.getTabCount(); - var editor = new CodeEditor(); - if (index >= 1) { - tabs.remove(index - 1); - index = tabs.getTabCount(); - } + int index = tabEditors.size(); + CodeEditor editor = new CodeEditor(); + editor.tabIndex = index; + Path file = editor.file; + editor.requestFocusInWindow(); + current_file.setText(file != null ? file.toString() : "[NONE]"); tabEditors.put(index, editor); - tabs.addTab("", editor); - tabs.setTabComponentAt(tabs.getTabCount() - 1, makeTabHeader(tabs, editor.file == null ? "Tab " + index : editor.filePathTruncated())); - if (index >= 0) { - addPlusTab(tabs); + + // Add first editor normally + if (index == 0) { + win.desk.addDockable(editor); + win.desk.createTab(win.dashboard, editor, 2); + } else { + // Add to same container as first editor + CodeEditor firstEditor = tabEditors.get(0); + win.desk.createTab(firstEditor, editor, 2); } - tabs.setSelectedIndex(index); } public static void addTab(Path path, Void e) { - var index = tabs.getTabCount(); - var editor = new CodeEditor(); - editor.file = path; - if (index >= 1) { - tabs.remove(index - 1); - index = tabs.getTabCount(); - } + var index = tabEditors.size(); + var editor = new CodeEditor(path); + editor.tabIndex = index; + editor.load(path.toFile()); + editor.requestFocusInWindow(); tabEditors.put(index, editor); - tabs.addTab("", editor); - tabs.setTabComponentAt(tabs.getTabCount() - 1, makeTabHeader(tabs, editor.file == null ? "Tab " + index : editor.filePathTruncated())); - if (index >= 0) { - addPlusTab(tabs); + + // Add first editor normally + if (index == 0) { + win.desk.createTab(win.dashboard, editor, 2); + } else { + // Add to same container as first editor + CodeEditor firstEditor = tabEditors.get(0); + win.desk.createTab(firstEditor, editor, 1); } - tabs.setSelectedIndex(index); + } + + public static void setSelectedEditor(CodeEditor ed) { + selected = ed; } public static CodeEditor getSelectedEditor() { - int index = tabs.getSelectedIndex(); - var ed = tabEditors.get(index); - return ed; + if (selected != null) { + return selected; + } + + for (var editor : tabEditors.values()) { + if (editor.textArea.isFocusOwner()) { + return editor; + } + } + return tabEditors.values().toArray(CodeEditor[]::new)[0]; // fallback if nothing has focus } private static void addPlusTab(JTabbedPane tabs) { @@ -340,62 +334,90 @@ private static Component makeTabHeader(JTabbedPane tabs, String title) { } public static void removeTab() { - if (tabs.getTabCount() == 1) { + if (tabEditors.size() <= 1) { return; } - int index = tabs.getSelectedIndex(); - var ed = tabEditors.get(index); - removeIfDirty(index, ed); + CodeEditor selected = getSelectedEditor(); + if (selected == null) { + return; + } + + Integer index = getEditorIndex(selected); + if (index == null) { + return; + } + + removeIfDirty(index, selected); } public static void removeAllTabs() { - int count = tabs.getTabCount(); - for (int index = 0; index < count - 1; index++) { - var ed = tabEditors.get(index); - if (ed == null) { - continue; - } - removeIfDirty(index, ed); + var editors = new HashMap<>(tabEditors); // Copy to avoid ConcurrentModificationException + for (var entry : editors.entrySet()) { + removeIfDirty(entry.getKey(), entry.getValue()); } - addTab(null); - removeTab(); } public static int tabsCount() { - return tabs.getTabCount(); + return tabEditors.size(); } - - private static void removeIfDirty(Integer index, CodeEditor ed) { + + private static boolean removeIfDirty(Integer index, CodeEditor ed) { if (ed.textArea.isDirty()) { int result = JOptionPane.showConfirmDialog(win, "File " + ed.filePathTruncated() + " is modified. Save?"); if (result == JOptionPane.OK_OPTION) { - if (!ed.saveFile()) { - return; - } + return ed.saveFile(); } } + win.desk.remove((Dockable) ed); // Actual removal from docking layout tabEditors.remove(index); - tabs.remove(index); - int last = migrateIndexes(); - tabs.setSelectedIndex(last); + migrateIndexes(); + + return true; } - private static int migrateIndexes() { - int index = 0; - tabEditors.clear(); - for (int i = 0; i < tabs.getTabCount(); i++) { - var comp = tabs.getComponentAt(i); - if (comp instanceof CodeEditor ed) { - tabEditors.put(i, ed); - index = Math.max(index, i); + private static boolean isDocked(Dockable d) { + for (var state: win.desk.getDockables()) { + var dockable = state.getDockable(); + if (dockable == d || dockable.equals(d)) { + return true; + } + } + return false; + } + + private static Integer getEditorIndex(CodeEditor ed) { + for (var entry : tabEditors.entrySet()) { + if (entry.getValue() == ed) { + return entry.getKey(); } } - return index; + return null; + } + + private static void migrateIndexes() { + HashMap newMap = new HashMap<>(); + int idx = 0; + for (CodeEditor ed : tabEditors.values()) { + newMap.put(idx++, ed); + } + tabEditors = newMap; + } + + public static void saveAll() { + for (var kv : tabEditors.entrySet()) { + var editor = kv.getValue(); + editor.saveFile(); + } + } + + public static void setSeletedTabTitle(String title) { + int index = tabs.getSelectedIndex(); + tabs.setTitleAt(index, title); } private JPanel makeCoolbar(int height, Action... actions) { - JPanel cool_bar = new JPanel(new BorderLayout()); + var cool_bar = new JPanel(new BorderLayout()); cool_bar.setPreferredSize(new Dimension(50, height)); JPanel top_buttons = new JPanel(new GridLayout(10, 1)); top_buttons.setOpaque(false); // transparent to inherit background @@ -415,6 +437,7 @@ private JPanel makeCoolbar(int height, Action... actions) { bottom_button.add(settingsBtn, BorderLayout.SOUTH); cool_bar.add(top_buttons, BorderLayout.NORTH); cool_bar.add(bottom_button, BorderLayout.SOUTH); + return cool_bar; } @@ -502,4 +525,13 @@ public String getSelectedText() { return getSelectedEditor().textArea.getSelectedText(); } + private void customizeDock() { + UIManager.put("DockViewTitleBar.close", (Icon) Icons.getIcon("close")); + UIManager.put("DockTabbedPane.close", (Icon) Icons.getIcon("close")); + UIManager.put("DockViewTitleBar.isFloatButtonDisplayed", true); + + var font = (Font)UIManager.get("DockViewTitleBar.titleFont"); + UIManager.put("DockViewTitleBar.titleFont", new Font(font.getName(), font.getStyle(), 11)); + } + } diff --git a/src/main/java/org/editor/events/Actions.java b/src/main/java/org/editor/events/Actions.java index 1cd8574..d521bea 100644 --- a/src/main/java/org/editor/events/Actions.java +++ b/src/main/java/org/editor/events/Actions.java @@ -179,7 +179,7 @@ public static void loadActions() { .icon("save-all") .tooltip("Save All") .shortcut("control shift S") - .handler(e -> It.todo()) + .handler(MenuEvents::saveAllFiles) .build(); exitAction diff --git a/src/main/java/org/editor/events/ListAction.java b/src/main/java/org/editor/events/ListAction.java new file mode 100644 index 0000000..9742d13 --- /dev/null +++ b/src/main/java/org/editor/events/ListAction.java @@ -0,0 +1,77 @@ +package org.editor.events; + +/** + * + * @author hexaredecimal + */ +import java.awt.event.*; +import javax.swing.*; + + +// Reference: https://stackoverflow.com/questions/4344682/double-click-event-on-jlist-element +public class ListAction implements MouseListener { + + private static final KeyStroke ENTER = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); + + private JList list; + private KeyStroke keyStroke; + + /* + * Add an Action to the JList bound by the default KeyStroke + */ + public ListAction(JList list, Action action) { + this(list, action, ENTER); + } + + /* + * Add an Action to the JList bound by the specified KeyStroke + */ + public ListAction(JList list, Action action, KeyStroke keyStroke) { + this.list = list; + this.keyStroke = keyStroke; + + // Add the KeyStroke to the InputMap + InputMap im = list.getInputMap(); + im.put(keyStroke, keyStroke); + + // Add the Action to the ActionMap + setAction(action); + + // Handle mouse double click + list.addMouseListener(this); + } + + /* + * Add the Action to the ActionMap + */ + public void setAction(Action action) { + list.getActionMap().put(keyStroke, action); + } + + // Implement MouseListener interface + public void mouseClicked(MouseEvent e) { + if (e.getClickCount() == 2) { + Action action = list.getActionMap().get(keyStroke); + + if (action != null) { + ActionEvent event = new ActionEvent( + list, + ActionEvent.ACTION_PERFORMED, + ""); + action.actionPerformed(event); + } + } + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + public void mousePressed(MouseEvent e) { + } + + public void mouseReleased(MouseEvent e) { + } +} diff --git a/src/main/java/org/editor/events/MenuEvents.java b/src/main/java/org/editor/events/MenuEvents.java index 7370463..31774f5 100644 --- a/src/main/java/org/editor/events/MenuEvents.java +++ b/src/main/java/org/editor/events/MenuEvents.java @@ -1,6 +1,5 @@ package org.editor.events; - import java.awt.event.ActionEvent; import java.io.IOException; import java.nio.file.Files; @@ -14,6 +13,7 @@ import org.editor.CodeEditor; import org.editor.EditorWindow; import org.editor.dialogs.AboutDialog; +import org.editor.fs.FileFilter; import org.fife.rsta.ui.GoToDialog; import org.fife.ui.rsyntaxtextarea.FileLocation; @@ -64,15 +64,15 @@ static void findEvent(ActionEvent e) { } findDialog.setVisible(true); } - + public static void aboutDialog(ActionEvent e) { - var _ = new AboutDialog(EditorWindow.win); + var _ = new AboutDialog(EditorWindow.win); } public static void closeTab(ActionEvent e) { EditorWindow.removeTab(); } - + public static void closeAllTabs(ActionEvent e) { EditorWindow.removeAllTabs(); } @@ -80,6 +80,9 @@ public static void closeAllTabs(ActionEvent e) { static void openFile(ActionEvent e) { // TODO: Use the System object to get the current pwd var fileChooser = new JFileChooser("."); + fileChooser.setFileFilter(FileFilter.mdFilter); + fileChooser.setFileFilter(FileFilter.picsFilter); + int status = fileChooser.showOpenDialog(EditorWindow.win); if (status != JFileChooser.APPROVE_OPTION) { return; @@ -87,31 +90,27 @@ static void openFile(ActionEvent e) { var fp = fileChooser.getSelectedFile(); var path = fp.toPath(); - try { - EditorWindow.addTab(path, null); - var loc = FileLocation.create(fp); - var ed = EditorWindow.getSelectedEditor(); - ed.setIsTmp(false); - ed.textArea.load(loc); - } catch (IOException ex) { - JOptionPane.showMessageDialog(EditorWindow.win, ex); - } + EditorWindow.addTab(path, null); } static void saveFile(ActionEvent e) { - if (EditorWindow.tabsCount() == 1) { - return; - } - var ed = EditorWindow.getSelectedEditor(); - ed.saveFile(); + if (EditorWindow.tabsCount() == 1) { + return; + } + var ed = EditorWindow.getSelectedEditor(); + ed.saveFile(); } - + static void saveFileAs(ActionEvent e) { - if (EditorWindow.tabsCount() == 1) { - return; - } - var ed = EditorWindow.getSelectedEditor(); - ed.saveFileAs(); + if (EditorWindow.tabsCount() == 1) { + return; + } + var ed = EditorWindow.getSelectedEditor(); + ed.saveFileAs(); + } + + static void saveAllFiles(ActionEvent e) { + EditorWindow.saveAll(); } static void closeFile(ActionEvent e) { diff --git a/src/main/java/org/editor/fs/FileFilter.java b/src/main/java/org/editor/fs/FileFilter.java new file mode 100644 index 0000000..cc946a7 --- /dev/null +++ b/src/main/java/org/editor/fs/FileFilter.java @@ -0,0 +1,13 @@ +package org.editor.fs; + +import javax.swing.filechooser.FileNameExtensionFilter; + +/** + * + * @author hexaredecimal + */ +public class FileFilter { + public static final FileNameExtensionFilter picsFilter = new FileNameExtensionFilter("Piccasso Script Files", "pics"); + public static final FileNameExtensionFilter mdFilter = new FileNameExtensionFilter("Markdown Files", "md"); + public static final FileNameExtensionFilter allFilter = new FileNameExtensionFilter("All Files (*.*)", "*"); +} diff --git a/src/main/java/org/editor/fs/FilePersistance.java b/src/main/java/org/editor/fs/FilePersistance.java new file mode 100644 index 0000000..cdd1056 --- /dev/null +++ b/src/main/java/org/editor/fs/FilePersistance.java @@ -0,0 +1,88 @@ +package org.editor.fs; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * + * @author hexaredecimal + */ +public class FilePersistance { + private static final List EMPTY = new ArrayList<>(); + private static final String RECENT_FILES = "./etc/rf/xxx.yy"; + private static final String RECENT_PROJECTS = "./etc/rf/xxx.yy"; + + public static List getRecentFiles() { + return getFiles(RECENT_FILES); + } + + public static List getRecentProjects() { + return getFiles(RECENT_PROJECTS); + } + + public static boolean isFilePersisted(Path path) { + var name = path.toString(); + return getRecentFiles().contains(name); + } + + public static boolean isProjectPersisted(Path path) { + var name = path.toString(); + return getRecentFiles().contains(name); + } + + public static void persistProject(Path path) { + persistTo(path, RECENT_PROJECTS); + } + + public static void persistFile(Path path) { + persistTo(path, RECENT_PROJECTS); + } + + + private static void persistTo(Path path, String dir) { + if (isFilePersisted(path)) { + return; + } + var files = getRecentFiles(); + files.addFirst(path.toString()); + var dest = new File(dir).toPath(); + try { + Files.write(dest, files); + } catch (IOException ex) { + Logger.getLogger(FilePersistance.class.getName()).log(Level.SEVERE, null, ex); + } + } + private static List getFiles(String file) { + var fp = new File(file); + + + if (!fp.exists()) { + try { + fp.createNewFile(); + return EMPTY; + } catch (IOException ex) { + return EMPTY; + } + } + + try { + var contents = Files.readString(fp.toPath()); + var items = contents + .lines() + .limit(15) // TODO: Allow this to be customizable throw the settings + .toList(); + var mutableList = new ArrayList(); + items.forEach(item -> mutableList.add(item)); + return mutableList; + } catch (IOException ex) { + return EMPTY; + } + } +} diff --git a/src/main/java/org/editor/menu/Menus.java b/src/main/java/org/editor/menu/Menus.java index b7173cb..01371cc 100644 --- a/src/main/java/org/editor/menu/Menus.java +++ b/src/main/java/org/editor/menu/Menus.java @@ -1,6 +1,8 @@ package org.editor.menu; import java.awt.Dimension; +import java.awt.event.ActionListener; +import java.io.File; import javax.swing.Action; import javax.swing.Box; import javax.swing.ImageIcon; @@ -9,8 +11,10 @@ import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JTextField; +import org.editor.EditorWindow; import org.editor.SearchInput; import org.editor.events.Actions; +import org.editor.fs.FilePersistance; import org.editor.icons.Icons; import org.fife.ui.rtextarea.RTextArea; @@ -19,7 +23,7 @@ * @author hexaredecimal */ public class Menus { - + public static void addMenus(JMenuBar menu_bar) { addFileMenu(menu_bar); addEditMenu(menu_bar); @@ -37,9 +41,9 @@ public static void addMenus(JMenuBar menu_bar) { searchField.setMaximumSize(new Dimension(150, searchSize.height)); // Limit max width menu_bar.add(searchField); menu_bar.add(Box.createRigidArea(new Dimension(5, 0))); - + Action[] actions = {Actions.navBottom, Actions.navTop, Actions.navLeft, Actions.navRight}; - for (var action: actions) { + for (var action : actions) { JButton btn = new JButton(action); btn.setText(""); menu_bar.add(btn); @@ -56,16 +60,28 @@ private static void addFileMenu(JMenuBar menu_bar) { JMenu recents = new JMenu("Recent Projects"); recents.setIcon(Icons.getIcon("time-machine")); fileMenu.add(recents); - + fileMenu.add(new JMenuItem(Actions.closeProjectAction)); fileMenu.addSeparator(); fileMenu.add(new JMenuItem(Actions.openFileAction)); - + JMenu recentfiles = new JMenu("Recent Files"); recentfiles.setIcon(Icons.getIcon("restore-page")); + + FilePersistance + .getRecentFiles() + .forEach(item -> { + var fp = new File(item); + var menuItem = createMenuItem(fp.getName(), "file", (e) -> { + var path = fp.toPath(); + EditorWindow.addTab(path, null); + }); + recentfiles.add(menuItem); + }); + fileMenu.add(recentfiles); - + fileMenu.add(new JMenuItem(Actions.closeFileAction)); fileMenu.addSeparator(); @@ -103,11 +119,11 @@ private static void addEditMenu(JMenuBar menu_bar) { private static void addNavigateMenu(JMenuBar menu_bar) { JMenu navMenu = new JMenu("Navigage"); - + JMenu tabs = new JMenu("Tabs"); tabs.setIcon(Icons.getIcon("layout")); navMenu.add(tabs); - + tabs.add(new JMenuItem(Actions.gotoTabAction)); tabs.add(new JMenuItem(Actions.addTabAction)); tabs.add(new JMenuItem(Actions.removeTabAction)); @@ -115,10 +131,10 @@ private static void addNavigateMenu(JMenuBar menu_bar) { tabs.add(new JMenuItem(Actions.removeAllTabsAction)); tabs.addSeparator(); tabs.add(createMenuItem("[Tab: 0]", "restore-window")); - + navMenu.addSeparator(); navMenu.add(new JMenuItem(Actions.gotoFileAction)); - + menu_bar.add(navMenu); } @@ -138,10 +154,10 @@ private static void addToolMenu(JMenuBar menu_bar) { toolsMenu.addSeparator(); toolsMenu.add(new JMenuItem(Actions.optionsAction)); toolsMenu.addSeparator(); - + JMenu renderToolsMenu = new JMenu("Tools"); renderToolsMenu.setIcon(Icons.getIcon("tools")); - + renderToolsMenu.add(new JMenuItem(Actions.normalAction)); renderToolsMenu.add(new JMenuItem(Actions.gridAction)); renderToolsMenu.add(new JMenuItem(Actions.pointAction)); @@ -151,11 +167,11 @@ private static void addToolMenu(JMenuBar menu_bar) { renderToolsMenu.add(new JMenuItem(Actions.thickBrushAction)); renderToolsMenu.add(new JMenuItem(Actions.paintBucketAction)); renderToolsMenu.add(new JMenuItem(Actions.effectsAction)); - + toolsMenu.add(renderToolsMenu); menu_bar.add(toolsMenu); } - + private static void addHelp(JMenuBar menu_bar) { JMenu helpMenu = new JMenu("Help"); helpMenu.add(new JMenuItem(Actions.docsAction)); @@ -165,28 +181,23 @@ private static void addHelp(JMenuBar menu_bar) { helpMenu.add(new JMenuItem(Actions.aboutAction)); menu_bar.add(helpMenu); } - - private static JMenuItem createMenuItem(Action action) { - JMenuItem item = new JMenuItem(action); - item.setToolTipText(null); // Swing annoyingly adds tool tip text to the menu item - return item; - } - - private static JMenuItem createMenuItem(String text) { - JMenuItem item = new JMenuItem(text); + + private static JMenuItem createMenuItem(String text, String icon) { + JMenuItem item = new JMenuItem(text, Icons.getIcon(icon)); return item; } - - private static JMenuItem createMenuItem(String text, String icon) { + + private static JMenuItem createMenuItem(String text, String icon, ActionListener listener) { JMenuItem item = new JMenuItem(text, Icons.getIcon(icon)); + item.addActionListener(listener); return item; } - + private static JMenuItem createMenuItem(String icon, Action action, String tooltip) { JMenuItem item = new JMenuItem(action); item.setIcon(Icons.getIcon(icon)); item.setToolTipText(tooltip); // Swing annoyingly adds tool tip text to the menu item return item; } - + } diff --git a/src/main/java/org/editor/panels/DashboardPanel.form b/src/main/java/org/editor/panels/DashboardPanel.form index 254de04..19bfffe 100644 --- a/src/main/java/org/editor/panels/DashboardPanel.form +++ b/src/main/java/org/editor/panels/DashboardPanel.form @@ -18,11 +18,14 @@ - + - + + + + @@ -36,11 +39,15 @@ - - - + + + + + + + - + @@ -60,7 +67,7 @@ - + @@ -72,15 +79,39 @@ - + + + + + - + + + + + + + + + + + + + + + + + + + + + @@ -172,5 +203,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/main/java/org/editor/panels/DashboardPanel.java b/src/main/java/org/editor/panels/DashboardPanel.java index dab84b6..4936b7e 100644 --- a/src/main/java/org/editor/panels/DashboardPanel.java +++ b/src/main/java/org/editor/panels/DashboardPanel.java @@ -4,6 +4,21 @@ */ package org.editor.panels; +import java.awt.Component; +import java.awt.event.ActionEvent; +import java.io.File; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.DefaultListCellRenderer; +import javax.swing.DefaultListModel; +import javax.swing.Icon; +import javax.swing.JLabel; +import javax.swing.JList; +import org.editor.EditorWindow; +import org.editor.events.ListAction; +import org.editor.fs.FilePersistance; +import org.editor.icons.Icons; + /** * * @author hexaredecimal @@ -15,6 +30,7 @@ public class DashboardPanel extends javax.swing.JPanel { */ public DashboardPanel() { initComponents(); + loadPersistedState(); } /** @@ -28,6 +44,8 @@ private void initComponents() { jLabel1 = new javax.swing.JLabel(); jPanel1 = new javax.swing.JPanel(); + jScrollPane2 = new javax.swing.JScrollPane(); + rFilesList = new javax.swing.JList<>(filesModel); jPanel2 = new javax.swing.JPanel(); jButton1 = new javax.swing.JButton(); jButton2 = new javax.swing.JButton(); @@ -35,24 +53,34 @@ private void initComponents() { jCheckBox1 = new javax.swing.JCheckBox(); jLabel2 = new javax.swing.JLabel(); jLabel3 = new javax.swing.JLabel(); + jPanel3 = new javax.swing.JPanel(); + jScrollPane3 = new javax.swing.JScrollPane(); + rProjList = new javax.swing.JList<>(); jLabel1.setIcon(new javax.swing.ImageIcon(getClass().getResource("/applogo/dashboard.png"))); // NOI18N jLabel1.setToolTipText(""); jLabel1.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); jLabel1.setName(""); // NOI18N - jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Recent Projects", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("sansserif", 1, 13), new java.awt.Color(255, 153, 51))); // NOI18N + jPanel1.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Recent Files", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("sansserif", 1, 13), new java.awt.Color(255, 153, 51))); // NOI18N jPanel1.setAutoscrolls(true); + jScrollPane2.setViewportView(rFilesList); + javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 339, Short.MAX_VALUE) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane2) + .addContainerGap()) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 0, Short.MAX_VALUE) + .addGroup(jPanel1Layout.createSequentialGroup() + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 121, Short.MAX_VALUE) + .addContainerGap()) ); jPanel2.setBorder(new javax.swing.border.LineBorder(new java.awt.Color(0, 0, 0), 1, true)); @@ -111,17 +139,40 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addContainerGap()) ); + jPanel3.setBorder(javax.swing.BorderFactory.createTitledBorder(null, "Recent Projects", javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("sansserif", 1, 13), new java.awt.Color(255, 153, 51))); // NOI18N + jPanel3.setAutoscrolls(true); + + jScrollPane3.setViewportView(rProjList); + + javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3); + jPanel3.setLayout(jPanel3Layout); + jPanel3Layout.setHorizontalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addContainerGap() + .addComponent(jScrollPane3) + .addContainerGap()) + ); + jPanel3Layout.setVerticalGroup( + jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(jPanel3Layout.createSequentialGroup() + .addComponent(jScrollPane3, javax.swing.GroupLayout.DEFAULT_SIZE, 120, Short.MAX_VALUE) + .addContainerGap()) + ); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addGap(56, 56, 56) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) .addGroup(layout.createSequentialGroup() .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(jPanel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))) .addComponent(jLabel1)) .addContainerGap(56, Short.MAX_VALUE)) ); @@ -131,17 +182,66 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { .addContainerGap() .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 401, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) - .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addContainerGap(15, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jPanel3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap(17, Short.MAX_VALUE)) ); }// //GEN-END:initComponents private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed - // TODO add your handling code here: + // TODO add your handling code here: }//GEN-LAST:event_jButton1ActionPerformed + private void loadPersistedState() { + FilePersistance + .getRecentFiles() + .forEach(item -> { + var fp = new File(item); + var path = fp.toPath().toString(); + filesModel.addElement(new ListItem(path, Icons.getIcon("file"))); + }); + + Action displayAction = new AbstractAction() { + @Override + public void actionPerformed(ActionEvent e) { + var list = (JList) e.getSource(); + var value = list.getSelectedValue().name; + EditorWindow.addTab(new File(value).toPath(), null); + } + }; + + rFilesList.setCellRenderer(new ListItemRenderer()); + var _ = new ListAction(rFilesList, displayAction); + } + + private static DefaultListModel filesModel = new DefaultListModel<>(); + private static DefaultListModel projectModel = new DefaultListModel<>(); + + class ListItem { + + String name; + Icon icon; + + public ListItem(String name, Icon icon) { + this.name = name; + this.icon = icon; + } + } + + class ListItemRenderer extends DefaultListCellRenderer { + + @Override + public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { + ListItem item = (ListItem) value; + JLabel label = (JLabel) super.getListCellRendererComponent(list, item.name, index, isSelected, cellHasFocus); + label.setIcon(item.icon); + return label; + } + } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton jButton1; @@ -153,5 +253,10 @@ private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRS private javax.swing.JLabel jLabel3; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; + private javax.swing.JPanel jPanel3; + private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JScrollPane jScrollPane3; + private javax.swing.JList rFilesList; + private javax.swing.JList rProjList; // End of variables declaration//GEN-END:variables } From aa8ebf00a9ee34688a33e591a23cb59b30333912 Mon Sep 17 00:00:00 2001 From: hexaredecimal Date: Mon, 12 May 2025 01:35:11 +0200 Subject: [PATCH 2/2] pom.xml: More deps --- pom.xml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 322daad..9d76c01 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,13 @@ rstaui 3.3.1 - + + + org.bidib.jbidib.com.vldocking + vldocking + 3.0.10 + +