feat(gui): use list component for recent projects on start page (PR #2513)
* feat(gui): use list component witch recent projects on start page * fix: spotless check * move classes into one package and some minor changes --------- Co-authored-by: Skylot <118523+skylot@users.noreply.github.com>
This commit is contained in:
@@ -155,13 +155,13 @@ import jadx.gui.ui.panel.IssuesPanel;
|
||||
import jadx.gui.ui.panel.JDebuggerPanel;
|
||||
import jadx.gui.ui.panel.ProgressPanel;
|
||||
import jadx.gui.ui.popupmenu.RecentProjectsMenuListener;
|
||||
import jadx.gui.ui.startpage.StartPageNode;
|
||||
import jadx.gui.ui.tab.EditorSyncManager;
|
||||
import jadx.gui.ui.tab.NavigationController;
|
||||
import jadx.gui.ui.tab.QuickTabsTree;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.ui.tab.TabsController;
|
||||
import jadx.gui.ui.tab.dnd.TabDndController;
|
||||
import jadx.gui.ui.treenodes.StartPageNode;
|
||||
import jadx.gui.ui.treenodes.SummaryNode;
|
||||
import jadx.gui.ui.treenodes.UndisplayedStringsNode;
|
||||
import jadx.gui.update.JadxUpdate;
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
package jadx.gui.ui.panel;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.ui.treenodes.StartPageNode;
|
||||
import jadx.gui.utils.Icons;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class StartPagePanel extends ContentPanel {
|
||||
|
||||
public StartPagePanel(TabbedPane tabbedPane, StartPageNode node) {
|
||||
super(tabbedPane, node);
|
||||
MainWindow mainWindow = tabbedPane.getMainWindow();
|
||||
Font baseFont = mainWindow.getSettings().getFont();
|
||||
|
||||
JButton openFile = new JButton(NLS.str("file.open_title"), Icons.OPEN);
|
||||
openFile.addActionListener(ev -> mainWindow.openFileDialog());
|
||||
|
||||
JButton openProject = new JButton(NLS.str("file.open_project"), Icons.OPEN_PROJECT);
|
||||
openProject.addActionListener(ev -> mainWindow.openProjectDialog());
|
||||
|
||||
JPanel start = new JPanel();
|
||||
start.setBorder(sectionFrame(NLS.str("start_page.start"), baseFont));
|
||||
start.setLayout(new BoxLayout(start, BoxLayout.LINE_AXIS));
|
||||
start.add(openFile);
|
||||
start.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
start.add(openProject);
|
||||
start.add(Box.createHorizontalGlue());
|
||||
|
||||
JPanel recentPanel = new JPanel();
|
||||
JScrollPane scrollPane = new JScrollPane(recentPanel);
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setPreferredSize(new Dimension(400, 200));
|
||||
scrollPane.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
||||
fillRecentPanel(recentPanel, scrollPane, mainWindow);
|
||||
|
||||
JPanel recent = new JPanel();
|
||||
recent.setBorder(sectionFrame(NLS.str("start_page.recent"), baseFont));
|
||||
recent.setLayout(new BoxLayout(recent, BoxLayout.PAGE_AXIS));
|
||||
recent.add(scrollPane);
|
||||
|
||||
JPanel center = new JPanel();
|
||||
center.setLayout(new BorderLayout(10, 10));
|
||||
center.add(start, BorderLayout.PAGE_START);
|
||||
center.add(recent, BorderLayout.CENTER);
|
||||
center.setMaximumSize(new Dimension(700, 600));
|
||||
center.setAlignmentX(CENTER_ALIGNMENT);
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||
setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
|
||||
add(Box.createVerticalGlue());
|
||||
add(center);
|
||||
add(Box.createVerticalGlue());
|
||||
}
|
||||
|
||||
private void fillRecentPanel(JPanel panel, JScrollPane scrollPane, MainWindow mainWindow) {
|
||||
JadxSettings settings = mainWindow.getSettings();
|
||||
List<Path> recentProjects = settings.getRecentProjects();
|
||||
panel.removeAll();
|
||||
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
|
||||
|
||||
Font baseFont = settings.getFont();
|
||||
Font font = baseFont.deriveFont(baseFont.getSize() - 1f);
|
||||
for (Path path : recentProjects) {
|
||||
JButton openBtn = new JButton(path.getFileName().toString());
|
||||
openBtn.setToolTipText(path.toAbsolutePath().toString());
|
||||
openBtn.setFont(font);
|
||||
openBtn.setBorderPainted(false);
|
||||
openBtn.addActionListener(ev -> mainWindow.open(path));
|
||||
|
||||
JButton removeBtn = new JButton();
|
||||
removeBtn.setIcon(Icons.CLOSE_INACTIVE);
|
||||
removeBtn.setRolloverIcon(Icons.CLOSE);
|
||||
removeBtn.setRolloverEnabled(true);
|
||||
removeBtn.setFocusable(false);
|
||||
removeBtn.setBorder(null);
|
||||
removeBtn.setBorderPainted(false);
|
||||
removeBtn.setContentAreaFilled(false);
|
||||
removeBtn.setOpaque(true);
|
||||
removeBtn.addActionListener(e -> {
|
||||
mainWindow.getSettings().removeRecentProject(path);
|
||||
fillRecentPanel(panel, scrollPane, mainWindow);
|
||||
panel.revalidate();
|
||||
scrollPane.repaint();
|
||||
});
|
||||
JPanel linePanel = new JPanel();
|
||||
linePanel.setLayout(new BoxLayout(linePanel, BoxLayout.LINE_AXIS));
|
||||
linePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
|
||||
linePanel.add(openBtn);
|
||||
linePanel.add(Box.createHorizontalGlue());
|
||||
linePanel.add(removeBtn);
|
||||
|
||||
panel.add(linePanel);
|
||||
}
|
||||
panel.add(Box.createVerticalGlue());
|
||||
}
|
||||
|
||||
private static Border sectionFrame(String title, Font font) {
|
||||
TitledBorder titledBorder = BorderFactory.createTitledBorder(title);
|
||||
titledBorder.setTitleFont(font.deriveFont(Font.BOLD, font.getSize() + 1));
|
||||
Border spacing = BorderFactory.createEmptyBorder(10, 10, 10, 10);
|
||||
return BorderFactory.createCompoundBorder(titledBorder, spacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package jadx.gui.ui.startpage;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.Objects;
|
||||
|
||||
import jadx.api.plugins.utils.CommonFileUtils;
|
||||
|
||||
/**
|
||||
* Represents an item in the recent projects list.
|
||||
*/
|
||||
public class RecentProjectItem {
|
||||
private final Path path;
|
||||
|
||||
public RecentProjectItem(Path path) {
|
||||
this.path = Objects.requireNonNull(path);
|
||||
}
|
||||
|
||||
public Path getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getProjectName() {
|
||||
return CommonFileUtils.removeFileExtension(path.getFileName().toString());
|
||||
}
|
||||
|
||||
public String getAbsolutePath() {
|
||||
return path.toAbsolutePath().toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getProjectName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
RecentProjectItem that = (RecentProjectItem) o;
|
||||
return Objects.equals(path, that.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(path);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package jadx.gui.ui.startpage;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.ListCellRenderer;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.basic.BasicButtonUI;
|
||||
|
||||
import jadx.gui.utils.Icons;
|
||||
|
||||
public class RecentProjectListCellRenderer extends JPanel implements ListCellRenderer<RecentProjectItem> {
|
||||
private static final long serialVersionUID = 5550591869239586857L;
|
||||
|
||||
private final JLabel fileNameLabel;
|
||||
private final JLabel pathLabel;
|
||||
private final JButton removeProjectBtn;
|
||||
|
||||
private final Color defaultBackground;
|
||||
private final Color defaultForeground;
|
||||
|
||||
private final Color selectedBackground;
|
||||
private final Color selectedForeground;
|
||||
|
||||
private Rectangle removeIconBounds;
|
||||
|
||||
public RecentProjectListCellRenderer(Font baseFont) {
|
||||
super(new BorderLayout(5, 0));
|
||||
setOpaque(true);
|
||||
setBorder(BorderFactory.createEmptyBorder(5, 10, 5, 5));
|
||||
|
||||
this.fileNameLabel = new JLabel();
|
||||
fileNameLabel.setFont(baseFont.deriveFont(Font.BOLD, baseFont.getSize()));
|
||||
|
||||
this.pathLabel = new JLabel();
|
||||
pathLabel.setFont(baseFont.deriveFont(baseFont.getSize() - 2f));
|
||||
pathLabel.setForeground(UIManager.getColor("Label.disabledForeground"));
|
||||
|
||||
JPanel textPanel = new JPanel(new BorderLayout());
|
||||
textPanel.setOpaque(false);
|
||||
textPanel.add(fileNameLabel, BorderLayout.NORTH);
|
||||
textPanel.add(pathLabel, BorderLayout.SOUTH);
|
||||
|
||||
removeProjectBtn = new JButton();
|
||||
removeProjectBtn.setIcon(Icons.CLOSE_INACTIVE);
|
||||
removeProjectBtn.setOpaque(false);
|
||||
removeProjectBtn.setUI(new BasicButtonUI());
|
||||
removeProjectBtn.setContentAreaFilled(false);
|
||||
removeProjectBtn.setFocusable(false);
|
||||
removeProjectBtn.setBorder(null);
|
||||
removeProjectBtn.setBorderPainted(false);
|
||||
|
||||
add(textPanel, BorderLayout.CENTER);
|
||||
add(removeProjectBtn, BorderLayout.EAST);
|
||||
|
||||
defaultBackground = UIManager.getColor("List.background");
|
||||
defaultForeground = UIManager.getColor("List.foreground");
|
||||
|
||||
selectedBackground = UIManager.getColor("List.selectionBackground");
|
||||
selectedForeground = UIManager.getColor("List.selectionForeground");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<? extends RecentProjectItem> list,
|
||||
RecentProjectItem value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
|
||||
fileNameLabel.setText(value.getProjectName());
|
||||
pathLabel.setText(value.getAbsolutePath());
|
||||
|
||||
boolean isThisRemoveButtonHovered = (index == StartPagePanel.hoveredRemoveBtnIndex);
|
||||
removeProjectBtn.setIcon(isThisRemoveButtonHovered ? Icons.CLOSE : Icons.CLOSE_INACTIVE);
|
||||
removeProjectBtn.setRolloverEnabled(isThisRemoveButtonHovered);
|
||||
|
||||
if (isSelected) {
|
||||
setBackground(selectedBackground);
|
||||
fileNameLabel.setForeground(selectedForeground);
|
||||
pathLabel.setForeground(selectedForeground.darker());
|
||||
removeProjectBtn.setForeground(selectedForeground);
|
||||
} else {
|
||||
setBackground(defaultBackground);
|
||||
fileNameLabel.setForeground(defaultForeground);
|
||||
pathLabel.setForeground(UIManager.getColor("Label.disabledForeground"));
|
||||
removeProjectBtn.setForeground(defaultForeground);
|
||||
}
|
||||
|
||||
setToolTipText(value.getAbsolutePath());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding paint to calculate the bounds of the remove button.
|
||||
* This is crucial for the MouseListener on the JList to determine if a click/hover was on the
|
||||
* button.
|
||||
*/
|
||||
@Override
|
||||
public void paint(Graphics g) {
|
||||
super.paint(g);
|
||||
// Ensure the button's layout is valid before getting bounds
|
||||
removeProjectBtn.doLayout();
|
||||
// Calculate bounds of the remove button relative to this renderer panel
|
||||
int x = getWidth() - removeProjectBtn.getWidth() - getBorder().getBorderInsets(this).right;
|
||||
int y = (getHeight() - removeProjectBtn.getHeight()) / 2;
|
||||
removeIconBounds = new Rectangle(x, y, removeProjectBtn.getWidth(), removeProjectBtn.getHeight());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the bounds of the remove button within the renderer component's coordinate system.
|
||||
* This is crucial for the MouseListener on the JList to determine if a click was on the icon.
|
||||
*
|
||||
* @return Rectangle representing the bounds of the remove icon.
|
||||
*/
|
||||
public Rectangle getRemoveIconBounds() {
|
||||
return removeIconBounds;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
package jadx.gui.ui.treenodes;
|
||||
package jadx.gui.ui.startpage;
|
||||
|
||||
import javax.swing.Icon;
|
||||
|
||||
import jadx.gui.treemodel.JClass;
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.ui.panel.StartPagePanel;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.utils.Icons;
|
||||
import jadx.gui.utils.NLS;
|
||||
@@ -0,0 +1,267 @@
|
||||
package jadx.gui.ui.startpage;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseMotionAdapter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.BorderFactory;
|
||||
import javax.swing.Box;
|
||||
import javax.swing.BoxLayout;
|
||||
import javax.swing.DefaultListModel;
|
||||
import javax.swing.JButton;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPanel;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.ListSelectionModel;
|
||||
import javax.swing.ScrollPaneConstants;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.border.Border;
|
||||
import javax.swing.border.TitledBorder;
|
||||
|
||||
import jadx.gui.settings.JadxSettings;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.ui.panel.ContentPanel;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.utils.Icons;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class StartPagePanel extends ContentPanel {
|
||||
private static final long serialVersionUID = 2457805175218770732L;
|
||||
|
||||
private final RecentProjectsJList recentList;
|
||||
private final DefaultListModel<RecentProjectItem> recentListModel;
|
||||
private final MainWindow mainWindow;
|
||||
private final JadxSettings settings;
|
||||
|
||||
public static int hoveredRemoveBtnIndex = -1;
|
||||
|
||||
public StartPagePanel(TabbedPane tabbedPane, StartPageNode node) {
|
||||
super(tabbedPane, node);
|
||||
this.mainWindow = tabbedPane.getMainWindow();
|
||||
this.settings = mainWindow.getSettings();
|
||||
Font baseFont = settings.getFont();
|
||||
|
||||
JButton openFile = new JButton(NLS.str("file.open_title"), Icons.OPEN);
|
||||
openFile.addActionListener(ev -> mainWindow.openFileDialog());
|
||||
|
||||
JButton openProject = new JButton(NLS.str("file.open_project"), Icons.OPEN_PROJECT);
|
||||
openProject.addActionListener(ev -> mainWindow.openProjectDialog());
|
||||
|
||||
JPanel start = new JPanel();
|
||||
start.setBorder(sectionFrame(NLS.str("start_page.start"), baseFont));
|
||||
start.setLayout(new BoxLayout(start, BoxLayout.LINE_AXIS));
|
||||
start.add(openFile);
|
||||
start.add(Box.createRigidArea(new Dimension(10, 0)));
|
||||
start.add(openProject);
|
||||
start.add(Box.createHorizontalGlue());
|
||||
|
||||
this.recentListModel = new DefaultListModel<>();
|
||||
this.recentList = new RecentProjectsJList(recentListModel);
|
||||
this.recentList.setCellRenderer(new RecentProjectListCellRenderer(baseFont));
|
||||
this.recentList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
|
||||
JScrollPane scrollPane = new JScrollPane(recentList);
|
||||
scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
|
||||
scrollPane.setPreferredSize(new Dimension(400, 250));
|
||||
scrollPane.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
||||
recentList.addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
int index = recentList.locationToIndex(e.getPoint());
|
||||
if (index == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
RecentProjectItem item = recentListModel.getElementAt(index);
|
||||
if (item == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
RecentProjectListCellRenderer renderer = (RecentProjectListCellRenderer) recentList.getCellRenderer()
|
||||
.getListCellRendererComponent(recentList, item, index, false, false);
|
||||
|
||||
Rectangle cellBounds = recentList.getCellBounds(index, index);
|
||||
if (cellBounds != null) {
|
||||
int xInCell = e.getX() - cellBounds.x;
|
||||
int yInCell = e.getY() - cellBounds.y;
|
||||
|
||||
Rectangle removeIconBounds = renderer.getRemoveIconBounds();
|
||||
if (removeIconBounds != null && removeIconBounds.contains(xInCell, yInCell)) {
|
||||
removeRecentProject(item.getPath());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton(e)) {
|
||||
openRecentProject(item.getPath());
|
||||
} else if (SwingUtilities.isRightMouseButton(e)) {
|
||||
recentList.setSelectedIndex(index);
|
||||
showRecentProjectContextMenu(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
recentList.addMouseMotionListener(new MouseMotionAdapter() {
|
||||
@Override
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
int oldHoveredRemoveBtnIndex = hoveredRemoveBtnIndex;
|
||||
hoveredRemoveBtnIndex = -1;
|
||||
|
||||
int currentCellIndex = recentList.locationToIndex(e.getPoint());
|
||||
|
||||
if (currentCellIndex != -1) {
|
||||
RecentProjectItem item = recentListModel.getElementAt(currentCellIndex);
|
||||
RecentProjectListCellRenderer renderer = (RecentProjectListCellRenderer) recentList.getCellRenderer()
|
||||
.getListCellRendererComponent(recentList, item, currentCellIndex, recentList.isSelectedIndex(currentCellIndex),
|
||||
false);
|
||||
|
||||
Rectangle cellBounds = recentList.getCellBounds(currentCellIndex, currentCellIndex);
|
||||
if (cellBounds != null) {
|
||||
int xInCell = e.getX() - cellBounds.x;
|
||||
int yInCell = e.getY() - cellBounds.y;
|
||||
|
||||
Rectangle removeIconBounds = renderer.getRemoveIconBounds();
|
||||
if (removeIconBounds != null && removeIconBounds.contains(xInCell, yInCell)) {
|
||||
hoveredRemoveBtnIndex = currentCellIndex;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (oldHoveredRemoveBtnIndex != hoveredRemoveBtnIndex) {
|
||||
if (oldHoveredRemoveBtnIndex != -1) {
|
||||
Rectangle bounds = recentList.getCellBounds(oldHoveredRemoveBtnIndex, oldHoveredRemoveBtnIndex);
|
||||
if (bounds != null) {
|
||||
recentList.repaint(bounds);
|
||||
}
|
||||
}
|
||||
if (hoveredRemoveBtnIndex != -1) {
|
||||
Rectangle bounds = recentList.getCellBounds(hoveredRemoveBtnIndex, hoveredRemoveBtnIndex);
|
||||
if (bounds != null) {
|
||||
recentList.repaint(bounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JPanel recent = new JPanel();
|
||||
recent.setBorder(sectionFrame(NLS.str("start_page.recent"), baseFont));
|
||||
recent.setLayout(new BoxLayout(recent, BoxLayout.PAGE_AXIS));
|
||||
recent.add(scrollPane);
|
||||
|
||||
JPanel center = new JPanel();
|
||||
center.setLayout(new BorderLayout(10, 10));
|
||||
center.add(start, BorderLayout.PAGE_START);
|
||||
center.add(recent, BorderLayout.CENTER);
|
||||
center.setMaximumSize(new Dimension(700, 600));
|
||||
center.setAlignmentX(CENTER_ALIGNMENT);
|
||||
|
||||
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
|
||||
setBorder(BorderFactory.createEmptyBorder(50, 50, 50, 50));
|
||||
add(Box.createVerticalGlue());
|
||||
add(center);
|
||||
add(Box.createVerticalGlue());
|
||||
|
||||
fillRecentProjectsList();
|
||||
}
|
||||
|
||||
private void fillRecentProjectsList() {
|
||||
recentListModel.clear();
|
||||
List<Path> recentPaths = settings.getRecentProjects();
|
||||
for (Path path : recentPaths) {
|
||||
recentListModel.addElement(new RecentProjectItem(path));
|
||||
}
|
||||
recentList.revalidate();
|
||||
recentList.repaint();
|
||||
}
|
||||
|
||||
private void openRecentProject(Path path) {
|
||||
mainWindow.open(path);
|
||||
}
|
||||
|
||||
private void removeRecentProject(Path path) {
|
||||
settings.removeRecentProject(path);
|
||||
fillRecentProjectsList();
|
||||
if (hoveredRemoveBtnIndex != -1 && hoveredRemoveBtnIndex >= recentListModel.size()) {
|
||||
hoveredRemoveBtnIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private void showRecentProjectContextMenu(MouseEvent e) {
|
||||
JPopupMenu popupMenu = new JPopupMenu();
|
||||
RecentProjectItem selectedItem = recentList.getSelectedValue();
|
||||
|
||||
if (selectedItem != null) {
|
||||
JMenuItem openItem = new JMenuItem(NLS.str("file.open_project"));
|
||||
openItem.addActionListener(actionEvent -> openRecentProject(selectedItem.getPath()));
|
||||
popupMenu.add(openItem);
|
||||
|
||||
JMenuItem removeItem = new JMenuItem(NLS.str("start_page.list.delete_recent_project"));
|
||||
removeItem.addActionListener(actionEvent -> removeRecentProject(selectedItem.getPath()));
|
||||
popupMenu.add(removeItem);
|
||||
}
|
||||
|
||||
popupMenu.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
|
||||
private static Border sectionFrame(String title, Font font) {
|
||||
TitledBorder titledBorder = BorderFactory.createTitledBorder(title);
|
||||
titledBorder.setTitleFont(font.deriveFont(Font.BOLD, font.getSize() + 1));
|
||||
Border spacing = BorderFactory.createEmptyBorder(10, 10, 10, 10);
|
||||
return BorderFactory.createCompoundBorder(titledBorder, spacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadSettings() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Inner class: Custom JList to override getToolTipText method.
|
||||
* This allows displaying specific tooltips based on mouse position within a cell.
|
||||
*/
|
||||
private static class RecentProjectsJList extends JList<RecentProjectItem> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public RecentProjectsJList(DefaultListModel<RecentProjectItem> model) {
|
||||
super(model);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getToolTipText(MouseEvent event) {
|
||||
int index = locationToIndex(event.getPoint());
|
||||
if (index == -1) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RecentProjectItem item = getModel().getElementAt(index);
|
||||
if (item == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RecentProjectListCellRenderer renderer = (RecentProjectListCellRenderer) getCellRenderer()
|
||||
.getListCellRendererComponent(this, item, index, isSelectedIndex(index), false);
|
||||
|
||||
Rectangle cellBounds = getCellBounds(index, index);
|
||||
if (cellBounds != null) {
|
||||
int xInCell = event.getX() - cellBounds.x;
|
||||
int yInCell = event.getY() - cellBounds.y;
|
||||
|
||||
Rectangle removeIconBounds = renderer.getRemoveIconBounds();
|
||||
if (removeIconBounds != null && removeIconBounds.contains(xInCell, yInCell)) {
|
||||
return NLS.str("start_page.list.delete_recent_project.tooltip");
|
||||
}
|
||||
}
|
||||
return item.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,6 +56,8 @@ file.export_node=Datei exportieren
|
||||
start_page.title=Startseite
|
||||
start_page.start=Start
|
||||
start_page.recent=Aktuelle Projekte
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
tree.inputs_title=Eingaben
|
||||
tree.input_files=Dateien
|
||||
|
||||
@@ -56,6 +56,8 @@ file.export_node=Export file
|
||||
start_page.title=Start page
|
||||
start_page.start=Start
|
||||
start_page.recent=Recent projects
|
||||
start_page.list.delete_recent_project=Delete project
|
||||
start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
tree.inputs_title=Inputs
|
||||
tree.input_files=Files
|
||||
|
||||
@@ -56,6 +56,8 @@ file.exit=Salir
|
||||
#start_page.title=Start page
|
||||
#start_page.start=Start
|
||||
#start_page.recent=Recent projects
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
#tree.inputs_title=Inputs
|
||||
#tree.input_files=Files
|
||||
|
||||
@@ -56,6 +56,8 @@ file.exit=Keluar
|
||||
start_page.title=Halaman Awal
|
||||
start_page.start=Mulai
|
||||
start_page.recent=Proyek Terbaru
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
tree.inputs_title=Input
|
||||
tree.input_files=Berkas
|
||||
|
||||
@@ -56,6 +56,8 @@ file.exit=나가기
|
||||
start_page.title=페이지 시작
|
||||
start_page.start=시작
|
||||
start_page.recent=최근 프로젝트
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
#tree.inputs_title=Inputs
|
||||
#tree.input_files=Files
|
||||
|
||||
@@ -56,6 +56,8 @@ file.exit=Sair
|
||||
start_page.title=Página inicial
|
||||
start_page.start=Começar
|
||||
start_page.recent=Projetos recentes
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
#tree.inputs_title=Inputs
|
||||
#tree.input_files=Files
|
||||
|
||||
@@ -56,6 +56,8 @@ file.exit=Выход
|
||||
start_page.title=Начальная страница
|
||||
start_page.start=Начать
|
||||
start_page.recent=Недавние проекты
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
tree.inputs_title=Входные файлы
|
||||
tree.input_files=Файлы
|
||||
|
||||
@@ -56,6 +56,8 @@ file.export_node=导出文件
|
||||
start_page.title=开始页面
|
||||
start_page.start=开始
|
||||
start_page.recent=最近项目
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
tree.inputs_title=输入
|
||||
tree.input_files=文件
|
||||
|
||||
@@ -56,6 +56,8 @@ file.export_node=匯出檔案
|
||||
start_page.title=開始頁面
|
||||
start_page.start=開始
|
||||
start_page.recent=近期專案
|
||||
#start_page.list.delete_recent_project=Delete project
|
||||
#start_page.list.delete_recent_project.tooltip=Delete project from recent list
|
||||
|
||||
tree.inputs_title=輸入
|
||||
tree.input_files=檔案
|
||||
|
||||
Reference in New Issue
Block a user