/* Copyright 2008-2010 Gephi Authors : Martin Škurla Website : http://www.gephi.org This file is part of Gephi. Gephi is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. Gephi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with Gephi. If not, see <http://www.gnu.org/licenses/>. */ package org.gephi.desktop.neo4j; import org.gephi.neo4j.plugin.api.ClassNotFulfillRequirementsException; import org.gephi.neo4j.plugin.api.FileSystemClassLoader; import org.gephi.neo4j.plugin.api.MutableNeo4jDelegateNodeDebugger; import org.gephi.neo4j.plugin.api.Neo4jDelegateNodeDebugger; import org.gephi.neo4j.plugin.api.Neo4jExporter; import org.gephi.neo4j.plugin.api.Neo4jImporter; import org.gephi.neo4j.plugin.api.Neo4jVisualDebugger; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import javax.swing.AbstractAction; import javax.swing.JFileChooser; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import org.gephi.desktop.neo4j.ui.DebugFileChooserComponent; import org.gephi.desktop.neo4j.ui.DebugPanel; import org.gephi.desktop.neo4j.ui.ExportOptionsPanel; import org.gephi.desktop.neo4j.ui.TraversalFilterPanel; import org.gephi.desktop.neo4j.ui.RemoteDatabasePanel; import org.gephi.desktop.neo4j.ui.TraversalImportPanel; import org.gephi.desktop.neo4j.ui.util.Neo4jUtils; import org.gephi.desktop.project.api.ProjectControllerUI; import org.gephi.project.api.ProjectController; import org.gephi.project.api.Workspace; import org.gephi.project.api.WorkspaceListener; import org.gephi.utils.longtask.api.LongTaskExecutor; import org.gephi.utils.longtask.spi.LongTask; import org.gephi.visualization.VizController; import org.neo4j.graphdb.GraphDatabaseService; import org.netbeans.validation.api.ui.ValidationPanel; import org.openide.DialogDescriptor; import org.openide.DialogDisplayer; import org.openide.NotifyDescriptor; import org.openide.awt.StatusDisplayer; import org.openide.util.HelpCtx; import org.openide.util.ImageUtilities; import org.openide.util.Lookup; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; import org.openide.util.actions.CallableSystemAction; /** * * @author Martin Škurla */ public class Neo4jMenuAction extends CallableSystemAction { private final String IMPORT_LAST_PATH = "Neo4jMenuAction_Import_Last_Path"; private final String EXPORT_LAST_PATH = "Neo4jMenuAction_Export_Last_Path"; private JMenuItem localExport; private JMenuItem remoteExport; private JMenuItem debug; private JMenu menu; private boolean previousEdgeHasUniColor; public Neo4jMenuAction() { initializeMenu(); Lookup.getDefault().lookup(ProjectController.class).addWorkspaceListener(new WorkspaceListener() { @Override public void initialize(Workspace workspace) { localExport.setEnabled(true); remoteExport.setEnabled(true); debug.setEnabled(true); } @Override public void disable() { localExport.setEnabled(false); remoteExport.setEnabled(false); debug.setEnabled(false); } @Override public void select(Workspace workspace) { } @Override public void unselect(Workspace workspace) { } @Override public void close(Workspace workspace) { } }); } @Override public void performAction() { throw new UnsupportedOperationException("Not supported yet."); } @Override public String getName() { return "importNeo4jDB"; } @Override public HelpCtx getHelpCtx() { return null; } @Override public JMenuItem getMenuPresenter() { return menu; } private void initializeMenu() { menu = new JMenu(NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_MenuLabel")); String localFullImportMenuLabel = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_LocalWholeImportMenuLabel"); JMenuItem localFullImport = new JMenuItem(new AbstractAction(localFullImportMenuLabel) { public void actionPerformed(ActionEvent e) { String lastDirectory = NbPreferences.forModule(Neo4jMenuAction.class).get(IMPORT_LAST_PATH, ""); JFileChooser fileChooser = new JFileChooser(lastDirectory); String localImportDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_LocalImportDialogTitle"); fileChooser.setDialogTitle(localImportDialogTitle); Neo4jCustomDirectoryProvider.setEnabled(true); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int dialogResult = fileChooser.showOpenDialog(null); Neo4jCustomDirectoryProvider.setEnabled(false); if (dialogResult == JFileChooser.CANCEL_OPTION) { return; } final File neo4jDirectory = fileChooser.getSelectedFile(); if (neo4jDirectory != null && neo4jDirectory.exists()) { NbPreferences.forModule(Neo4jMenuAction.class).put(IMPORT_LAST_PATH, neo4jDirectory.getParentFile().getAbsolutePath()); } final GraphDatabaseService graphDB = Neo4jUtils.localDatabase(neo4jDirectory); String traversalDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_TraversalDialogTitle"); final TraversalFilterPanel filterPanel = new TraversalFilterPanel(); ValidationPanel validationPanel = filterPanel.createValidationPanel(); final DialogDescriptor dd = new DialogDescriptor(validationPanel, traversalDialogTitle); validationPanel.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { dd.setValid(!((ValidationPanel) e.getSource()).isProblem()); } }); Object result = DialogDisplayer.getDefault().notify(dd); if (result == NotifyDescriptor.OK_OPTION) { final Neo4jImporter neo4jImporter = Lookup.getDefault().lookup(Neo4jImporter.class); LongTaskExecutor executor = new LongTaskExecutor(true); executor.execute((LongTask) neo4jImporter, new Runnable() { @Override public void run() { initProject(); neo4jImporter.importDatabase(graphDB, filterPanel.getFilterDescriptions(), filterPanel.isRestrictModeEnabled(), filterPanel.isMatchCaseEnabled()); StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ImportTaskFinished", neo4jDirectory)); } }); } } }); localFullImport.setIcon(ImageUtilities.loadImageIcon("org/gephi/desktop/neo4j/resources/import.png", false)); String localTraversalImportMenuLabel = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_LocalTraversalImportMenuLabel"); JMenuItem localTraversalImport = new JMenuItem(new AbstractAction(localTraversalImportMenuLabel) { public void actionPerformed(ActionEvent e) { String lastDirectory = NbPreferences.forModule(Neo4jMenuAction.class).get(IMPORT_LAST_PATH, ""); JFileChooser fileChooser = new JFileChooser(lastDirectory); String localImportDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_LocalImportDialogTitle"); fileChooser.setDialogTitle(localImportDialogTitle); Neo4jCustomDirectoryProvider.setEnabled(true); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int dialogResult = fileChooser.showOpenDialog(null); Neo4jCustomDirectoryProvider.setEnabled(false); if (dialogResult == JFileChooser.CANCEL_OPTION) { return; } final File neo4jDirectory = fileChooser.getSelectedFile(); if (neo4jDirectory != null && neo4jDirectory.exists()) { NbPreferences.forModule(Neo4jMenuAction.class).put(IMPORT_LAST_PATH, neo4jDirectory.getParentFile().getAbsolutePath()); } final GraphDatabaseService graphDB = Neo4jUtils.localDatabase(neo4jDirectory); String traversalDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_TraversalDialogTitle"); final TraversalImportPanel traversalPanel = new TraversalImportPanel(graphDB); ValidationPanel validationPanel = traversalPanel.createValidationPanel(); final DialogDescriptor dd = new DialogDescriptor(validationPanel, traversalDialogTitle); validationPanel.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { dd.setValid(!((ValidationPanel) e.getSource()).isProblem()); } }); Object result = DialogDisplayer.getDefault().notify(dd); if (result == NotifyDescriptor.OK_OPTION) { final Neo4jImporter neo4jImporter = Lookup.getDefault().lookup(Neo4jImporter.class); LongTaskExecutor executor = new LongTaskExecutor(true); executor.execute((LongTask) neo4jImporter, new Runnable() { @Override public void run() { initProject(); neo4jImporter.importDatabase(graphDB, traversalPanel.getStartNodeId(), traversalPanel.getOrder(), traversalPanel.getMaxDepth(), traversalPanel.getRelationshipDescriptions(), traversalPanel.getFilterDescriptions(), traversalPanel.isRestrictModeEnabled(), traversalPanel.isMatchCaseEnabled()); StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ImportTaskFinished", neo4jDirectory)); } }); } } }); String localExportMenuLabel = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_LocalExportMenuLabel"); localExport = new JMenuItem(new AbstractAction(localExportMenuLabel) { public void actionPerformed(ActionEvent e) { String exportOptionsDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ExportOptionsDialogTitle"); final ExportOptionsPanel exportOptionsPanel = new ExportOptionsPanel(); ValidationPanel validationPanel = exportOptionsPanel.createValidationPanel(); final DialogDescriptor dd = new DialogDescriptor(validationPanel, exportOptionsDialogTitle); validationPanel.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { dd.setValid(!((ValidationPanel) e.getSource()).isProblem()); } }); Object result = DialogDisplayer.getDefault().notify(dd); if (result == NotifyDescriptor.OK_OPTION) { String lastDirectory = NbPreferences.forModule(Neo4jMenuAction.class).get(EXPORT_LAST_PATH, ""); JFileChooser fileChooser = new JFileChooser(lastDirectory); String localExportDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_LocalExportDialogTitle"); fileChooser.setDialogTitle(localExportDialogTitle); fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); int dialogResult = fileChooser.showOpenDialog(null); if (dialogResult == JFileChooser.APPROVE_OPTION) { final File neo4jDirectory = fileChooser.getSelectedFile(); if (neo4jDirectory != null && neo4jDirectory.exists()) { NbPreferences.forModule(Neo4jMenuAction.class).put(EXPORT_LAST_PATH, neo4jDirectory.getParentFile().getAbsolutePath()); } final Neo4jExporter neo4jExporter = Lookup.getDefault().lookup(Neo4jExporter.class); LongTaskExecutor executor = new LongTaskExecutor(true); executor.execute((LongTask) neo4jExporter, new Runnable() { @Override public void run() { GraphDatabaseService graphDB = Neo4jUtils.localDatabase(neo4jDirectory); neo4jExporter.exportDatabase(graphDB, exportOptionsPanel.getFromColumn(), exportOptionsPanel.getDefaultValue(), exportOptionsPanel.getExportEdgeColumnNames(), exportOptionsPanel.getExportNodeColumnNames()); graphDB.shutdown(); StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ExportTaskFinished", neo4jDirectory)); } }); } } } }); localExport.setIcon(ImageUtilities.loadImageIcon("org/gephi/desktop/neo4j/resources/export.png", false)); String remoteImportMenuLabel = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_RemoteImportMenuLabel"); JMenuItem remoteImport = new JMenuItem(new AbstractAction(remoteImportMenuLabel) { public void actionPerformed(ActionEvent e) { final RemoteDatabasePanel databasePanel = new RemoteDatabasePanel(); ValidationPanel validationPanel = databasePanel.createValidationPanel(); String remoteImportDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_RemoteImportDialogTitle"); final DialogDescriptor dd = new DialogDescriptor(validationPanel, remoteImportDialogTitle); validationPanel.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { dd.setValid(!((ValidationPanel) e.getSource()).isProblem()); } }); Object result = DialogDisplayer.getDefault().notify(dd); if (result == NotifyDescriptor.OK_OPTION) { final Neo4jImporter neo4jImporter = Lookup.getDefault().lookup(Neo4jImporter.class); LongTaskExecutor executor = new LongTaskExecutor(true); executor.execute((LongTask) neo4jImporter, new Runnable() { @Override public void run() { GraphDatabaseService graphDB = Neo4jUtils.remoteDatabase(databasePanel.getRemoteUrl(), databasePanel.getLogin(), databasePanel.getPassword()); neo4jImporter.importDatabase(graphDB); StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ImportTaskFinished", databasePanel.getRemoteUrl())); } }); } } }); String remoteExportMenuLabel = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_RemoteExportMenuLabel"); remoteExport = new JMenuItem(new AbstractAction(remoteExportMenuLabel) { public void actionPerformed(ActionEvent e) { final RemoteDatabasePanel databasePanel = new RemoteDatabasePanel(); ValidationPanel validationPanel = databasePanel.createValidationPanel(); String remoteExportDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_RemoteExportDialogTitle"); final DialogDescriptor dd = new DialogDescriptor(validationPanel, remoteExportDialogTitle); validationPanel.addChangeListener(new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { dd.setValid(!((ValidationPanel) e.getSource()).isProblem()); } }); Object result = DialogDisplayer.getDefault().notify(dd); if (result == NotifyDescriptor.OK_OPTION) { final Neo4jExporter neo4jExporter = Lookup.getDefault().lookup(Neo4jExporter.class); LongTaskExecutor executor = new LongTaskExecutor(true); executor.execute((LongTask) neo4jExporter, new Runnable() { @Override public void run() { GraphDatabaseService graphDB = Neo4jUtils.remoteDatabase(databasePanel.getRemoteUrl(), databasePanel.getLogin(), databasePanel.getPassword()); neo4jExporter.exportDatabase(graphDB,//TODO >>> refactor like for local export with export dialog null, null, null, null); graphDB.shutdown(); StatusDisplayer.getDefault().setStatusText(NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ExportTaskFinished", databasePanel.getRemoteUrl())); } }); } } }); String debugMenuLabel = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_DebugMenuLabel"); debug = new JMenuItem(new AbstractAction(debugMenuLabel) { public void actionPerformed(ActionEvent e) { JFileChooser fileChooser = new JFileChooser(); String chooseDebugFileDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_ChooseDebugFileDialogTitle"); fileChooser.setDialogTitle(chooseDebugFileDialogTitle); fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setFileFilter(new Neo4jDebugFileFilter()); fileChooser.setFileView(new Neo4jDebugFileView()); fileChooser.setAccessory(new DebugFileChooserComponent(fileChooser)); int dialogResult = fileChooser.showOpenDialog(null); if (dialogResult == JFileChooser.CANCEL_OPTION) { return; } File neo4jDebugFile = fileChooser.getSelectedFile(); FileSystemClassLoader classLoader = Lookup.getDefault().lookup(FileSystemClassLoader.class); Class<?> loadedClass = null; try { loadedClass = classLoader.loadClass(neo4jDebugFile, enabled, Neo4jDelegateNodeDebugger.class); } catch (ClassNotFoundException cnfe) { showWarningMessage(); return; } catch (NoClassDefFoundError ncdfe) { showWarningMessage(); return; } catch (ClassNotFulfillRequirementsException cnfre) { showWarningMessage(); return; } catch (IllegalArgumentException iae) { showWarningMessage(); return; } Neo4jDelegateNodeDebugger neo4jDebugger = null; try { neo4jDebugger = (Neo4jDelegateNodeDebugger) loadedClass.newInstance(); } catch (IllegalAccessException iae) { throw new AssertionError(); } catch (InstantiationException ie) { throw new AssertionError(); } // see GraphRestoration JavaDoc GraphRestoration graphRestoration = new GraphRestoration(); previousEdgeHasUniColor = VizController.getInstance().getVizModel().isEdgeHasUniColor(); VizController.getInstance().getVizModel().setEdgeHasUniColor(true); String debugDialogTitle = NbBundle.getMessage(Neo4jMenuAction.class, "CTL_Neo4j_DebugOptionsDialogTitle"); DialogDescriptor dialog = new DialogDescriptor(new DebugPanel(new MutableNeo4jDelegateNodeDebugger(neo4jDebugger)), debugDialogTitle, false, graphRestoration); dialog.addPropertyChangeListener(graphRestoration); DialogDisplayer.getDefault().notify(dialog); } }); menu.add(localFullImport); menu.add(localTraversalImport); menu.add(remoteImport); menu.addSeparator(); localExport.setEnabled(false); menu.add(localExport); remoteExport.setEnabled(false); menu.add(remoteExport); menu.addSeparator(); debug.setEnabled(false); menu.add(debug); } private void showWarningMessage() { NotifyDescriptor notifyDescriptor = new NotifyDescriptor.Message("Selected file is not valid Neo4j debug file.", JOptionPane.WARNING_MESSAGE); DialogDisplayer.getDefault().notify(notifyDescriptor); } private void initProject() { ProjectController projectController = Lookup.getDefault().lookup(ProjectController.class); if (projectController.getCurrentProject() == null) { ProjectControllerUI projectControllerUI = Lookup.getDefault().lookup(ProjectControllerUI.class); projectControllerUI.newProject(); } } /* * This class is needed because of NetBeans platform. Action listener is used for * cases when user clicks OK/Cancel button. PropertyChangeListener is used for cases * when user clicks Cancel/Close button. * * We want to restore graph in all 3 cases, so we need to implement and register both * interfaces. */ private class GraphRestoration implements PropertyChangeListener, ActionListener { private final Neo4jVisualDebugger neo4jVisualDebugger = Lookup.getDefault().lookup(Neo4jVisualDebugger.class); @Override public void propertyChange(PropertyChangeEvent evt) { neo4jVisualDebugger.restore(); VizController.getInstance().getVizModel().setEdgeHasUniColor(previousEdgeHasUniColor); } @Override public void actionPerformed(ActionEvent e) { neo4jVisualDebugger.restore(); VizController.getInstance().getVizModel().setEdgeHasUniColor(previousEdgeHasUniColor); } } }