diff --git a/ide/projectui/src/org/netbeans/modules/project/ui/ProjectTab.java b/ide/projectui/src/org/netbeans/modules/project/ui/ProjectTab.java index 98a4bd1785c7..dde9908fbb6b 100644 --- a/ide/projectui/src/org/netbeans/modules/project/ui/ProjectTab.java +++ b/ide/projectui/src/org/netbeans/modules/project/ui/ProjectTab.java @@ -23,8 +23,13 @@ import java.awt.Color; import java.awt.Component; import java.awt.Cursor; +import java.awt.Dimension; import java.awt.EventQueue; +import java.awt.FlowLayout; +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; import java.awt.Image; +import java.awt.Insets; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -45,6 +50,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -56,15 +62,21 @@ import javax.swing.Action; import javax.swing.ActionMap; import javax.swing.BorderFactory; +import javax.swing.ImageIcon; +import javax.swing.JButton; +import javax.swing.JEditorPane; import javax.swing.JLabel; +import javax.swing.JLayeredPane; import javax.swing.JPanel; import javax.swing.JPopupMenu; +import javax.swing.JToolBar; import javax.swing.SwingConstants; import javax.swing.SwingUtilities; import javax.swing.UIManager; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.text.DefaultEditorKit; +import javax.swing.text.Document; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeModel; import javax.swing.tree.TreeNode; @@ -82,8 +94,10 @@ import org.openide.awt.ActionReference; import org.openide.awt.ActionReferences; import org.openide.awt.ActionRegistration; +import org.openide.awt.Actions; import org.openide.awt.StatusDisplayer; import org.openide.awt.UndoRedo; +import org.openide.cookies.EditorCookie; import org.openide.explorer.ExplorerManager; import org.openide.explorer.ExplorerUtils; import org.openide.explorer.view.BeanTreeView; @@ -140,6 +154,8 @@ public class ProjectTab extends TopComponent private String id; private final transient ProjectTreeView btv; + JPanel projectTreeViewPanel = new JPanel(new BorderLayout()); + JLayeredPane layeredPane = new JLayeredPane(); private final JLabel noProjectsLabel = new JLabel(NbBundle.getMessage(ProjectTab.class, "NO_PROJECT_OPEN")); @@ -176,8 +192,44 @@ public ProjectTab() { btv.setDragSource (true); btv.setRootVisible(false); + add(layeredPane, BorderLayout.CENTER); + projectTreeViewPanel.add(btv, BorderLayout.CENTER); - add( btv, BorderLayout.CENTER ); + JPanel buttonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 10, 5)); + buttonPanel.setOpaque(false); + + ImageIcon collapseTreeIcon = ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/collapseTree.svg",false); + JButton collapseAllButton = new JButton(); + collapseAllButton.setIcon(collapseTreeIcon); + collapseAllButton.setBorderPainted(false); + collapseAllButton.setContentAreaFilled(false); + collapseAllButton.setFocusPainted(false); + collapseAllButton.addActionListener((ActionEvent ae ) -> { + collapseNodes(rootNode, this); + }); + collapseAllButton.setFocusable(false); + JButton navigateToSelectedFileButton = new JButton(); + ImageIcon crossHairsIcon = ImageUtilities.loadImageIcon("org/netbeans/modules/project/ui/resources/crossHairs.svg",false); + navigateToSelectedFileButton.setIcon(crossHairsIcon); + navigateToSelectedFileButton.setBorderPainted(false); + navigateToSelectedFileButton.setContentAreaFilled(false); + navigateToSelectedFileButton.setFocusPainted(false); + + navigateToSelectedFileButton.addActionListener((ActionEvent ae ) -> { + navigateToCurrentFile(); + }); + navigateToSelectedFileButton.setFocusable(false); + buttonPanel.add(collapseAllButton); + buttonPanel.add(navigateToSelectedFileButton); + layeredPane.add(projectTreeViewPanel, JLayeredPane.DEFAULT_LAYER); + layeredPane.add(buttonPanel, JLayeredPane.PALETTE_LAYER); + + addComponentListener(new java.awt.event.ComponentAdapter() { + public void componentResized(java.awt.event.ComponentEvent evt) { + resetLayeredPaneSize(); + buttonPanel.setBounds(0, 0, getWidth(), buttonPanel.getPreferredSize().height); + } + }); OpenProjects.getDefault().addPropertyChangeListener(this); @@ -344,7 +396,7 @@ public int getPersistenceType() { * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the FormEditor. */ - private void initComponents() {//GEN-BEGIN:initComponents + private void initComponents() { setLayout(new java.awt.BorderLayout()); @@ -367,6 +419,52 @@ public void requestFocus() { btv.requestFocus(); } + public static FileObject getActiveEditorFile() { + // Get all opened windows + Set opened = WindowManager.getDefault().getRegistry().getOpened(); + + // Find the editor window + for (TopComponent tc : opened) { + // Check if this component is an editor window and is focused + if (tc.isShowing() && isEditorWindow(tc)) { + // Get the DataObject from the editor + DataObject dataObj = tc.getLookup().lookup(DataObject.class); + if (dataObj != null) { + return dataObj.getPrimaryFile(); + } + } + } + return null; + } + + private static boolean isEditorWindow(TopComponent tc) { + // Check if this is an editor window by looking for EditorCookie + EditorCookie ec = tc.getLookup().lookup(EditorCookie.class); + if (ec != null) { + // Additional check - verify the component's class name + // Editor windows typically have "EditorTopComponent" in their class name + String className = tc.getClass().getName().toLowerCase(); + return className.contains("editor") || className.contains("multiview"); + } + return false; + } + + private void navigateToCurrentFile() { + FileObject selectedFileInCodeEditor = getActiveEditorFile(); + if (selectedFileInCodeEditor != null) { + Node nodeToSelect = findNode(selectedFileInCodeEditor); + if (nodeToSelect != null) { + try { + getExplorerManager().setSelectedNodes(new Node[]{nodeToSelect}); + btv.scrollToNode(nodeToSelect); + + } catch (Exception ex) { + org.openide.util.Exceptions.printStackTrace(ex); + } + } + } + } + // PERSISTENCE private static final long serialVersionUID = 9374872358L; @@ -681,20 +779,31 @@ private void showNoProjectsLabel() { if (noProjectsLabel.isShowing()) { return; } - remove(btv); + remove(layeredPane); add(noProjectsLabel, BorderLayout.CENTER); revalidate(); repaint(); } + private void resetLayeredPaneSize() { + projectTreeViewPanel.setBounds(0, 0, getWidth(), getHeight()); + projectTreeViewPanel.setPreferredSize(new Dimension(getWidth(), getHeight())); + layeredPane.setBounds(0, 0, getWidth(), getHeight()); + layeredPane.setPreferredSize(new Dimension(getWidth(), getHeight())); + btv.setBounds(0, 0, getWidth(), getHeight()); + btv.setPreferredSize(new Dimension(getWidth(), getHeight())); + revalidate(); + repaint(); + } + private void restoreTreeView() { if (btv.isShowing()) { return; } remove(noProjectsLabel); - add(btv, BorderLayout.CENTER ); - revalidate(); - repaint(); + projectTreeViewPanel.add(btv, BorderLayout.CENTER); + add(layeredPane, BorderLayout.CENTER); + resetLayeredPaneSize(); } // Private innerclasses ---------------------------------------------------- @@ -869,6 +978,17 @@ public void preferenceChange(PreferenceChangeEvent evt) { } } + + private static void collapseNodes(Node node, ProjectTab tab) { + if ( node.getChildren().getNodesCount() != 0 ) { + for ( Node nodeIter : node.getChildren().getNodes() ) { + if( tab.btv.isExpanded(nodeIter) ) { + collapseNodes(nodeIter, tab); + tab.btv.collapseNode(nodeIter); + } + } + } + } @ActionID(category="Project", id="org.netbeans.modules.project.ui.collapseAllNodes") @ActionRegistration(displayName="#collapseAllNodes") @@ -939,18 +1059,6 @@ public void run() { }); } - - private void collapseNodes(Node node, ProjectTab tab) { - if ( node.getChildren().getNodesCount() != 0 ) { - for ( Node nodeIter : node.getChildren().getNodes() ) { - if( tab.btv.isExpanded(nodeIter) ) { - collapseNodes(nodeIter, tab); - tab.btv.collapseNode(nodeIter); - } - } - } - } - } @ActionID(category="Project", id="org.netbeans.modules.project.ui.NodeSelectionProjectAction") diff --git a/ide/projectui/src/org/netbeans/modules/project/ui/resources/collapseTree.svg b/ide/projectui/src/org/netbeans/modules/project/ui/resources/collapseTree.svg new file mode 100644 index 000000000000..c8796186646d --- /dev/null +++ b/ide/projectui/src/org/netbeans/modules/project/ui/resources/collapseTree.svg @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/ide/projectui/src/org/netbeans/modules/project/ui/resources/crossHairs.svg b/ide/projectui/src/org/netbeans/modules/project/ui/resources/crossHairs.svg new file mode 100644 index 000000000000..a740c31e9d32 --- /dev/null +++ b/ide/projectui/src/org/netbeans/modules/project/ui/resources/crossHairs.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file