/* * Copyright (c) 2016 David Boissier. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.codinjutsu.tools.mongo.view; import com.intellij.ide.CommonActionsManager; import com.intellij.ide.TreeExpander; import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionToolbar; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.DefaultActionGroup; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.LoadingDecorator; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.ui.Splitter; import com.intellij.openapi.util.Disposer; import com.intellij.ui.NumberDocument; import com.intellij.ui.PopupHandler; import com.intellij.ui.components.panels.NonOpaquePanel; import com.mongodb.DBRef; import org.bson.Document; import org.codinjutsu.tools.mongo.ServerConfiguration; import org.codinjutsu.tools.mongo.logic.MongoManager; import org.codinjutsu.tools.mongo.logic.Notifier; import org.codinjutsu.tools.mongo.model.MongoCollection; import org.codinjutsu.tools.mongo.model.MongoCollectionResult; import org.codinjutsu.tools.mongo.model.MongoQueryOptions; import org.codinjutsu.tools.mongo.utils.GuiUtils; import org.codinjutsu.tools.mongo.view.action.*; import org.codinjutsu.tools.mongo.view.model.navigation.Navigation; import org.jetbrains.annotations.NotNull; import javax.swing.*; import java.awt.*; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; public class MongoPanel extends JPanel implements Disposable { private final LoadingDecorator loadingDecorator; private JPanel rootPanel; private Splitter splitter; private JPanel toolBar; private JPanel errorPanel; private final JTextField rowLimitField = new JTextField(""); private final MongoResultPanel resultPanel; private final QueryPanel queryPanel; private final MongoManager mongoManager; private final ServerConfiguration configuration; private final Navigation navigation; private MongoCollectionResult currentResults; public MongoPanel(Project project, final MongoManager mongoManager, final ServerConfiguration configuration, final Navigation navigation) { this.mongoManager = mongoManager; this.navigation = navigation; this.configuration = configuration; this.currentResults = new MongoCollectionResult(navigation.getCurrentWayPoint().getLabel()); errorPanel.setLayout(new BorderLayout()); queryPanel = new QueryPanel(project); queryPanel.setVisible(false); resultPanel = createResultPanel(project, Notifier.getInstance(project)); loadingDecorator = new LoadingDecorator(resultPanel, this, 0); splitter.setOrientation(true); splitter.setProportion(0.2f); splitter.setSecondComponent(loadingDecorator.getComponent()); setLayout(new BorderLayout()); add(rootPanel); initToolBar(); } private MongoResultPanel createResultPanel(Project project, Notifier notifier) { return new MongoResultPanel(project, new MongoDocumentOperations() { public Document getMongoDocument(Object _id) { return mongoManager.findMongoDocument(configuration, navigation.getCurrentWayPoint().getCollection(), _id); } public void updateMongoDocument(Document mongoDocument) { mongoManager.update(configuration, navigation.getCurrentWayPoint().getCollection(), mongoDocument); executeQuery(); } @Override public Document getReferenceDocument(String collection, Object _id, String database) { return mongoManager.findMongoDocument( configuration, new MongoCollection(collection, database != null ? database : navigation.getCurrentWayPoint().getCollection().getDatabaseName()), _id); } public void deleteMongoDocument(Object objectId) { mongoManager.delete(configuration, navigation.getCurrentWayPoint().getCollection(), objectId); executeQuery(); } }, notifier); } private void initToolBar() { toolBar.setLayout(new BorderLayout()); JPanel rowLimitPanel = createRowLimitComponent(); toolBar.add(rowLimitPanel, BorderLayout.WEST); JComponent actionToolBarComponent = createResultActionsComponent(); toolBar.add(actionToolBarComponent, BorderLayout.CENTER); JComponent viewToolbarComponent = createSelectViewActionsComponent(); toolBar.add(viewToolbarComponent, BorderLayout.EAST); } @NotNull private JPanel createRowLimitComponent() { rowLimitField.setColumns(5); rowLimitField.setDocument(new NumberDocument()); JPanel rowLimitPanel = new NonOpaquePanel(); rowLimitPanel.add(new JLabel("Row limit:"), BorderLayout.WEST); rowLimitPanel.add(rowLimitField, BorderLayout.CENTER); rowLimitPanel.add(Box.createHorizontalStrut(5), BorderLayout.EAST); return rowLimitPanel; } @NotNull private JComponent createResultActionsComponent() { DefaultActionGroup actionResultGroup = new DefaultActionGroup("MongoResultGroup", true); actionResultGroup.add(new ExecuteQuery(this)); actionResultGroup.add(new OpenFindAction(this)); actionResultGroup.add(new EnableAggregateAction(queryPanel)); actionResultGroup.addSeparator(); actionResultGroup.add(new AddMongoDocumentAction(resultPanel)); actionResultGroup.add(new EditMongoDocumentAction(resultPanel)); actionResultGroup.add(new CopyResultAction(resultPanel)); actionResultGroup.addSeparator(); actionResultGroup.add(new NavigateBackwardAction(this)); addBasicTreeActions(actionResultGroup); actionResultGroup.add(new CloseFindEditorAction(this)); ActionToolbar actionToolBar = ActionManager.getInstance().createActionToolbar("MongoResultGroupActions", actionResultGroup, true); actionToolBar.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); JComponent actionToolBarComponent = actionToolBar.getComponent(); actionToolBarComponent.setBorder(null); actionToolBarComponent.setOpaque(false); return actionToolBarComponent; } @NotNull private JComponent createSelectViewActionsComponent() { DefaultActionGroup viewSelectGroup = new DefaultActionGroup("MongoViewSelectGroup", false); viewSelectGroup.add(new ViewAsTreeAction(this)); viewSelectGroup.add(new ViewAsTableAction(this)); ActionToolbar viewToolbar = ActionManager.getInstance().createActionToolbar("MongoViewSelectedActions", viewSelectGroup, true); viewToolbar.setLayoutPolicy(ActionToolbar.AUTO_LAYOUT_POLICY); JComponent viewToolbarComponent = viewToolbar.getComponent(); viewToolbarComponent.setBorder(null); viewToolbarComponent.setOpaque(false); return viewToolbarComponent; } private void addBasicTreeActions(DefaultActionGroup actionResultGroup) { final TreeExpander treeExpander = new TreeExpander() { @Override public void expandAll() { resultPanel.expandAll(); } @Override public boolean canExpand() { return true; } @Override public void collapseAll() { resultPanel.collapseAll(); } @Override public boolean canCollapse() { return true; } }; CommonActionsManager actionsManager = CommonActionsManager.getInstance(); final AnAction expandAllAction = actionsManager.createExpandAllAction(treeExpander, resultPanel); final AnAction collapseAllAction = actionsManager.createCollapseAllAction(treeExpander, resultPanel); Disposer.register(this, new Disposable() { @Override public void dispose() { collapseAllAction.unregisterCustomShortcutSet(resultPanel); expandAllAction.unregisterCustomShortcutSet(resultPanel); } }); actionResultGroup.addSeparator(); actionResultGroup.add(expandAllAction); actionResultGroup.add(collapseAllAction); } public Navigation.WayPoint getCurrentWayPoint() { return navigation.getCurrentWayPoint(); } public void showResults() { executeQuery(); } private void executeQuery(final boolean useCachedResults, final Navigation.WayPoint wayPoint) { errorPanel.setVisible(false); validateQuery(); ApplicationManager.getApplication().executeOnPooledThread(new Runnable() { @Override public void run() { try { GuiUtils.runInSwingThread(new Runnable() { @Override public void run() { loadingDecorator.startLoading(false); } }); if (!useCachedResults) { currentResults = mongoManager.loadCollectionValues( configuration, wayPoint.getCollection(), wayPoint.getQueryOptions()); } GuiUtils.runInSwingThread(new Runnable() { @Override public void run() { resultPanel.updateResultView(currentResults); initActions(resultPanel.resultTreeTableView); } }); } catch (final Exception ex) { GuiUtils.runInSwingThread(new Runnable() { @Override public void run() { errorPanel.invalidate(); errorPanel.removeAll(); errorPanel.add(new ErrorPanel(ex), BorderLayout.CENTER); errorPanel.validate(); errorPanel.setVisible(true); } }); } finally { GuiUtils.runInSwingThread(new Runnable() { @Override public void run() { loadingDecorator.stopLoading(); } }); } } }); } private void initActions(JsonTreeTableView resultTreeTableView) { resultTreeTableView.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent mouseEvent) { if (mouseEvent.getClickCount() == 2 && resultPanel.isSelectedNodeId()) { resultPanel.editSelectedMongoDocument(); } } }); DefaultActionGroup actionPopupGroup = new DefaultActionGroup("MongoResultPopupGroup", true); if (ApplicationManager.getApplication() != null) { actionPopupGroup.add(new EditMongoDocumentAction(resultPanel)); actionPopupGroup.add(new CopyResultAction(resultPanel)); actionPopupGroup.add(new GoToMongoDocumentAction(this)); } PopupHandler.installPopupHandler(resultTreeTableView, actionPopupGroup, "POPUP", ActionManager.getInstance()); } public void executeQuery() { Navigation.WayPoint currentWayPoint = navigation.getCurrentWayPoint(); currentWayPoint.setQueryOptions(queryPanel.getQueryOptions(rowLimitField.getText())); executeQuery(false, currentWayPoint); } private void validateQuery() { queryPanel.validateQuery(); } @Override public void dispose() { resultPanel.dispose(); } public MongoResultPanel getResultPanel() { return resultPanel; } public void openFindEditor() { queryPanel.setVisible(true); splitter.setFirstComponent(queryPanel); GuiUtils.runInSwingThread(new Runnable() { @Override public void run() { focusOnEditor(); } }); } public void closeFindEditor() { splitter.setFirstComponent(null); queryPanel.setVisible(false); } public void focusOnEditor() { queryPanel.requestFocusOnEditor(); } public boolean isFindEditorOpened() { return splitter.getFirstComponent() == queryPanel; } public void setViewMode(MongoResultPanel.ViewMode viewMode) { if (resultPanel.getCurrentViewMode().equals(viewMode)) { return; } this.resultPanel.setCurrentViewMode(viewMode); executeQuery(true, navigation.getCurrentWayPoint()); } public ServerConfiguration getConfiguration() { return configuration; } public void navigateBackward() { navigation.moveBackward(); executeQuery(false, navigation.getCurrentWayPoint()); } public boolean hasNavigationHistory() { return navigation.getWayPoints().size() > 1; } public void goToReferencedDocument() { DBRef selectedDBRef = resultPanel.getSelectedDBRef(); Document referencedDocument = resultPanel.getReferencedDocument(selectedDBRef); if (referencedDocument == null) { Messages.showErrorDialog(this, "Referenced document was not found"); return; } navigation.addNewWayPoint( new MongoCollection(selectedDBRef.getCollectionName(), selectedDBRef.getDatabaseName() != null ? selectedDBRef.getDatabaseName() : navigation.getCurrentWayPoint().getCollection().getDatabaseName()), new MongoQueryOptions().setFilter( new Document("_id", selectedDBRef.getId()) )); executeQuery(false, navigation.getCurrentWayPoint()); } interface MongoDocumentOperations { Document getMongoDocument(Object _id); void deleteMongoDocument(Object mongoDocument); void updateMongoDocument(Document mongoDocument); Document getReferenceDocument(String collection, Object _id, String database); } }