feat(gui): pin tabs (PR #2230)
* add ability to pin tabs * save pinned tabs with Save Project action * further prevent closing pinned tabs * add translation entries * prevent pinning start page * add pinned tabs tree view * properly dispose of quickTabsTree * restructure code * more unpin context menu items
This commit is contained in:
@@ -136,6 +136,8 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
|
||||
private boolean dockLogViewer = true;
|
||||
|
||||
private boolean dockQuickTabs = false;
|
||||
|
||||
private TabDndGhostType tabDndGhostType = TabDndGhostType.OUTLINE;
|
||||
|
||||
private int settingsVersion = CURRENT_SETTINGS_VERSION;
|
||||
@@ -742,7 +744,16 @@ public class JadxSettings extends JadxCLIArgs {
|
||||
|
||||
public void setDockLogViewer(boolean dockLogViewer) {
|
||||
this.dockLogViewer = dockLogViewer;
|
||||
partialSync(settings -> this.dockLogViewer = dockLogViewer);
|
||||
partialSync(settings -> settings.dockLogViewer = dockLogViewer);
|
||||
}
|
||||
|
||||
public boolean isDockQuickTabs() {
|
||||
return dockQuickTabs;
|
||||
}
|
||||
|
||||
public void setDockQuickTabs(boolean dockQuickTabs) {
|
||||
this.dockQuickTabs = dockQuickTabs;
|
||||
partialSync(settings -> settings.dockQuickTabs = dockQuickTabs);
|
||||
}
|
||||
|
||||
public XposedCodegenLanguage getXposedCodegenLanguage() {
|
||||
|
||||
@@ -29,6 +29,7 @@ public class TabStateViewAdapter {
|
||||
tvs.setCaret(viewState.getCaretPos());
|
||||
tvs.setView(new ViewPoint(viewState.getViewPoint()));
|
||||
tvs.setActive(viewState.isActive());
|
||||
tvs.setPinned(viewState.isPinned());
|
||||
return tvs;
|
||||
}
|
||||
|
||||
@@ -41,6 +42,7 @@ public class TabStateViewAdapter {
|
||||
}
|
||||
EditorViewState viewState = new EditorViewState(node, tvs.getSubPath(), tvs.getCaret(), tvs.getView().toPoint());
|
||||
viewState.setActive(tvs.isActive());
|
||||
viewState.setPinned(tvs.isPinned());
|
||||
return viewState;
|
||||
} catch (Exception e) {
|
||||
LOG.error("Failed to load tab state: " + tvs, e);
|
||||
|
||||
@@ -7,6 +7,7 @@ public class TabViewState {
|
||||
private int caret;
|
||||
private ViewPoint view;
|
||||
boolean active;
|
||||
boolean pinned;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
@@ -55,4 +56,12 @@ public class TabViewState {
|
||||
public void setActive(boolean active) {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public boolean isPinned() {
|
||||
return pinned;
|
||||
}
|
||||
|
||||
public void setPinned(boolean pinned) {
|
||||
this.pinned = pinned;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ public abstract class JNode extends DefaultMutableTreeNode implements Comparable
|
||||
return javaNode.getName();
|
||||
}
|
||||
|
||||
public boolean isPinnable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public @Nullable JPopupMenu onTreePopupMenu(MainWindow mainWindow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ import java.awt.DisplayMode;
|
||||
import java.awt.Font;
|
||||
import java.awt.GraphicsDevice;
|
||||
import java.awt.GraphicsEnvironment;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.dnd.DnDConstants;
|
||||
import java.awt.dnd.DropTarget;
|
||||
import java.awt.event.ActionEvent;
|
||||
@@ -140,6 +139,7 @@ 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.tab.QuickTabsTree;
|
||||
import jadx.gui.ui.tab.TabbedPane;
|
||||
import jadx.gui.ui.tab.dnd.TabDndController;
|
||||
import jadx.gui.ui.treenodes.StartPageNode;
|
||||
@@ -203,6 +203,7 @@ public class MainWindow extends JFrame {
|
||||
private transient JSplitPane treeSplitPane;
|
||||
private transient JSplitPane rightSplitPane;
|
||||
private transient JSplitPane bottomSplitPane;
|
||||
private transient JSplitPane quickTabsAndCodeSplitPane;
|
||||
|
||||
private JTree tree;
|
||||
private DefaultTreeModel treeModel;
|
||||
@@ -228,6 +229,7 @@ public class MainWindow extends JFrame {
|
||||
private transient IssuesPanel issuesPanel;
|
||||
private transient @Nullable LogPanel logPanel;
|
||||
private transient @Nullable JDebuggerPanel debuggerPanel;
|
||||
private transient @Nullable QuickTabsTree quickTabsTree;
|
||||
|
||||
private final List<ILoadListener> loadListeners = new ArrayList<>();
|
||||
private final List<Consumer<JRoot>> treeUpdateListener = new ArrayList<>();
|
||||
@@ -888,27 +890,11 @@ public class MainWindow extends JFrame {
|
||||
|
||||
@Nullable
|
||||
private JNode getJNodeUnderMouse(MouseEvent mouseEvent) {
|
||||
TreePath path = tree.getClosestPathForLocation(mouseEvent.getX(), mouseEvent.getY());
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
// allow 'closest' path only at the right of the item row
|
||||
Rectangle pathBounds = tree.getPathBounds(path);
|
||||
if (pathBounds != null) {
|
||||
int y = mouseEvent.getY();
|
||||
if (y < pathBounds.y || y > (pathBounds.y + pathBounds.height)) {
|
||||
return null;
|
||||
}
|
||||
if (mouseEvent.getX() < pathBounds.x) {
|
||||
// exclude expand/collapse events
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Object obj = path.getLastPathComponent();
|
||||
if (obj instanceof JNode) {
|
||||
tree.setSelectionPath(path);
|
||||
return (JNode) obj;
|
||||
TreeNode treeNode = UiUtils.getTreeNodeUnderMouse(tree, mouseEvent);
|
||||
if (treeNode instanceof JNode) {
|
||||
return (JNode) treeNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -1061,6 +1047,17 @@ public class MainWindow extends JFrame {
|
||||
dockLog.setState(settings.isDockLogViewer());
|
||||
dockLog.addActionListener(event -> settings.setDockLogViewer(!settings.isDockLogViewer()));
|
||||
|
||||
JCheckBoxMenuItem dockQuickTabs = new JCheckBoxMenuItem(NLS.str("menu.dock_quick_tabs"));
|
||||
dockQuickTabs.setState(settings.isDockQuickTabs());
|
||||
dockQuickTabs.addActionListener(event -> {
|
||||
boolean visible = quickTabsTree == null;
|
||||
setQuickTabsVisibility(visible);
|
||||
settings.setDockQuickTabs(visible);
|
||||
});
|
||||
if (dockQuickTabs.getState()) {
|
||||
setQuickTabsVisibility(true);
|
||||
}
|
||||
|
||||
JadxGuiAction syncAction = new JadxGuiAction(ActionModel.SYNC, this::syncWithEditor);
|
||||
JadxGuiAction textSearchAction = new JadxGuiAction(ActionModel.TEXT_SEARCH, this::textSearch);
|
||||
JadxGuiAction clsSearchAction = new JadxGuiAction(ActionModel.CLASS_SEARCH,
|
||||
@@ -1124,6 +1121,7 @@ public class MainWindow extends JFrame {
|
||||
view.add(heapUsageBarMenuItem);
|
||||
view.add(alwaysSelectOpened);
|
||||
view.add(dockLog);
|
||||
view.add(dockQuickTabs);
|
||||
|
||||
JMenu nav = new JadxMenu(NLS.str("menu.navigation"), shortcutsController);
|
||||
nav.setMnemonic(KeyEvent.VK_N);
|
||||
@@ -1348,8 +1346,13 @@ public class MainWindow extends JFrame {
|
||||
tabbedPane.setMinimumSize(new Dimension(150, 150));
|
||||
new TabDndController(tabbedPane, settings);
|
||||
|
||||
quickTabsAndCodeSplitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
|
||||
quickTabsAndCodeSplitPane.setResizeWeight(0.15);
|
||||
quickTabsAndCodeSplitPane.setDividerSize(0);
|
||||
quickTabsAndCodeSplitPane.setRightComponent(tabbedPane);
|
||||
|
||||
rightSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
|
||||
rightSplitPane.setTopComponent(tabbedPane);
|
||||
rightSplitPane.setTopComponent(quickTabsAndCodeSplitPane);
|
||||
rightSplitPane.setResizeWeight(SPLIT_PANE_RESIZE_WEIGHT);
|
||||
|
||||
treeSplitPane.setRightComponent(rightSplitPane);
|
||||
@@ -1482,6 +1485,9 @@ public class MainWindow extends JFrame {
|
||||
if (logPanel != null) {
|
||||
logPanel.loadSettings();
|
||||
}
|
||||
if (quickTabsTree != null) {
|
||||
quickTabsTree.loadSettings();
|
||||
}
|
||||
|
||||
shortcutsController.loadSettings();
|
||||
}
|
||||
@@ -1654,6 +1660,25 @@ public class MainWindow extends JFrame {
|
||||
rightSplitPane.setBottomComponent(null);
|
||||
}
|
||||
|
||||
private void setQuickTabsVisibility(boolean visible) {
|
||||
if (visible) {
|
||||
if (quickTabsTree == null) {
|
||||
quickTabsTree = new QuickTabsTree(this);
|
||||
}
|
||||
|
||||
quickTabsAndCodeSplitPane.setLeftComponent(quickTabsTree);
|
||||
quickTabsAndCodeSplitPane.setDividerSize(5);
|
||||
} else {
|
||||
quickTabsAndCodeSplitPane.setLeftComponent(null);
|
||||
quickTabsAndCodeSplitPane.setDividerSize(0);
|
||||
|
||||
if (quickTabsTree != null) {
|
||||
quickTabsTree.dispose();
|
||||
quickTabsTree = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JMenu getPluginsMenu() {
|
||||
return pluginsMenu;
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ public class EditorViewState {
|
||||
private final Point viewPoint;
|
||||
private final String subPath;
|
||||
private boolean active;
|
||||
private boolean pinned;
|
||||
|
||||
public EditorViewState(JNode node, String subPath, int caretPos, Point viewPoint) {
|
||||
this.node = node;
|
||||
@@ -44,6 +45,14 @@ public class EditorViewState {
|
||||
this.active = active;
|
||||
}
|
||||
|
||||
public boolean isPinned() {
|
||||
return pinned;
|
||||
}
|
||||
|
||||
public void setPinned(boolean pinned) {
|
||||
this.pinned = pinned;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "EditorViewState{node=" + node
|
||||
|
||||
@@ -15,6 +15,7 @@ public abstract class ContentPanel extends JPanel {
|
||||
|
||||
protected TabbedPane tabbedPane;
|
||||
protected JNode node;
|
||||
private boolean pinned;
|
||||
|
||||
protected ContentPanel(TabbedPane panel, JNode jnode) {
|
||||
tabbedPane = panel;
|
||||
@@ -50,6 +51,18 @@ public abstract class ContentPanel extends JPanel {
|
||||
return tabbedPane.getMainWindow().getSettings();
|
||||
}
|
||||
|
||||
public boolean isPinned() {
|
||||
return pinned;
|
||||
}
|
||||
|
||||
public void setPinned(boolean pinned) {
|
||||
this.pinned = pinned;
|
||||
}
|
||||
|
||||
public boolean isPinnable() {
|
||||
return node.isPinnable();
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
tabbedPane = null;
|
||||
node = null;
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
package jadx.gui.ui.tab;
|
||||
|
||||
import jadx.gui.treemodel.JNode;
|
||||
|
||||
public interface ITabStatesListener {
|
||||
void onTabPinChange(JNode node, boolean pinned);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package jadx.gui.ui.tab;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
|
||||
import jadx.gui.ui.MainWindow;
|
||||
|
||||
abstract class QuickTabsBaseNode extends DefaultMutableTreeNode {
|
||||
JPopupMenu onTreePopupMenu(MainWindow mainWindow) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Icon getIcon() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package jadx.gui.ui.tab;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class QuickTabsChildNode extends QuickTabsBaseNode {
|
||||
private final JNode node;
|
||||
|
||||
public QuickTabsChildNode(JNode node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return node.toString();
|
||||
}
|
||||
|
||||
public JNode getJNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JPopupMenu onTreePopupMenu(MainWindow mainWindow) {
|
||||
JPopupMenu menu = node.onTreePopupMenu(mainWindow);
|
||||
|
||||
if (node.isPinnable()) {
|
||||
if (menu == null) {
|
||||
menu = new JPopupMenu();
|
||||
}
|
||||
|
||||
JMenuItem unpinAction = new JMenuItem(NLS.str("tabs.unpin"));
|
||||
unpinAction.addActionListener(e -> {
|
||||
TabComponent tabComponent = mainWindow.getTabbedPane().getTabComponentByNode(node);
|
||||
if (tabComponent != null) {
|
||||
tabComponent.togglePin();
|
||||
}
|
||||
});
|
||||
menu.add(unpinAction, 0);
|
||||
menu.add(new JPopupMenu.Separator(), 1);
|
||||
}
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
Icon getIcon() {
|
||||
return node.getIcon();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package jadx.gui.ui.tab;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
|
||||
abstract class QuickTabsParentNode extends QuickTabsBaseNode {
|
||||
private final TabbedPane tabbedPane;
|
||||
private final Map<JNode, QuickTabsChildNode> childrenMap = new HashMap<>();
|
||||
|
||||
protected QuickTabsParentNode(TabbedPane tabbedPane) {
|
||||
super();
|
||||
|
||||
this.tabbedPane = tabbedPane;
|
||||
}
|
||||
|
||||
public void addJNode(JNode node) {
|
||||
if (childrenMap.containsKey(node)) {
|
||||
return;
|
||||
}
|
||||
QuickTabsChildNode childNode = new QuickTabsChildNode(node);
|
||||
childrenMap.put(node, childNode);
|
||||
add(childNode);
|
||||
}
|
||||
|
||||
public void removeJNode(JNode node) {
|
||||
QuickTabsChildNode childNode = childrenMap.remove(node);
|
||||
if (childNode == null) {
|
||||
return;
|
||||
}
|
||||
remove(childNode);
|
||||
}
|
||||
|
||||
public QuickTabsChildNode getQuickTabsNode(JNode node) {
|
||||
return childrenMap.get(node);
|
||||
}
|
||||
|
||||
public TabbedPane getTabbedPane() {
|
||||
return tabbedPane;
|
||||
}
|
||||
|
||||
abstract String getTitle();
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
JPopupMenu onTreePopupMenu(MainWindow mainWindow) {
|
||||
return super.onTreePopupMenu(mainWindow);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package jadx.gui.ui.tab;
|
||||
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JMenuItem;
|
||||
import javax.swing.JPopupMenu;
|
||||
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.Icons;
|
||||
import jadx.gui.utils.NLS;
|
||||
|
||||
public class QuickTabsPinParentNode extends QuickTabsParentNode {
|
||||
protected QuickTabsPinParentNode(TabbedPane tabbedPane) {
|
||||
super(tabbedPane);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return NLS.str("tree.pinned_tabs");
|
||||
}
|
||||
|
||||
@Override
|
||||
Icon getIcon() {
|
||||
return Icons.PIN;
|
||||
}
|
||||
|
||||
@Override
|
||||
JPopupMenu onTreePopupMenu(MainWindow mainWindow) {
|
||||
if (getChildCount() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
JPopupMenu menu = new JPopupMenu();
|
||||
JMenuItem unpinAll = new JMenuItem(NLS.str("tabs.unpin_all"));
|
||||
unpinAll.addActionListener(e -> getTabbedPane().unpinAll());
|
||||
menu.add(unpinAll);
|
||||
|
||||
return menu;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,157 @@
|
||||
package jadx.gui.ui.tab;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Font;
|
||||
import java.awt.event.KeyAdapter;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
|
||||
import javax.swing.JPopupMenu;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.event.TreeSelectionEvent;
|
||||
import javax.swing.event.TreeSelectionListener;
|
||||
import javax.swing.tree.DefaultMutableTreeNode;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.DefaultTreeModel;
|
||||
import javax.swing.tree.TreeNode;
|
||||
|
||||
import jadx.gui.treemodel.JNode;
|
||||
import jadx.gui.ui.MainWindow;
|
||||
import jadx.gui.utils.UiUtils;
|
||||
|
||||
public class QuickTabsTree extends JTree implements ITabStatesListener, TreeSelectionListener {
|
||||
private final MainWindow mainWindow;
|
||||
private final DefaultTreeModel treeModel;
|
||||
|
||||
private final QuickTabsParentNode pinParentNode;
|
||||
|
||||
public QuickTabsTree(MainWindow mainWindow) {
|
||||
this.mainWindow = mainWindow;
|
||||
|
||||
mainWindow.getTabbedPane().addTabStateListener(this);
|
||||
|
||||
Root root = new Root();
|
||||
pinParentNode = new QuickTabsPinParentNode(mainWindow.getTabbedPane());
|
||||
fillPinParentNode();
|
||||
root.add(pinParentNode);
|
||||
|
||||
treeModel = new DefaultTreeModel(root);
|
||||
setModel(treeModel);
|
||||
setCellRenderer(new CellRenderer());
|
||||
setRootVisible(false);
|
||||
setShowsRootHandles(true);
|
||||
|
||||
addMouseListener(new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
TreeNode pressedNode = UiUtils.getTreeNodeUnderMouse(QuickTabsTree.this, e);
|
||||
if (SwingUtilities.isLeftMouseButton(e)) {
|
||||
if (nodeClickAction(pressedNode)) {
|
||||
setFocusable(true);
|
||||
requestFocus();
|
||||
}
|
||||
}
|
||||
if (SwingUtilities.isRightMouseButton(e)) {
|
||||
triggerRightClickAction(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
addKeyListener(new KeyAdapter() {
|
||||
@Override
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if (e.getKeyCode() == KeyEvent.VK_ENTER) {
|
||||
nodeClickAction(getLastSelectedPathComponent());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
private void triggerRightClickAction(MouseEvent e) {
|
||||
TreeNode treeNode = UiUtils.getTreeNodeUnderMouse(this, e);
|
||||
if (!(treeNode instanceof QuickTabsBaseNode)) {
|
||||
return;
|
||||
}
|
||||
|
||||
QuickTabsBaseNode quickTabsNode = (QuickTabsBaseNode) treeNode;
|
||||
JPopupMenu menu = quickTabsNode.onTreePopupMenu(mainWindow);
|
||||
if (menu != null) {
|
||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean nodeClickAction(Object pressedNode) {
|
||||
if (pressedNode == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (pressedNode instanceof QuickTabsChildNode) {
|
||||
QuickTabsChildNode childNode = (QuickTabsChildNode) pressedNode;
|
||||
return mainWindow.getTabbedPane().showNode(childNode.getJNode());
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void fillPinParentNode() {
|
||||
mainWindow.getTabbedPane().getPinnedTabs().forEach((contentPanel) -> pinParentNode.addJNode(contentPanel.getNode()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void valueChanged(TreeSelectionEvent event) {
|
||||
DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode) getLastSelectedPathComponent();
|
||||
if (selectedNode != null) {
|
||||
if (selectedNode instanceof QuickTabsChildNode) {
|
||||
QuickTabsChildNode childNode = (QuickTabsChildNode) selectedNode;
|
||||
JNode jNode = childNode.getJNode();
|
||||
TabbedPane tabbedPane = mainWindow.getTabbedPane();
|
||||
tabbedPane.selectTab(tabbedPane.getTabByNode(jNode));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabPinChange(JNode node, boolean pinned) {
|
||||
if (pinned) {
|
||||
pinParentNode.addJNode(node);
|
||||
treeModel.nodesWereInserted(pinParentNode, new int[] { pinParentNode.getChildCount() - 1 });
|
||||
} else {
|
||||
QuickTabsChildNode child = pinParentNode.getQuickTabsNode(node);
|
||||
int removedIndex = pinParentNode.getIndex(child);
|
||||
pinParentNode.removeJNode(node);
|
||||
treeModel.nodesWereRemoved(pinParentNode, new int[] { removedIndex }, new Object[] { child });
|
||||
}
|
||||
}
|
||||
|
||||
public void loadSettings() {
|
||||
Font font = mainWindow.getSettings().getFont();
|
||||
Font largerFont = font.deriveFont(font.getSize() + 2.f);
|
||||
|
||||
setFont(largerFont);
|
||||
}
|
||||
|
||||
public void dispose() {
|
||||
mainWindow.getTabbedPane().removeTabStateListener(this);
|
||||
}
|
||||
|
||||
private class Root extends DefaultMutableTreeNode {
|
||||
|
||||
}
|
||||
|
||||
private class CellRenderer extends DefaultTreeCellRenderer {
|
||||
@Override
|
||||
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, boolean leaf, int row,
|
||||
boolean hasFocus) {
|
||||
Component c = super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
|
||||
if (value instanceof QuickTabsBaseNode) {
|
||||
QuickTabsBaseNode quickTabsNode = (QuickTabsBaseNode) value;
|
||||
setIcon(quickTabsNode.getIcon());
|
||||
}
|
||||
return c;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,6 +38,8 @@ public class TabComponent extends JPanel {
|
||||
private final ContentPanel contentPanel;
|
||||
|
||||
private JLabel label;
|
||||
private JButton pinBtn;
|
||||
private JButton closeBtn;
|
||||
|
||||
public TabComponent(TabbedPane tabbedPane, ContentPanel contentPanel) {
|
||||
this.tabbedPane = tabbedPane;
|
||||
@@ -74,7 +76,18 @@ public class TabComponent extends JPanel {
|
||||
((JEditableNode) node).addChangeListener(c -> label.setText(buildTabTitle(node)));
|
||||
}
|
||||
|
||||
final JButton closeBtn = new JButton();
|
||||
pinBtn = new JButton();
|
||||
pinBtn.setIcon(Icons.PIN);
|
||||
pinBtn.setRolloverIcon(Icons.PIN_HOVERED);
|
||||
pinBtn.setRolloverEnabled(true);
|
||||
pinBtn.setOpaque(false);
|
||||
pinBtn.setUI(new BasicButtonUI());
|
||||
pinBtn.setContentAreaFilled(false);
|
||||
pinBtn.setBorder(null);
|
||||
pinBtn.setBorderPainted(false);
|
||||
pinBtn.addActionListener(e -> togglePin());
|
||||
|
||||
closeBtn = new JButton();
|
||||
closeBtn.setIcon(Icons.CLOSE_INACTIVE);
|
||||
closeBtn.setRolloverIcon(Icons.CLOSE);
|
||||
closeBtn.setRolloverEnabled(true);
|
||||
@@ -84,13 +97,13 @@ public class TabComponent extends JPanel {
|
||||
closeBtn.setFocusable(false);
|
||||
closeBtn.setBorder(null);
|
||||
closeBtn.setBorderPainted(false);
|
||||
closeBtn.addActionListener(e -> tabbedPane.closeCodePanel(contentPanel));
|
||||
closeBtn.addActionListener(e -> tabbedPane.closeCodePanel(contentPanel, true));
|
||||
|
||||
MouseAdapter clickAdapter = new MouseAdapter() {
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
if (SwingUtilities.isMiddleMouseButton(e)) {
|
||||
tabbedPane.closeCodePanel(contentPanel);
|
||||
tabbedPane.closeCodePanel(contentPanel, true);
|
||||
} else if (SwingUtilities.isRightMouseButton(e)) {
|
||||
JPopupMenu menu = createTabPopupMenu(contentPanel);
|
||||
menu.show(e.getComponent(), e.getX(), e.getY());
|
||||
@@ -105,10 +118,38 @@ public class TabComponent extends JPanel {
|
||||
addListenerForDnd();
|
||||
|
||||
add(label);
|
||||
add(closeBtn);
|
||||
updateCloseOrPinButton();
|
||||
setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
public void updateCloseOrPinButton() {
|
||||
if (contentPanel.isPinned()) {
|
||||
if (closeBtn.isShowing()) {
|
||||
remove(closeBtn);
|
||||
}
|
||||
if (!pinBtn.isShowing()) {
|
||||
add(pinBtn);
|
||||
}
|
||||
}
|
||||
if (!contentPanel.isPinned()) {
|
||||
if (pinBtn.isShowing()) {
|
||||
remove(pinBtn);
|
||||
}
|
||||
if (!closeBtn.isShowing()) {
|
||||
add(closeBtn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void togglePin() {
|
||||
contentPanel.setPinned(!contentPanel.isPinned());
|
||||
updateCloseOrPinButton();
|
||||
if (contentPanel.isPinned()) {
|
||||
tabbedPane.advanceTab(this);
|
||||
}
|
||||
tabbedPane.notifyTabStateChange(this, true);
|
||||
}
|
||||
|
||||
private void addListenerForDnd() {
|
||||
if (tabbedPane.getDnd() == null) {
|
||||
return;
|
||||
@@ -150,8 +191,22 @@ public class TabComponent extends JPanel {
|
||||
menu.addSeparator();
|
||||
}
|
||||
|
||||
if (contentPanel.isPinnable()) {
|
||||
String pinTitle = contentPanel.isPinned() ? NLS.str("tabs.unpin") : NLS.str("tabs.pin");
|
||||
JMenuItem pinTab = new JMenuItem(pinTitle);
|
||||
pinTab.addActionListener(e -> togglePin());
|
||||
menu.add(pinTab);
|
||||
|
||||
JMenuItem unpinAll = new JMenuItem(NLS.str("tabs.unpin_all"));
|
||||
unpinAll.addActionListener(e -> tabbedPane.unpinAll());
|
||||
menu.add(unpinAll);
|
||||
}
|
||||
|
||||
JMenuItem closeTab = new JMenuItem(NLS.str("tabs.close"));
|
||||
closeTab.addActionListener(e -> tabbedPane.closeCodePanel(contentPanel));
|
||||
closeTab.addActionListener(e -> tabbedPane.closeCodePanel(contentPanel, true));
|
||||
if (contentPanel.isPinned()) {
|
||||
closeTab.setEnabled(false);
|
||||
}
|
||||
menu.add(closeTab);
|
||||
|
||||
List<ContentPanel> tabs = tabbedPane.getTabs();
|
||||
@@ -160,14 +215,14 @@ public class TabComponent extends JPanel {
|
||||
closeOther.addActionListener(e -> {
|
||||
for (ContentPanel panel : tabs) {
|
||||
if (panel != contentPanel) {
|
||||
tabbedPane.closeCodePanel(panel);
|
||||
tabbedPane.closeCodePanel(panel, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
menu.add(closeOther);
|
||||
|
||||
JMenuItem closeAll = new JMenuItem(NLS.str("tabs.closeAll"));
|
||||
closeAll.addActionListener(e -> tabbedPane.closeAllTabs());
|
||||
closeAll.addActionListener(e -> tabbedPane.closeAllTabs(true));
|
||||
menu.add(closeAll);
|
||||
|
||||
if (contentPanel != ListUtils.last(tabs)) {
|
||||
@@ -180,7 +235,7 @@ public class TabComponent extends JPanel {
|
||||
pastCurrentPanel = true;
|
||||
}
|
||||
} else {
|
||||
tabbedPane.closeCodePanel(panel);
|
||||
tabbedPane.closeCodePanel(panel, true);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -212,4 +267,8 @@ public class TabComponent extends JPanel {
|
||||
}
|
||||
return node.getName();
|
||||
}
|
||||
|
||||
public ContentPanel getContentPanel() {
|
||||
return contentPanel;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,8 @@ public class TabbedPane extends JTabbedPane {
|
||||
|
||||
private final transient MainWindow mainWindow;
|
||||
private final transient Map<JNode, ContentPanel> tabsMap = new HashMap<>();
|
||||
|
||||
private final ArrayList<ITabStatesListener> tabStatesListeners = new ArrayList<>();
|
||||
private final transient JumpManager jumps = new JumpManager();
|
||||
|
||||
private transient ContentPanel curTab;
|
||||
@@ -343,6 +345,7 @@ public class TabbedPane extends JTabbedPane {
|
||||
viewState = new EditorViewState(panel.getNode(), "", 0, EditorViewState.ZERO);
|
||||
}
|
||||
viewState.setActive(panel == selected);
|
||||
viewState.setPinned(panel.isPinned());
|
||||
states.add(viewState);
|
||||
}
|
||||
return states;
|
||||
@@ -356,6 +359,17 @@ public class TabbedPane extends JTabbedPane {
|
||||
if (viewState.isActive()) {
|
||||
setSelectedComponent(contentPanel);
|
||||
}
|
||||
if (contentPanel != null) {
|
||||
boolean pinned = viewState.isPinned();
|
||||
contentPanel.setPinned(pinned);
|
||||
Component component = getTabComponentAt(indexOfComponent(contentPanel));
|
||||
if (component instanceof TabComponent) {
|
||||
TabComponent tabComponent = (TabComponent) component;
|
||||
JNode node = contentPanel.getNode();
|
||||
tabComponent.updateCloseOrPinButton();
|
||||
tabStatesListeners.forEach(l -> l.onTabPinChange(node, pinned));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void navBack() {
|
||||
@@ -386,11 +400,42 @@ public class TabbedPane extends JTabbedPane {
|
||||
}
|
||||
|
||||
public void closeCodePanel(ContentPanel contentPanel) {
|
||||
closeCodePanel(contentPanel, false);
|
||||
}
|
||||
|
||||
public void closeCodePanel(ContentPanel contentPanel, boolean considerPins) {
|
||||
if (considerPins && contentPanel.isPinned()) {
|
||||
return;
|
||||
}
|
||||
|
||||
tabsMap.remove(contentPanel.getNode());
|
||||
remove(contentPanel);
|
||||
contentPanel.dispose();
|
||||
}
|
||||
|
||||
public void advanceTab(TabComponent tabComponent) {
|
||||
remove(tabComponent.getContentPanel());
|
||||
add(tabComponent.getContentPanel(), 0);
|
||||
setTabComponentAt(0, tabComponent);
|
||||
selectTab(tabComponent.getContentPanel());
|
||||
}
|
||||
|
||||
public void notifyTabStateChange(TabComponent tabComponent, boolean pinChange) {
|
||||
if (pinChange) {
|
||||
JNode node = tabComponent.getContentPanel().getNode();
|
||||
boolean pinned = tabComponent.getContentPanel().isPinned();
|
||||
tabStatesListeners.forEach(l -> l.onTabPinChange(node, pinned));
|
||||
}
|
||||
}
|
||||
|
||||
public void addTabStateListener(ITabStatesListener listener) {
|
||||
tabStatesListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeTabStateListener(ITabStatesListener listener) {
|
||||
tabStatesListeners.remove(listener);
|
||||
}
|
||||
|
||||
public List<ContentPanel> getTabs() {
|
||||
List<ContentPanel> list = new ArrayList<>(getTabCount());
|
||||
for (int i = 0; i < getTabCount(); i++) {
|
||||
@@ -399,10 +444,41 @@ public class TabbedPane extends JTabbedPane {
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<ContentPanel> getPinnedTabs() {
|
||||
List<ContentPanel> list = new ArrayList<>(getTabCount());
|
||||
for (int i = 0; i < getTabCount(); i++) {
|
||||
ContentPanel contentPanel = (ContentPanel) getComponentAt(i);
|
||||
if (contentPanel.isPinned()) {
|
||||
list.add(contentPanel);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<TabComponent> getPinnedTabComponents() {
|
||||
List<TabComponent> list = new ArrayList<>(getTabCount());
|
||||
for (int i = 0; i < getTabCount(); i++) {
|
||||
ContentPanel contentPanel = (ContentPanel) getComponentAt(i);
|
||||
if (contentPanel.isPinned()) {
|
||||
list.add((TabComponent) getTabComponentAt(i));
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public @Nullable ContentPanel getTabByNode(JNode node) {
|
||||
return tabsMap.get(node);
|
||||
}
|
||||
|
||||
public @Nullable TabComponent getTabComponentByNode(JNode node) {
|
||||
Component component = getTabComponentAt(indexOfComponent(getTabByNode(node)));
|
||||
if (!(component instanceof TabComponent)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (TabComponent) component;
|
||||
}
|
||||
|
||||
private @Nullable ContentPanel getContentPanel(JNode node) {
|
||||
ContentPanel panel = getTabByNode(node);
|
||||
if (panel != null) {
|
||||
@@ -417,6 +493,10 @@ public class TabbedPane extends JTabbedPane {
|
||||
return newPanel;
|
||||
}
|
||||
|
||||
public void unpinAll() {
|
||||
getPinnedTabComponents().forEach(TabComponent::togglePin);
|
||||
}
|
||||
|
||||
public void refresh(JNode node) {
|
||||
ContentPanel panel = getTabByNode(node);
|
||||
if (panel != null) {
|
||||
@@ -464,8 +544,12 @@ public class TabbedPane extends JTabbedPane {
|
||||
}
|
||||
|
||||
public void closeAllTabs() {
|
||||
closeAllTabs(false);
|
||||
}
|
||||
|
||||
public void closeAllTabs(boolean considerPins) {
|
||||
for (ContentPanel panel : getTabs()) {
|
||||
closeCodePanel(panel);
|
||||
closeCodePanel(panel, considerPins);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,4 +32,9 @@ public class StartPageNode extends JNode {
|
||||
public JClass getJParent() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPinnable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,11 @@ public class Icons {
|
||||
|
||||
public static final ImageIcon SAVE_ALL = UiUtils.openSvgIcon("ui/menu-saveall");
|
||||
|
||||
public static final ImageIcon PIN = UiUtils.openSvgIcon("nodes/pin");
|
||||
public static final ImageIcon PIN_DARK = UiUtils.openSvgIcon("nodes/pin_dark");
|
||||
public static final ImageIcon PIN_HOVERED = UiUtils.openSvgIcon("nodes/pinHovered");
|
||||
public static final ImageIcon PIN_HOVERED_DARK = UiUtils.openSvgIcon("nodes/pinHovered_dark");
|
||||
|
||||
public static final ImageIcon STATIC = openSvgIcon("nodes/staticMark");
|
||||
public static final ImageIcon FINAL = openSvgIcon("nodes/finalMark");
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import java.awt.Component;
|
||||
import java.awt.Image;
|
||||
import java.awt.MouseInfo;
|
||||
import java.awt.Point;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Window;
|
||||
import java.awt.datatransfer.Clipboard;
|
||||
@@ -12,6 +13,7 @@ import java.awt.datatransfer.Transferable;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -24,9 +26,12 @@ import javax.swing.Icon;
|
||||
import javax.swing.ImageIcon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.JTree;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.RootPaneContainer;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.tree.TreeNode;
|
||||
import javax.swing.tree.TreePath;
|
||||
|
||||
import org.intellij.lang.annotations.MagicConstant;
|
||||
import org.jetbrains.annotations.TestOnly;
|
||||
@@ -296,6 +301,31 @@ public class UiUtils {
|
||||
return pos;
|
||||
}
|
||||
|
||||
public static TreeNode getTreeNodeUnderMouse(JTree tree, MouseEvent mouseEvent) {
|
||||
TreePath path = tree.getClosestPathForLocation(mouseEvent.getX(), mouseEvent.getY());
|
||||
if (path == null) {
|
||||
return null;
|
||||
}
|
||||
// allow 'closest' path only at the right of the item row
|
||||
Rectangle pathBounds = tree.getPathBounds(path);
|
||||
if (pathBounds != null) {
|
||||
int y = mouseEvent.getY();
|
||||
if (y < pathBounds.y || y > (pathBounds.y + pathBounds.height)) {
|
||||
return null;
|
||||
}
|
||||
if (mouseEvent.getX() < pathBounds.x) {
|
||||
// exclude expand/collapse events
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Object obj = path.getLastPathComponent();
|
||||
if (obj instanceof TreeNode) {
|
||||
tree.setSelectionPath(path);
|
||||
return (TreeNode) obj;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getEnvVar(String varName, String defValue) {
|
||||
String envVal = System.getenv(varName);
|
||||
if (envVal == null) {
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=Codepaket erweitern
|
||||
menu.heapUsageBar=Speicherverbrauchsleiste anzeigen
|
||||
menu.alwaysSelectOpened=Immer geöffnete Datei/Klasse auswählen
|
||||
#menu.dock_log=Dock log viewer
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=Navigation
|
||||
menu.text_search=Textsuche
|
||||
menu.class_search=Klassen-Suche
|
||||
@@ -58,6 +59,7 @@ file.exit=Beenden
|
||||
tree.sources_title=Quelltexte
|
||||
tree.resources_title=Ressourcen
|
||||
tree.loading=Laden…
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=Laden
|
||||
progress.save_mappings=Zuordnungen exportieren
|
||||
@@ -79,6 +81,9 @@ search.find=Suchen
|
||||
tabs.copy_class_name=Klassennamen kopieren
|
||||
tabs.close=Schließen
|
||||
tabs.closeOthers=Andere schließen
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=Alles schließen
|
||||
tabs.closeAllRight=Schließe alles rechts
|
||||
tabs.code=Code
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=Show flatten packages
|
||||
menu.heapUsageBar=Show memory usage bar
|
||||
menu.alwaysSelectOpened=Always Select Opened File/Class
|
||||
menu.dock_log=Dock log viewer
|
||||
menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=Navigation
|
||||
menu.text_search=Text search
|
||||
menu.class_search=Class search
|
||||
@@ -58,6 +59,7 @@ tree.input_scripts=Scripts
|
||||
tree.sources_title=Source code
|
||||
tree.resources_title=Resources
|
||||
tree.loading=Loading...
|
||||
tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=Loading
|
||||
progress.save_mappings=Saving mappings
|
||||
@@ -79,6 +81,9 @@ search.results=%s%d results
|
||||
tabs.copy_class_name=Copy Name
|
||||
tabs.close=Close
|
||||
tabs.closeOthers=Close Others
|
||||
tabs.unpin=Unpin
|
||||
tabs.unpin_all=Unpin All
|
||||
tabs.pin=Pin
|
||||
tabs.closeAll=Close All
|
||||
tabs.closeAllRight=Close All Right
|
||||
tabs.code=Code
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=Mostrar paquetes en vista plana
|
||||
#menu.heapUsageBar=
|
||||
#menu.alwaysSelectOpened=Always Select Opened File/Class
|
||||
#menu.dock_log=Dock log viewer
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=Navegación
|
||||
menu.text_search=Buscar texto
|
||||
menu.class_search=Buscar clase
|
||||
@@ -58,6 +59,7 @@ file.exit=Salir
|
||||
tree.sources_title=Código fuente
|
||||
tree.resources_title=Recursos
|
||||
tree.loading=Cargando...
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=Cargando
|
||||
#progress.save_mappings=
|
||||
@@ -79,6 +81,9 @@ search.find=Buscar
|
||||
tabs.copy_class_name=Copy Name
|
||||
tabs.close=Cerrar
|
||||
tabs.closeOthers=Cerrar otros
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=Cerrar todo
|
||||
tabs.closeAllRight=Cierra todo a la derecha
|
||||
#tabs.code=
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=Tampilkan paket yang diratakan
|
||||
menu.heapUsageBar=Tampilkan penggunaan memori
|
||||
menu.alwaysSelectOpened=Selalu Pilih Berkas/Kelas yang Terbuka
|
||||
menu.dock_log=Kaitkan pemantau log
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=Navigasi
|
||||
menu.text_search=Pencarian Teks
|
||||
menu.class_search=Pencarian Kelas
|
||||
@@ -58,6 +59,7 @@ tree.input_scripts=Skrip
|
||||
tree.sources_title=Kode Sumber
|
||||
tree.resources_title=Sumber Daya
|
||||
tree.loading=Memuat...
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=Memuat
|
||||
progress.save_mappings=Menyimpan pemetaan
|
||||
@@ -79,6 +81,9 @@ search.results=%s%d hasil
|
||||
tabs.copy_class_name=Salin Nama
|
||||
tabs.close=Tutup
|
||||
tabs.closeOthers=Tutup yang Lain
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=Tutup Semua
|
||||
tabs.closeAllRight=Tutup Semua yang Kanan
|
||||
tabs.code=Kode
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=플랫 패키지 표시
|
||||
menu.heapUsageBar=메모리 사용량 표시
|
||||
menu.alwaysSelectOpened=항상 열린 파일/클래스 선택
|
||||
#menu.dock_log=Dock log viewer
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=네비게이션
|
||||
menu.text_search=텍스트 검색
|
||||
menu.class_search=클래스 검색
|
||||
@@ -58,6 +59,7 @@ start_page.recent=최근 프로젝트
|
||||
tree.sources_title=소스코드
|
||||
tree.resources_title=리소스
|
||||
tree.loading=로딩중...
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=로딩중
|
||||
progress.save_mappings=매핑 내보내는 중
|
||||
@@ -79,6 +81,9 @@ search.find=찾기
|
||||
tabs.copy_class_name=이름 복사
|
||||
tabs.close=닫기
|
||||
tabs.closeOthers=이 탭을 제외하고 닫기
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=모두 닫기
|
||||
tabs.closeAllRight=오른쪽의 모든 것을 닫으십시오
|
||||
tabs.code=코드
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=Mostrar pacotes achatados
|
||||
menu.heapUsageBar=Mostrar uso de memória
|
||||
menu.alwaysSelectOpened=Sempre selecionar arquivo/classe aberta
|
||||
#menu.dock_log=Dock log viewer
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=Navegação
|
||||
menu.text_search=Buscar por texto
|
||||
menu.class_search=Buscar por classe
|
||||
@@ -58,6 +59,7 @@ start_page.recent=Projetos recentes
|
||||
tree.sources_title=Código fonte
|
||||
tree.resources_title=Recursos
|
||||
tree.loading=Carregando...
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=Carregando
|
||||
#progress.save_mappings=Saving mappings
|
||||
@@ -79,6 +81,9 @@ search.find=Encontrar
|
||||
tabs.copy_class_name=Copiar nome
|
||||
tabs.close=Fechar
|
||||
tabs.closeOthers=Fechar outros
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=Fechar todos
|
||||
tabs.closeAllRight=Feche tudo à direita
|
||||
tabs.code=Código
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=Плоская структура пакетов
|
||||
menu.heapUsageBar=Использование ОЗУ
|
||||
menu.alwaysSelectOpened=Выбирать открытый файл/класс
|
||||
menu.dock_log=Просмотр логов в панели
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=Навигация
|
||||
menu.text_search=Поиск строк
|
||||
menu.class_search=Поиск классов
|
||||
@@ -58,6 +59,7 @@ tree.input_scripts=Скрипты
|
||||
tree.sources_title=Исходный код
|
||||
tree.resources_title=Ресурсы
|
||||
tree.loading=Загрузка...
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=Загрузка
|
||||
progress.save_mappings=Сохранить маппинги
|
||||
@@ -79,6 +81,9 @@ search.results=%s%d результатов
|
||||
tabs.copy_class_name=Копировать имя
|
||||
tabs.close=Закрыть
|
||||
tabs.closeOthers=Закрыть другие
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=Закрыть все
|
||||
tabs.closeAllRight=Закройте все справа
|
||||
tabs.code=Код
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=展开显示代码包
|
||||
menu.heapUsageBar=显示内存使用栏
|
||||
menu.alwaysSelectOpened=始终选中打开的文件/类
|
||||
menu.dock_log=停靠日志查看器
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=导航
|
||||
menu.text_search=文本搜索
|
||||
menu.class_search=类名搜索
|
||||
@@ -58,6 +59,7 @@ tree.input_scripts=脚本
|
||||
tree.sources_title=源代码
|
||||
tree.resources_title=资源文件
|
||||
tree.loading=加载中…
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=正在加载
|
||||
progress.save_mappings=导出映射
|
||||
@@ -79,6 +81,9 @@ search.results=%s%d 个结果
|
||||
tabs.copy_class_name=复制名称
|
||||
tabs.close=关闭
|
||||
tabs.closeOthers=关闭其他
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=关闭全部
|
||||
tabs.closeAllRight=关闭右边的所有
|
||||
tabs.code=代码
|
||||
|
||||
@@ -10,6 +10,7 @@ menu.flatten=展開顯示套件
|
||||
menu.heapUsageBar=顯示記憶體使用率條
|
||||
menu.alwaysSelectOpened=總是選擇已開啟的檔案/類別
|
||||
menu.dock_log=固定記錄檔檢視器
|
||||
#menu.dock_quick_tabs=Dock quick tabs
|
||||
menu.navigation=瀏覽
|
||||
menu.text_search=文字搜尋
|
||||
menu.class_search=類別搜尋
|
||||
@@ -58,6 +59,7 @@ tree.input_scripts=腳本
|
||||
tree.sources_title=原始碼
|
||||
tree.resources_title=資源
|
||||
tree.loading=載入中...
|
||||
#tree.pinned_tabs=Pinned Tabs
|
||||
|
||||
progress.load=載入中
|
||||
progress.save_mappings=正在匯出對應
|
||||
@@ -79,6 +81,9 @@ search.results=%s%d 個結果
|
||||
tabs.copy_class_name=複製名稱
|
||||
tabs.close=關閉
|
||||
tabs.closeOthers=關閉其他
|
||||
#tabs.unpin=Unpin
|
||||
#tabs.unpin_all=Unpin All
|
||||
#tabs.pin=Pin
|
||||
tabs.closeAll=關閉全部
|
||||
tabs.closeAllRight=關閉右邊的所有
|
||||
tabs.code=程式碼
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
<!-- Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.48057 5.70711L6.26727 7.20016C6.19763 7.68767 5.90122 8.07205 5.53634 8.29289C4.78518 8.74751 4.39847 9.41436 4.19857 10H11.8015C11.6016 9.41434 11.2149 8.74746 10.4637 8.29284C10.0988 8.07201 9.80236 7.68762 9.73272 7.20009L9.51943 5.70711C9.39072 4.80611 10.0899 4 11 4V3L5 3V4C5.91014 4 6.60928 4.80611 6.48057 5.70711ZM5.27732 7.05873C5.25463 7.2176 5.15585 7.35428 5.01856 7.43737C3.84968 8.14481 3.35768 9.22759 3.15058 10.0138C3.0099 10.5478 3.44776 11 4.00005 11H12C12.5523 11 12.9902 10.5478 12.8495 10.0138C12.6424 9.22757 12.1504 8.14475 10.9814 7.43732C10.8442 7.35423 10.7454 7.21754 10.7227 7.05867L10.5094 5.56569C10.4667 5.26712 10.6984 5 11 5C11.5523 5 12 4.55228 12 4V3C12 2.44772 11.5523 2 11 2H5C4.44772 2 4 2.44772 4 3V4C4 4.55228 4.44772 5 5 5C5.3016 5 5.53327 5.26712 5.49062 5.56569L5.27732 7.05873Z" fill="#6C707E"/>
|
||||
<path d="M7.5 11H8.5V14.5C8.5 14.7761 8.27614 15 8 15V15C7.72386 15 7.5 14.7761 7.5 14.5V11Z" fill="#6C707E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
@@ -0,0 +1,6 @@
|
||||
<!-- Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.48057 5.70711L6.26727 7.20016C6.19763 7.68767 5.90122 8.07205 5.53634 8.29289C4.78518 8.74751 4.39847 9.41436 4.19857 10H11.8015C11.6016 9.41434 11.2149 8.74746 10.4637 8.29284C10.0988 8.07201 9.80236 7.68762 9.73272 7.20009L9.51943 5.70711C9.39072 4.80611 10.0899 4 11 4V3L5 3V4C5.91014 4 6.60928 4.80611 6.48057 5.70711ZM5.27732 7.05873C5.25463 7.2176 5.15585 7.35428 5.01856 7.43737C3.84968 8.14481 3.35768 9.22759 3.15058 10.0138C3.0099 10.5478 3.44776 11 4.00005 11H12C12.5523 11 12.9902 10.5478 12.8495 10.0138C12.6424 9.22757 12.1504 8.14475 10.9814 7.43732C10.8442 7.35423 10.7454 7.21754 10.7227 7.05867L10.5094 5.56569C10.4667 5.26712 10.6984 5 11 5C11.5523 5 12 4.55228 12 4V3C12 2.44772 11.5523 2 11 2H5C4.44772 2 4 2.44772 4 3V4C4 4.55228 4.44772 5 5 5C5.3016 5 5.53327 5.26712 5.49062 5.56569L5.27732 7.05873Z" fill="#6C707E"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.48073 5.70711L6.26744 7.20016C6.19779 7.68767 5.90138 8.07205 5.5365 8.29289C4.78534 8.74751 4.39863 9.41436 4.19873 10H11.8017C11.6018 9.41434 11.2151 8.74746 10.4639 8.29284C10.099 8.07201 9.80253 7.68762 9.73288 7.20009L9.5196 5.70711C9.39088 4.80611 10.09 4 11.0002 4V3L5.00016 3V4C5.91031 4 6.60944 4.80611 6.48073 5.70711Z" fill="#EBECF0"/>
|
||||
<path d="M7.5 11H8.5V14.5C8.5 14.7761 8.27614 15 8 15V15C7.72386 15 7.5 14.7761 7.5 14.5V11Z" fill="#6C707E"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,6 @@
|
||||
<!-- Copyright 2000-2023 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.48057 5.70711L6.26727 7.20016C6.19763 7.68767 5.90122 8.07205 5.53634 8.29289C4.78518 8.74751 4.39847 9.41436 4.19857 10H11.8015C11.6016 9.41434 11.2149 8.74746 10.4637 8.29284C10.0988 8.07201 9.80236 7.68762 9.73272 7.20009L9.51943 5.70711C9.39072 4.80611 10.0899 4 11 4V3L5 3V4C5.91014 4 6.60928 4.80611 6.48057 5.70711ZM5.27732 7.05873C5.25463 7.2176 5.15585 7.35428 5.01856 7.43737C3.84968 8.14481 3.35768 9.22759 3.15058 10.0138C3.0099 10.5478 3.44776 11 4.00005 11H12C12.5523 11 12.9902 10.5478 12.8495 10.0138C12.6424 9.22757 12.1504 8.14475 10.9814 7.43732C10.8442 7.35423 10.7454 7.21754 10.7227 7.05867L10.5094 5.56569C10.4667 5.26712 10.6984 5 11 5C11.5523 5 12 4.55228 12 4V3C12 2.44772 11.5523 2 11 2H5C4.44772 2 4 2.44772 4 3V4C4 4.55228 4.44772 5 5 5C5.3016 5 5.53327 5.26712 5.49062 5.56569L5.27732 7.05873Z" fill="#CED0D6"/>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.48073 5.70711L6.26744 7.20016C6.19779 7.68767 5.90138 8.07205 5.5365 8.29289C4.78534 8.74751 4.39863 9.41436 4.19873 10H11.8017C11.6018 9.41434 11.2151 8.74746 10.4639 8.29284C10.099 8.07201 9.80253 7.68762 9.73288 7.20009L9.5196 5.70711C9.39088 4.80611 10.09 4 11.0002 4V3L5.00016 3V4C5.91031 4 6.60944 4.80611 6.48073 5.70711Z" fill="#43454A"/>
|
||||
<path d="M7.5 11H8.5V14.5C8.5 14.7761 8.27614 15 8 15V15C7.72386 15 7.5 14.7761 7.5 14.5V11Z" fill="#CED0D6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,5 @@
|
||||
<!-- Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. -->
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M6.48057 5.70711L6.26727 7.20016C6.19763 7.68767 5.90122 8.07205 5.53634 8.29289C4.78518 8.74751 4.39847 9.41436 4.19857 10H11.8015C11.6016 9.41434 11.2149 8.74746 10.4637 8.29284C10.0988 8.07201 9.80236 7.68762 9.73272 7.20009L9.51943 5.70711C9.39072 4.80611 10.0899 4 11 4V3L5 3V4C5.91014 4 6.60928 4.80611 6.48057 5.70711ZM5.27732 7.05873C5.25463 7.2176 5.15585 7.35428 5.01856 7.43737C3.84968 8.14481 3.35768 9.22759 3.15058 10.0138C3.0099 10.5478 3.44776 11 4.00005 11H12C12.5523 11 12.9902 10.5478 12.8495 10.0138C12.6424 9.22757 12.1504 8.14475 10.9814 7.43732C10.8442 7.35423 10.7454 7.21754 10.7227 7.05867L10.5094 5.56569C10.4667 5.26712 10.6984 5 11 5C11.5523 5 12 4.55228 12 4V3C12 2.44772 11.5523 2 11 2H5C4.44772 2 4 2.44772 4 3V4C4 4.55228 4.44772 5 5 5C5.3016 5 5.53327 5.26712 5.49062 5.56569L5.27732 7.05873Z" fill="#CED0D6"/>
|
||||
<path d="M7.5 11H8.5V14.5C8.5 14.7761 8.27614 15 8 15V15C7.72386 15 7.5 14.7761 7.5 14.5V11Z" fill="#CED0D6"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
Reference in New Issue
Block a user