package net.sourceforge.squirrel_sql.client.gui.recentfiles; import net.sourceforge.squirrel_sql.client.IApplication; import net.sourceforge.squirrel_sql.client.gui.dnd.DropedFileExtractor; import net.sourceforge.squirrel_sql.client.session.ISQLPanelAPI; import net.sourceforge.squirrel_sql.fw.gui.GUIUtils; import net.sourceforge.squirrel_sql.fw.gui.TreeDnDHandler; import net.sourceforge.squirrel_sql.fw.gui.TreeDnDHandlerCallback; import net.sourceforge.squirrel_sql.fw.sql.ISQLAlias; import net.sourceforge.squirrel_sql.fw.util.StringManager; import net.sourceforge.squirrel_sql.fw.util.StringManagerFactory; import javax.swing.*; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.TreeNode; import javax.swing.tree.TreePath; import java.awt.*; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.*; import java.io.File; import java.util.*; import java.util.List; import java.util.prefs.Preferences; public class RecentFilesController { private static final StringManager s_stringMgr = StringManagerFactory.getStringManager(RecentFilesDialog.class); private static final String PREF_KEY_RECENT_FILES_EXPANDED = "Squirrel.recentFiles.expanded"; private static final String PREF_KEY_FAVOURITE_FILES_EXPANDED = "Squirrel.favouriteFiles.expanded"; private static final String PREF_KEY_RECENT_ALIAS_FILES_EXPANDED = "Squirrel.recentAliasFiles.expanded"; private static final String PREF_KEY_FAVOURITE_ALIAS_FILES_EXPANDED = "Squirrel.favouriteAliasFiles.expanded"; private RecentFilesDialog _dialog; private IApplication _app; private Frame _parent; private ISQLAlias _selectedAlias; private DefaultMutableTreeNode _recentFilesNode; private DefaultMutableTreeNode _favouriteFilesNode; private DefaultMutableTreeNode _recentFilesForAliasNode; private DefaultMutableTreeNode _favouriteFilesForAliasNode; private File _fileToOpen; public RecentFilesController(IApplication app, ISQLAlias selectedAlias) { init(app, app.getMainFrame() , selectedAlias, true); } public RecentFilesController(ISQLPanelAPI panel) { Frame parent = GUIUtils.getOwningFrame(panel.getSQLEntryPanel().getTextComponent()); init(panel.getSession().getApplication(), parent, panel.getSession().getAlias(), false); } private void init(IApplication app, final Frame parent, final ISQLAlias selectedAlias, boolean showAppendOption) { _app = app; _parent = parent; _selectedAlias = selectedAlias; _dialog = new RecentFilesDialog(_parent, showAppendOption); _dialog.btnClose.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { _dialog.dispose(); } }); initAndLoadTree(); _dialog.txtNumberRecentFiles.setInt(_app.getRecentFilesManager().getMaxRecentFiles()); _dialog.txtNumberRecentFiles.getDocument().addDocumentListener(new DocumentListener() { @Override public void insertUpdate(DocumentEvent e) { updateRecentFilesCount(); } @Override public void removeUpdate(DocumentEvent e) { updateRecentFilesCount(); } @Override public void changedUpdate(DocumentEvent e) { updateRecentFilesCount(); } }); _dialog.btnFavourites.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { onAddToFavourites(null); } }); _dialog.btnAliasFavourites.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { onAddToFavourites(selectedAlias); } }); _dialog.btnRemoveSeleted.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { onRemoveSelected(); } }); _dialog.btnOpenFile.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { onOpenFile(); } }); _dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { onWindowClosing(); } @Override public void windowClosed(WindowEvent e) { onWindowClosing(); } }); _dialog.setVisible(true); } private void onOpenFile() { _fileToOpen = findFileToOpen(null); if(null == _fileToOpen) { return; } _dialog.dispose(); } private void onWindowClosing() { JTree tre = _dialog.treFiles; tre.isCollapsed(new TreePath(_recentFilesNode.getPath())); Preferences.userRoot().putBoolean(PREF_KEY_RECENT_FILES_EXPANDED, tre.isExpanded(new TreePath(_recentFilesNode.getPath()))); Preferences.userRoot().putBoolean(PREF_KEY_FAVOURITE_FILES_EXPANDED, tre.isExpanded(new TreePath(_favouriteFilesNode.getPath()))); Preferences.userRoot().putBoolean(PREF_KEY_RECENT_ALIAS_FILES_EXPANDED, tre.isExpanded(new TreePath(_recentFilesForAliasNode.getPath()))); Preferences.userRoot().putBoolean(PREF_KEY_FAVOURITE_ALIAS_FILES_EXPANDED, tre.isExpanded(new TreePath(_favouriteFilesForAliasNode.getPath()))); } private void onRemoveSelected() { HashSet<DefaultMutableTreeNode> changedParents = new HashSet<DefaultMutableTreeNode>(); TreePath[] paths = _dialog.treFiles.getSelectionPaths(); DefaultTreeModel model = (DefaultTreeModel) _dialog.treFiles.getModel(); for (TreePath path : paths) { DefaultMutableTreeNode dmtn = (DefaultMutableTreeNode) path.getLastPathComponent(); if( dmtn.getUserObject() instanceof File ) { model.removeNodeFromParent(dmtn); changedParents.add((DefaultMutableTreeNode) path.getParentPath().getLastPathComponent()); } } for (DefaultMutableTreeNode changedParent : changedParents) { model.nodeStructureChanged(changedParent); } writeUiTreeToModel(); } private void writeUiTreeToModel() { _app.getRecentFilesManager().setRecentFiles(getFileStringsFromNode(_recentFilesNode)); _app.getRecentFilesManager().setFavouriteFiles(getFileStringsFromNode(_favouriteFilesNode)); _app.getRecentFilesManager().setRecentFilesForAlias(_selectedAlias, getFileStringsFromNode(_recentFilesForAliasNode)); _app.getRecentFilesManager().setFavouriteFilesForAlias(_selectedAlias, getFileStringsFromNode(_favouriteFilesForAliasNode)); } private ArrayList<String> getFileStringsFromNode(DefaultMutableTreeNode parentNode) { ArrayList<String> files = new ArrayList<String>(); for (int i = 0; i < parentNode.getChildCount(); i++) { File file = (File) ((DefaultMutableTreeNode) parentNode.getChildAt(i)).getUserObject(); files.add(file.getAbsolutePath()); } return files; } private void onAddToFavourites(ISQLAlias alias) { JFileChooser fc = new JFileChooser(_app.getSquirrelPreferences().getFilePreviousDir()); fc.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int returnVal = fc.showOpenDialog(_parent); if (returnVal != JFileChooser.APPROVE_OPTION) { return; } DefaultMutableTreeNode nodeToAddTo; ArrayList<String> listToAddTo; if (null == alias) { _app.getRecentFilesManager().adjustFavouriteFiles(fc.getSelectedFile()); nodeToAddTo = _favouriteFilesNode; listToAddTo = _app.getRecentFilesManager().getFavouriteFiles(); } else { _app.getRecentFilesManager().adjustFavouriteAliasFiles(alias, fc.getSelectedFile()); nodeToAddTo = _favouriteFilesForAliasNode; listToAddTo = _app.getRecentFilesManager().getFavouriteFilesForAlias(alias); } nodeToAddTo.removeAllChildren(); addFileKidsToNode(nodeToAddTo, listToAddTo, false); DefaultTreeModel dtm = (DefaultTreeModel) _dialog.treFiles.getModel(); dtm.nodeStructureChanged(nodeToAddTo); _dialog.treFiles.expandPath(new TreePath(nodeToAddTo.getPath())); DefaultMutableTreeNode firstChild = (DefaultMutableTreeNode) nodeToAddTo.getFirstChild(); _dialog.treFiles.scrollPathToVisible(new TreePath(firstChild.getPath())); } private void updateRecentFilesCount() { int maxRecentFiles = _dialog.txtNumberRecentFiles.getInt(); if (0 < maxRecentFiles) { _app.getRecentFilesManager().setMaxRecentFiles(maxRecentFiles); } } private void initAndLoadTree() { DefaultMutableTreeNode root = new DefaultMutableTreeNode(); _dialog.treFiles.setModel(new DefaultTreeModel(root)); _dialog.treFiles.setRootVisible(false); _dialog.treFiles.setCellRenderer(new RecentFilesTreeCellRenderer(_app)); _recentFilesNode = GUIUtils.createFolderNode(s_stringMgr.getString("RecentFilesController.recentFiles.global")); root.add(_recentFilesNode); addFileKidsToNode(_recentFilesNode, _app.getRecentFilesManager().getRecentFiles(), Preferences.userRoot().getBoolean(PREF_KEY_RECENT_FILES_EXPANDED, true)); _favouriteFilesNode = GUIUtils.createFolderNode(s_stringMgr.getString("RecentFilesController.favouritFiles.global")); root.add(_favouriteFilesNode); addFileKidsToNode(_favouriteFilesNode, _app.getRecentFilesManager().getFavouriteFiles(), Preferences.userRoot().getBoolean(PREF_KEY_FAVOURITE_FILES_EXPANDED, false)); _recentFilesForAliasNode = GUIUtils.createFolderNode(s_stringMgr.getString("RecentFilesController.recentFiles.alias", _selectedAlias.getName())); root.add(_recentFilesForAliasNode); addFileKidsToNode(_recentFilesForAliasNode, _app.getRecentFilesManager().getRecentFilesForAlias(_selectedAlias), Preferences.userRoot().getBoolean(PREF_KEY_RECENT_ALIAS_FILES_EXPANDED, false)); _favouriteFilesForAliasNode = GUIUtils.createFolderNode(s_stringMgr.getString("RecentFilesController.favouritFiles.alias", _selectedAlias.getName())); root.add(_favouriteFilesForAliasNode); addFileKidsToNode(_favouriteFilesForAliasNode, _app.getRecentFilesManager().getFavouriteFilesForAlias(_selectedAlias), Preferences.userRoot().getBoolean(PREF_KEY_FAVOURITE_ALIAS_FILES_EXPANDED, false)); _dialog.treFiles.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent evt) { onMouseClickedTree(evt); } }); initDnD(); } private void initDnD() { TreeDnDHandlerCallback treeDnDHandlerCallback = new TreeDnDHandlerCallback() { @Override public boolean nodeAcceptsKids(DefaultMutableTreeNode selNode) { return onNodeAcceptsKids(selNode); } @Override public void dndExecuted() { onDndExecuted(); } @Override public ArrayList<DefaultMutableTreeNode> createPasteTreeNodesFromExternalTransfer(DropTargetDropEvent dtde, TreePath targetPath) { return onCreatePasteTreeNodesFromExternalTransfer(dtde, targetPath); } }; new TreeDnDHandler(_dialog.treFiles, treeDnDHandlerCallback, true); } private ArrayList<DefaultMutableTreeNode> onCreatePasteTreeNodesFromExternalTransfer(DropTargetDropEvent dtde, TreePath targetPath) { List<File> files = DropedFileExtractor.getFiles(dtde, _app); ArrayList<DefaultMutableTreeNode> ret = new ArrayList<DefaultMutableTreeNode>(); DefaultMutableTreeNode parent = findParent(targetPath); for (File file : files) { if (false == parentContainsFile(parent, file)) { ret.add(new DefaultMutableTreeNode(file)); } } return ret; } private boolean parentContainsFile(DefaultMutableTreeNode parentNode, File fileToCheck) { if(null == parentNode) { return false; } for (int i = 0; i < parentNode.getChildCount(); i++) { File file = (File) ((DefaultMutableTreeNode) parentNode.getChildAt(i)).getUserObject(); if(file.equals(fileToCheck)) { return true; } } return false; } private DefaultMutableTreeNode findParent(TreePath targetPath) { if(((DefaultMutableTreeNode)targetPath.getLastPathComponent()).getUserObject() instanceof File) { targetPath = targetPath.getParentPath(); } if(targetPath.getLastPathComponent() == _recentFilesNode) { return _recentFilesNode; } else if(targetPath.getLastPathComponent() == _recentFilesForAliasNode) { return _recentFilesForAliasNode; } else if(targetPath.getLastPathComponent() == _favouriteFilesNode) { return _favouriteFilesNode; } else if(targetPath.getLastPathComponent() == _favouriteFilesForAliasNode) { return _favouriteFilesForAliasNode; } else { return null; } } private void onDndExecuted() { writeUiTreeToModel(); } private boolean onNodeAcceptsKids(DefaultMutableTreeNode selNode) { return _recentFilesNode == selNode || _recentFilesForAliasNode == selNode || _favouriteFilesNode == selNode || _favouriteFilesForAliasNode == selNode; } private void onMouseClickedTree(MouseEvent evt) { _fileToOpen = findFileToOpen(evt); if(null != _fileToOpen) { _dialog.dispose(); } } private File findFileToOpen(MouseEvent evt) { DefaultMutableTreeNode tn = getSelectedFileNode(evt); if (tn == null) { if (null == evt) // The open button was pushed { JOptionPane.showMessageDialog(_dialog, s_stringMgr.getString("RecentFilesController.pleaseSelectFile")); } return null; } File file = (File) tn.getUserObject(); if(false == file.exists()) { if(JOptionPane.YES_OPTION == JOptionPane.showConfirmDialog(_dialog, s_stringMgr.getString("RecentFilesController.fileDoesNotExist"))) { DefaultTreeModel model = (DefaultTreeModel) _dialog.treFiles.getModel(); TreeNode parent = tn.getParent(); model.removeNodeFromParent(tn); model.nodeStructureChanged(parent); if(parent == _recentFilesNode) { _app.getRecentFilesManager().setRecentFiles(getFileStringsFromNode(_recentFilesNode)); } else if(parent == _favouriteFilesNode) { _app.getRecentFilesManager().setFavouriteFiles(getFileStringsFromNode(_favouriteFilesNode)); } else if(parent == _recentFilesForAliasNode) { _app.getRecentFilesManager().setRecentFilesForAlias(_selectedAlias, getFileStringsFromNode(_recentFilesForAliasNode)); } else { _app.getRecentFilesManager().setFavouriteFilesForAlias(_selectedAlias, getFileStringsFromNode(_favouriteFilesForAliasNode)); } } return null; } if(file.isDirectory()) { JFileChooser fc = new JFileChooser(file); fc.setFileSelectionMode(JFileChooser.FILES_ONLY); int returnVal = fc.showOpenDialog(_parent); if (returnVal != JFileChooser.APPROVE_OPTION) { return null; } file = fc.getSelectedFile(); } if(false == file.canRead()) { JOptionPane.showMessageDialog(_dialog, s_stringMgr.getString("RecentFilesController.fileIsNotReadable")); return null; } return file; } private DefaultMutableTreeNode getSelectedFileNode(MouseEvent evt) { TreePath path = _dialog.treFiles.getSelectionPath(); if(null == path) { return null; } if (null != evt) { if (evt.getClickCount() < 2) { return null; } if (false == _dialog.treFiles.getPathBounds(path).contains(evt.getPoint())) { // If the mouse wasn't placed on the selected file we do nothing. return null; } } DefaultMutableTreeNode tn = (DefaultMutableTreeNode) path.getLastPathComponent(); if(false == tn.getUserObject() instanceof File) { return null; } return tn; } private void addFileKidsToNode(final DefaultMutableTreeNode parentNode, ArrayList<String> filePaths, final boolean expand) { for (String filePath : filePaths) { DefaultMutableTreeNode node = new DefaultMutableTreeNode(new File(filePath)); parentNode.add(node); } SwingUtilities.invokeLater(new Runnable() { public void run() { if (expand) { _dialog.treFiles.expandPath(new TreePath(parentNode.getPath())); } } }); } public File getFileToOpen() { return _fileToOpen; } public boolean isAppend() { return _dialog.chkAppend.isSelected(); } }