/*
* Copyright 2015 Igor Maznitsa.
*
* 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 com.igormaznitsa.ideamindmap.editor;
import com.igormaznitsa.ideamindmap.facet.MindMapFacet;
import com.igormaznitsa.ideamindmap.settings.MindMapApplicationSettings;
import com.igormaznitsa.ideamindmap.settings.MindMapSettingsComponent;
import com.igormaznitsa.ideamindmap.swing.*;
import com.igormaznitsa.ideamindmap.utils.IdeaUtils;
import com.igormaznitsa.meta.annotation.MustNotContainNull;
import com.igormaznitsa.mindmap.model.*;
import com.igormaznitsa.mindmap.model.logger.Logger;
import com.igormaznitsa.mindmap.model.logger.LoggerFactory;
import com.igormaznitsa.mindmap.plugins.api.CustomJob;
import com.igormaznitsa.mindmap.plugins.api.PopUpMenuItemPlugin;
import com.igormaznitsa.mindmap.plugins.misc.AboutPlugin;
import com.igormaznitsa.mindmap.plugins.misc.OptionsPlugin;
import com.igormaznitsa.mindmap.plugins.processors.ExtraFilePlugin;
import com.igormaznitsa.mindmap.plugins.processors.ExtraJumpPlugin;
import com.igormaznitsa.mindmap.plugins.processors.ExtraNotePlugin;
import com.igormaznitsa.mindmap.plugins.processors.ExtraURIPlugin;
import com.igormaznitsa.mindmap.plugins.tools.ChangeColorPlugin;
import com.igormaznitsa.mindmap.swing.panel.*;
import com.igormaznitsa.mindmap.swing.panel.ui.AbstractElement;
import com.igormaznitsa.mindmap.swing.panel.ui.ElementPart;
import com.igormaznitsa.mindmap.swing.panel.utils.Utils;
import com.intellij.openapi.options.ShowSettingsUtil;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.*;
import java.awt.*;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.ResourceBundle;
public class MindMapPanelControllerImpl implements MindMapPanelController, MindMapConfigListener {
private static final ResourceBundle BUNDLE = java.util.ResourceBundle.getBundle("/i18n/Bundle");
private static final Logger LOGGER = LoggerFactory.getLogger(MindMapPanelControllerImpl.class);
private static final String FILELINK_ATTR_OPEN_IN_SYSTEM = "useSystem"; //NOI18N
private final MindMapDocumentEditor editor;
private final MindMapDialogProvider dialogProvider;
public MindMapPanelControllerImpl(final MindMapDocumentEditor editor) {
this.editor = editor;
this.dialogProvider = new MindMapDialogProvider(editor.getProject());
MindMapApplicationSettings.findInstance().getConfig().addConfigurationListener(this);
}
public MindMapDialogProvider getDialogProvider() {
return this.dialogProvider;
}
public MindMapDocumentEditor getEditor() {
return this.editor;
}
@Override
public boolean isUnfoldCollapsedTopicDropTarget(@Nonnull final MindMapPanel mindMapPanel) {
final MindMapFacet facet = this.editor.findFacet();
return facet == null || facet.getConfiguration().isUnfoldTopicWhenItIsDropTarget();
}
@Override
public boolean isCopyColorInfoFromParentToNewChildAllowed(@Nonnull final MindMapPanel mindMapPanel) {
final MindMapFacet facet = this.editor.findFacet();
return facet == null || facet.getConfiguration().isCopyColorInformationFromParent();
}
@Override
public boolean isSelectionAllowed(@Nonnull final MindMapPanel mindMapPanel) {
return true;
}
@Override
public boolean isElementDragAllowed(@Nonnull MindMapPanel mindMapPanel) {
return true;
}
@Override
public boolean isMouseMoveProcessingAllowed(@Nonnull MindMapPanel mindMapPanel) {
return true;
}
@Override
public boolean isMouseWheelProcessingAllowed(@Nonnull MindMapPanel mindMapPanel) {
return true;
}
@Override
public boolean isMouseClickProcessingAllowed(@Nonnull MindMapPanel mindMapPanel) {
return true;
}
@Override
@Nonnull
public MindMapPanelConfig provideConfigForMindMapPanel(@Nonnull MindMapPanel mindMapPanel) {
return MindMapApplicationSettings.findInstance().getConfig();
}
private Map<Class<? extends PopUpMenuItemPlugin>, CustomJob> customProcessors = null;
private Map<Class<? extends PopUpMenuItemPlugin>, CustomJob> getCustomProcessors() {
if (this.customProcessors == null) {
this.customProcessors = new HashMap<Class<? extends PopUpMenuItemPlugin>, CustomJob>();
this.customProcessors.put(ExtraNotePlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
editTextForTopic(topic);
panel.requestFocus();
}
});
this.customProcessors.put(ExtraFilePlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
editFileLinkForTopic(topic);
panel.requestFocus();
}
});
this.customProcessors.put(ExtraURIPlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
editLinkForTopic(topic);
panel.requestFocus();
}
});
this.customProcessors.put(ExtraJumpPlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
editTopicLinkForTopic(topic);
panel.requestFocus();
}
});
this.customProcessors.put(ChangeColorPlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
processColorDialogForTopics(panel, selectedTopics.length > 0 ? selectedTopics : new Topic[]{topic});
}
});
this.customProcessors.put(AboutPlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
showAbout();
}
});
this.customProcessors.put(OptionsPlugin.class, new CustomJob() {
@Override
public void doJob(@Nonnull final PopUpMenuItemPlugin plugin, @Nonnull final MindMapPanel panel, @Nonnull final DialogProvider dialogProvider, @Nullable final Topic topic, @Nullable @MustNotContainNull final Topic[] selectedTopics) {
startOptionsEdit();
}
});
}
return this.customProcessors;
}
@Override
public JPopupMenu makePopUpForMindMapPanel(@Nonnull final MindMapPanel source, @Nonnull final Point point, @Nullable final AbstractElement element, @Nullable final ElementPart partUnderMouse) {
return Utils.makePopUp(source, this.dialogProvider, element == null ? null : element.getModel(), source.getSelectedTopics(), getCustomProcessors());
}
private void startOptionsEdit() {
final Runnable action = new Runnable() {
@Override
public void run() {
ShowSettingsUtil.getInstance().showSettingsDialog(editor.getProject(), MindMapSettingsComponent.DISPLAY_NAME);
}
};
if (!IdeaUtils.submitTransactionLater(action)){
SwingUtilities.invokeLater(action);
}
}
private void editLinkForTopic(final Topic topic) {
final ExtraLink link = (ExtraLink) topic.getExtras().get(Extra.ExtraType.LINK);
final MMapURI result;
if (link == null) {
// create new
result = IdeaUtils.editURI(this.editor, String.format(BUNDLE.getString("MMDGraphEditor.editLinkForTopic.dlgAddURITitle"), Utils.makeShortTextVersion(topic.getText(), 16)), null);
}
else {
// edit
result = IdeaUtils.editURI(this.editor, String.format(BUNDLE.getString("MMDGraphEditor.editLinkForTopic.dlgEditURITitle"), Utils.makeShortTextVersion(topic.getText(), 16)), link.getValue());
}
if (result != null) {
if (result == IdeaUtils.EMPTY_URI) {
topic.removeExtra(Extra.ExtraType.LINK);
}
else {
topic.setExtra(new ExtraLink(result));
}
final MindMapPanel mindMapPanel = this.editor.getMindMapPanel();
mindMapPanel.invalidate();
mindMapPanel.repaint();
this.editor.onMindMapModelChanged(mindMapPanel);
}
}
private void editTopicLinkForTopic(final Topic topic) {
final MindMapPanel mindMapPanel = this.editor.getMindMapPanel();
final ExtraTopic link = (ExtraTopic) topic.getExtras().get(Extra.ExtraType.TOPIC);
ExtraTopic result = null;
final ExtraTopic remove = new ExtraTopic("_______"); //NOI18N
if (link == null) {
final MindMapTreePanel treePanel = new MindMapTreePanel(mindMapPanel.getModel(), null, true, null);
if (IdeaUtils.plainMessageOkCancel(this.editor.getProject(), BUNDLE.getString("MMDGraphEditor.editTopicLinkForTopic.dlgSelectTopicTitle"), treePanel)) {
final Topic selected = treePanel.getSelectedTopic();
treePanel.dispose();
if (selected != null) {
result = ExtraTopic.makeLinkTo(mindMapPanel.getModel(), selected);
}
else {
result = remove;
}
}
}
else {
final MindMapTreePanel panel = new MindMapTreePanel(mindMapPanel.getModel(), link, true, null);
if (IdeaUtils.plainMessageOkCancel(this.editor.getProject(), BUNDLE.getString("MMDGraphEditor.editTopicLinkForTopic.dlgEditSelectedTitle"), panel)) {
final Topic selected = panel.getSelectedTopic();
if (selected != null) {
result = ExtraTopic.makeLinkTo(mindMapPanel.getModel(), selected);
}
else {
result = remove;
}
}
}
if (result != null) {
if (result == remove) {
topic.removeExtra(Extra.ExtraType.TOPIC);
}
else {
topic.setExtra(result);
}
mindMapPanel.invalidate();
mindMapPanel.repaint();
this.editor.onMindMapModelChanged(mindMapPanel);
}
}
private void editFileLinkForTopic(final Topic topic) {
final ExtraFile file = (ExtraFile) topic.getExtras().get(Extra.ExtraType.FILE);
final FileEditPanel.DataContainer path;
final File projectFolder = IdeaUtils.vfile2iofile(this.editor.findRootFolderForEditedFile());
if (projectFolder == null){
LOGGER.error("Can't find root folder for project or module!");
dialogProvider.msgError("Can't find the project or module root folder!");
return;
}
if (file == null) {
path = IdeaUtils.editFilePath(this.editor, BUNDLE.getString("MMDGraphEditor.editFileLinkForTopic.dlgTitle"), projectFolder, null);
}
else {
final MMapURI uri = file.getValue();
final boolean flagOpenInSystem = Boolean.parseBoolean(uri.getParameters().getProperty(FILELINK_ATTR_OPEN_IN_SYSTEM, "false")); //NOI18N
final FileEditPanel.DataContainer origPath;
origPath = new FileEditPanel.DataContainer(uri.asFile(projectFolder).getAbsolutePath(), flagOpenInSystem);
path = IdeaUtils.editFilePath(this.editor, BUNDLE.getString("MMDGraphEditor.editFileLinkForTopic.addPathTitle"), projectFolder, origPath);
}
if (path != null) {
final boolean changed;
if (path.isEmpty()) {
changed = topic.removeExtra(Extra.ExtraType.FILE);
}
else {
final Properties props = new Properties();
if (path.isShowWithSystemTool()) {
props.put(FILELINK_ATTR_OPEN_IN_SYSTEM, "true"); //NOI18N
}
final MMapURI fileUri = MMapURI.makeFromFilePath(this.editor.isMakeRelativePath() ? projectFolder : null, path.getPath(), props); //NOI18N
final File theFile = fileUri.asFile(projectFolder);
LOGGER.info(String.format("Path %s converted to uri: %s", path.getPath(), fileUri.asString(false, true))); //NOI18N
if (theFile.exists()) {
topic.setExtra(new ExtraFile(fileUri));
changed = true;
}
else {
dialogProvider.msgError(String.format(BUNDLE.getString("MMDGraphEditor.editFileLinkForTopic.errorCantFindFile"), path.getPath()));
changed = false;
}
}
if (changed) {
final MindMapPanel mindMapPanel = this.editor.getMindMapPanel();
mindMapPanel.invalidate();
mindMapPanel.repaint();
this.editor.onMindMapModelChanged(mindMapPanel);
}
}
}
private void processColorDialogForTopics(final MindMapPanel source, final Topic[] topics) {
final Color borderColor = IdeaUtils.extractCommonColorForColorChooserButton(StandardTopicAttribute.ATTR_BORDER_COLOR.getText(), topics);
final Color fillColor = IdeaUtils.extractCommonColorForColorChooserButton(StandardTopicAttribute.ATTR_FILL_COLOR.getText(), topics);
final Color textColor = IdeaUtils.extractCommonColorForColorChooserButton(StandardTopicAttribute.ATTR_TEXT_COLOR.getText(), topics);
final ColorAttributePanel panel = new ColorAttributePanel(getDialogProvider(), borderColor, fillColor, textColor);
if (IdeaUtils.plainMessageOkCancel(this.editor.getProject(), String.format(BUNDLE.getString("MMDGraphEditor.colorEditDialogTitle"), topics.length), panel)) {
ColorAttributePanel.Result result = panel.getResult();
if (result.getBorderColor() != ColorChooserButton.DIFF_COLORS) {
Utils.setAttribute(StandardTopicAttribute.ATTR_BORDER_COLOR.getText(), Utils.color2html(result.getBorderColor(), false), topics);
}
if (result.getTextColor() != ColorChooserButton.DIFF_COLORS) {
Utils.setAttribute(StandardTopicAttribute.ATTR_TEXT_COLOR.getText(), Utils.color2html(result.getTextColor(), false), topics);
}
if (result.getFillColor() != ColorChooserButton.DIFF_COLORS) {
Utils.setAttribute(StandardTopicAttribute.ATTR_FILL_COLOR.getText(), Utils.color2html(result.getFillColor(), false), topics);
}
source.updateView(true);
}
}
private void editTextForTopic(final Topic topic) {
final ExtraNote note = (ExtraNote) topic.getExtras().get(Extra.ExtraType.NOTE);
final String result;
if (note == null) {
// create new
result = IdeaUtils
.editText(this.editor.getProject(), String.format(BUNDLE.getString("MMDGraphEditor.editTextForTopic.dlfAddNoteTitle"), Utils.makeShortTextVersion(topic.getText(), 16)),
""); //NOI18N
}
else {
// edit
result = IdeaUtils
.editText(this.editor.getProject(), String.format(BUNDLE.getString("MMDGraphEditor.editTextForTopic.dlgEditNoteTitle"), Utils.makeShortTextVersion(topic.getText(), 16)),
note.getValue());
}
if (result != null) {
if (result.isEmpty()) {
topic.removeExtra(Extra.ExtraType.NOTE);
}
else {
topic.setExtra(new ExtraNote(result));
}
this.editor.getMindMapPanel().invalidate();
this.editor.getMindMapPanel().repaint();
this.editor.onMindMapModelChanged(this.editor.getMindMapPanel());
}
}
public void showAbout() {
AboutForm.show(this.editor.getProject());
}
@Override
@Nonnull
public DialogProvider getDialogProvider(@Nonnull final MindMapPanel mindMapPanel) {
return this.dialogProvider;
}
@Override
public boolean processDropTopicToAnotherTopic(@Nonnull final MindMapPanel source, @Nonnull final Point dropPoint, @Nonnull final Topic draggedTopic, @Nullable final Topic destinationTopic) {
boolean result = false;
if (draggedTopic != null && destinationTopic != null && draggedTopic != destinationTopic) {
if (destinationTopic.getExtras().containsKey(Extra.ExtraType.TOPIC)) {
if (!getDialogProvider()
.msgConfirmOkCancel(BUNDLE.getString("MMDGraphEditor.addTopicToElement.confirmTitle"), BUNDLE.getString("MMDGraphEditor.addTopicToElement.confirmMsg"))) {
return result;
}
}
final ExtraTopic topicLink = ExtraTopic.makeLinkTo(this.editor.getMindMapPanel().getModel(), draggedTopic);
destinationTopic.setExtra(topicLink);
result = true;
}
return result;
}
@Override public void onConfigurationPropertyChanged(@Nonnull final MindMapPanelConfig mindMapPanelConfig) {
this.editor.refreshConfiguration();
}
}