/* * 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.settings; import com.igormaznitsa.ideamindmap.swing.AboutForm; import com.igormaznitsa.ideamindmap.swing.ColorChooserButton; import com.igormaznitsa.ideamindmap.swing.FontSelector; import com.igormaznitsa.ideamindmap.swing.KeyShortCutEditPanel; import com.igormaznitsa.mindmap.model.logger.Logger; import com.igormaznitsa.mindmap.model.logger.LoggerFactory; import com.igormaznitsa.mindmap.swing.panel.MindMapPanelConfig; import com.igormaznitsa.mindmap.swing.panel.utils.KeyShortcut; import com.igormaznitsa.mindmap.swing.panel.utils.PropertiesPreferences; import com.intellij.openapi.ui.DialogWrapper; import org.apache.commons.io.FileUtils; import javax.annotation.Nullable; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JPanel; import javax.swing.JSlider; import javax.swing.JSpinner; import javax.swing.SpinnerModel; import javax.swing.SpinnerNumberModel; import javax.swing.filechooser.FileFilter; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Font; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.io.File; import java.util.*; import java.util.prefs.Preferences; public class MindMapSettingsPanel { private JPanel mainPanel; private JSpinner spinnerGridStep; private JCheckBox checkBoxShowGrid; private ColorChooserButton colorButtonGridColor; private ColorChooserButton colorButtonBackgroundColor; private JSpinner spinnerConnectorWidth; private JSpinner spinnerJumpLinkWidth; private JSpinner spinnerCollapsatorSize; private JSpinner spinnerCollapsatorWidth; private ColorChooserButton colorButtonCollapsatorFill; private ColorChooserButton colorButtonJumpLink; private ColorChooserButton colorButtonCollapsatorBorder; private ColorChooserButton colorButtonConnectorColor; private JSpinner spinnerSelectionFrameWidth; private JSpinner spinnerSelectionFrameGap; private ColorChooserButton colorButtonSelectFrameColor; private JCheckBox checkBoxDropShadow; private JSlider slider1stLevelHorzGap; private JSlider slider1stLevelVertGap; private JSlider slider2ndLevelHorzGap; private JSlider slider2ndLevelVertGap; private JSpinner spinnerBorderWidth; private JButton buttonFont; private JButton buttonAbout; private ColorChooserButton colorButtonRootFill; private ColorChooserButton colorButtonRootText; private ColorChooserButton colorButton1stLevelFill; private ColorChooserButton colorButton1stLevelText; private ColorChooserButton colorButton2ndLevelFill; private ColorChooserButton colorButton2ndLevelText; private JButton buttonEditKeyShortcuts; private JCheckBox checkBoxScalingModifierALT; private JCheckBox checkBoxScalingModifierCTRL; private JCheckBox checkBoxScalingModifierSHFT; private JCheckBox checkBoxScalingModifierMETA; private JButton buttonResetSettings; private JButton buttonExportSettings; private JButton buttonImportSettings; private static final Logger LOGGER = LoggerFactory.getLogger(MindMapSettingsPanel.class); private final MindMapSettingsComponent controller; private static File lastExportedSettingsFile; private static File lastImportedSettingsFile; private static final class PropertiesFileFilter extends FileFilter { @Override public boolean accept(final File f) { return f.isDirectory() || f.getName().toLowerCase(Locale.ENGLISH).endsWith(".properties"); } @Override public String getDescription() { return "Java properties file (*.properties)"; } } private final MindMapPanelConfig etalon = new MindMapPanelConfig(); private Font theFont; private final Map<String,KeyShortcut> mapKeyShortCuts = new TreeMap<String,KeyShortcut>(new Comparator<String>(){ @Override public int compare(String o1, String o2) { return o1.compareTo(o2); } }); private static class DialogComponent extends DialogWrapper { private final JComponent component; public DialogComponent(final Component parent, final String title, final Component component) { super(parent, true); final JPanel panel = new JPanel(new BorderLayout(0, 0)); panel.add(component, BorderLayout.CENTER); this.component = panel; init(); setTitle(title); pack(); } @Override @Nullable protected JComponent createCenterPanel() { return this.component; } } public MindMapSettingsPanel(final MindMapSettingsComponent controller) { this.controller = controller; this.spinnerGridStep.setModel(makeIntSpinnerModel(2, 500, 1)); this.spinnerConnectorWidth.setModel(makeFloatSpinnerModel(0.05f, 20.0f, 0.01f)); this.spinnerJumpLinkWidth.setModel(makeFloatSpinnerModel(0.05f, 20.0f, 0.01f)); this.spinnerCollapsatorSize.setModel(makeIntSpinnerModel(3, 500, 1)); this.spinnerCollapsatorWidth.setModel(makeFloatSpinnerModel(0.01f, 100.0f, 0.1f)); this.spinnerSelectionFrameWidth.setModel(makeFloatSpinnerModel(0.02f, 100.0f, 0.1f)); this.spinnerSelectionFrameGap.setModel(makeIntSpinnerModel(1, 500, 1)); this.spinnerBorderWidth.setModel(makeFloatSpinnerModel(0.05f, 50.0f, 0.1f)); buttonAbout.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { AboutForm.show(mainPanel); } }); buttonResetSettings.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { loadFieldsFrom(new MindMapPanelConfig()); } }); buttonImportSettings.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final File file = controller.getDialogProvider().msgOpenFileDialog("importSettings", "Import settings", lastImportedSettingsFile, true, new PropertiesFileFilter(), "Open"); if (file != null) { lastImportedSettingsFile = file; try { final Preferences prefs = (new PropertiesPreferences("IDEA MindMap plugin", FileUtils.readFileToString(file))); final MindMapPanelConfig loadedConfig = new MindMapPanelConfig(); loadedConfig.loadFrom(prefs); loadFieldsFrom(loadedConfig); } catch (final Exception ex) { LOGGER.error("Can't import settings", ex); controller.getDialogProvider().msgError("Can't import settings [" + ex.getMessage() + ']'); } } } }); buttonExportSettings.addActionListener(new ActionListener() { @Override public void actionPerformed(final ActionEvent e) { File file = controller.getDialogProvider().msgSaveFileDialog("exportSettings", "Export settings", lastExportedSettingsFile, true, new PropertiesFileFilter(), "Save"); if (file != null) { lastExportedSettingsFile = file; if (!file.getName().toLowerCase(Locale.ENGLISH).endsWith(".properties")) { final Boolean addExt = controller.getDialogProvider().msgConfirmYesNoCancel("Add extension", "Add '.properties' extension?"); if (addExt == null) { return; } if (addExt) { file = new File(file.getAbsolutePath() + ".properties"); } } if (file.exists() && !controller.getDialogProvider().msgConfirmOkCancel("Override file", String.format("File %s exists, to override it?", file.getName()))) { return; } final PropertiesPreferences prefs = new PropertiesPreferences("IDEA MindMap plugin"); final MindMapPanelConfig cfg = makeConfig(); cfg.saveTo(prefs); try { FileUtils.write(file, prefs.toString()); } catch (final Exception ex) { LOGGER.error("Can't export settings", ex); controller.getDialogProvider().msgError("Can't export settings [" + ex.getMessage() + ']'); } } } }); buttonFont.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { final FontSelector fontSelector = new FontSelector(theFont); if (new DialogComponent(mainPanel, "Select font", fontSelector.getPanel()).showAndGet()) { theFont = fontSelector.getValue(); updateFontButton(); } } }); buttonEditKeyShortcuts.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent evt) { final List<KeyShortcut> list = new ArrayList<KeyShortcut>(); for(final Map.Entry<String,KeyShortcut> e : mapKeyShortCuts.entrySet()){ list.add(e.getValue()); } final KeyShortCutEditPanel editPanel = new KeyShortCutEditPanel(list); if (new DialogComponent(mainPanel, "Edit shortcuts", editPanel).showAndGet()){ for(final KeyShortcut k : editPanel.getResult()){ mapKeyShortCuts.put(k.getID(),k); } } } }); } private static double toDouble(final Number number){ return number.doubleValue(); } public void reset(final MindMapPanelConfig config) { this.etalon.makeFullCopyOf(config, false, false); loadFieldsFrom(this.etalon); } public void loadFieldsFrom(final MindMapPanelConfig config) { this.colorButtonBackgroundColor.setValue(config.getPaperColor()); this.colorButtonGridColor.setValue(config.getGridColor()); this.colorButtonCollapsatorFill.setValue(config.getCollapsatorBackgroundColor()); this.colorButtonCollapsatorBorder.setValue(config.getCollapsatorBorderColor()); this.colorButtonConnectorColor.setValue(config.getConnectorColor()); this.colorButtonJumpLink.setValue(config.getJumpLinkColor()); this.colorButtonSelectFrameColor.setValue(config.getSelectLineColor()); this.colorButtonRootFill.setValue(config.getRootBackgroundColor()); this.colorButtonRootText.setValue(config.getRootTextColor()); this.colorButton1stLevelFill.setValue(config.getFirstLevelBackgroundColor()); this.colorButton1stLevelText.setValue(config.getFirstLevelTextColor()); this.colorButton2ndLevelFill.setValue(config.getOtherLevelBackgroundColor()); this.colorButton2ndLevelText.setValue(config.getOtherLevelTextColor()); this.checkBoxShowGrid.setSelected(config.isShowGrid()); this.checkBoxDropShadow.setSelected(config.isDropShadow()); this.checkBoxScalingModifierALT.setSelected((config.getScaleModifiers() & KeyEvent.ALT_MASK)!=0); this.checkBoxScalingModifierCTRL.setSelected((config.getScaleModifiers() & KeyEvent.CTRL_MASK)!=0); this.checkBoxScalingModifierMETA.setSelected((config.getScaleModifiers() & KeyEvent.META_MASK)!=0); this.checkBoxScalingModifierSHFT.setSelected((config.getScaleModifiers() & KeyEvent.SHIFT_MASK)!=0); this.spinnerGridStep.setValue(config.getGridStep()); this.spinnerCollapsatorSize.setValue(config.getCollapsatorSize()); this.spinnerCollapsatorWidth.setValue(toDouble(config.getCollapsatorBorderWidth())); this.spinnerConnectorWidth.setValue(toDouble(config.getConnectorWidth())); this.spinnerJumpLinkWidth.setValue(toDouble(config.getJumpLinkWidth())); this.spinnerSelectionFrameWidth.setValue(toDouble(config.getSelectLineWidth())); this.spinnerSelectionFrameGap.setValue(config.getSelectLineGap()); this.spinnerBorderWidth.setValue(toDouble(config.getElementBorderWidth())); this.slider1stLevelHorzGap.setValue(config.getFirstLevelHorizontalInset()); this.slider1stLevelVertGap.setValue(config.getFirstLevelVerticalInset()); this.slider2ndLevelHorzGap.setValue(config.getOtherLevelHorizontalInset()); this.slider2ndLevelVertGap.setValue(config.getOtherLevelVerticalInset()); this.theFont = config.getFont(); this.mapKeyShortCuts.clear(); for(final Map.Entry<String,KeyShortcut> e : config.getKeyShortcutMap().entrySet()){ this.mapKeyShortCuts.put(e.getKey(),e.getValue()); } updateFontButton(); } private void updateFontButton() { final String strStyle; if (theFont.isBold()) { strStyle = theFont.isItalic() ? "bolditalic" : "bold"; } else { strStyle = theFont.isItalic() ? "italic" : "plain"; } this.buttonFont.setText(theFont.getFamily() + ", " + strStyle + ", " + theFont.getSize()); } private static int getInt(final JSpinner spinner) { return ((Number) spinner.getValue()).intValue(); } private static float getFloat(final JSpinner spinner) { return ((Number) spinner.getValue()).floatValue(); } private static SpinnerModel makeIntSpinnerModel(final int min, final int max, final int step) { return new SpinnerNumberModel(min, min, max, step); } private static SpinnerModel makeFloatSpinnerModel(final double min, final double max, final double step) { return new SpinnerNumberModel(min, min, max, step); } public JPanel getPanel() { return this.mainPanel; } private void createUIComponents() { colorButtonBackgroundColor = new ColorChooserButton(); colorButtonGridColor = new ColorChooserButton(); colorButtonCollapsatorBorder = new ColorChooserButton(); colorButtonCollapsatorFill = new ColorChooserButton(); colorButtonJumpLink = new ColorChooserButton(); colorButtonConnectorColor = new ColorChooserButton(); colorButtonSelectFrameColor = new ColorChooserButton(); colorButtonRootFill = new ColorChooserButton(); colorButtonRootText = new ColorChooserButton(); colorButton1stLevelFill = new ColorChooserButton(); colorButton1stLevelText = new ColorChooserButton(); colorButton2ndLevelFill = new ColorChooserButton(); colorButton2ndLevelText = new ColorChooserButton(); } public MindMapPanelConfig makeConfig() { final MindMapPanelConfig result = new MindMapPanelConfig(this.etalon, false); result.setPaperColor(this.colorButtonBackgroundColor.getValue()); result.setGridColor(this.colorButtonGridColor.getValue()); result.setCollapsatorBackgroundColor(this.colorButtonCollapsatorFill.getValue()); result.setCollapsatorBorderColor(this.colorButtonCollapsatorBorder.getValue()); result.setConnectorColor(this.colorButtonConnectorColor.getValue()); result.setJumpLinkColor(this.colorButtonJumpLink.getValue()); result.setSelectLineColor(this.colorButtonSelectFrameColor.getValue()); result.setRootBackgroundColor(this.colorButtonRootFill.getValue()); result.setRootTextColor(this.colorButtonRootText.getValue()); result.setFirstLevelBackgroundColor(this.colorButton1stLevelFill.getValue()); result.setFirstLevelTextColor(this.colorButton1stLevelText.getValue()); result.setOtherLevelBackgroundColor(this.colorButton2ndLevelFill.getValue()); result.setOtherLevelTextColor(this.colorButton2ndLevelText.getValue()); result.setGridStep(getInt(this.spinnerGridStep)); result.setConnectorWidth(getFloat(this.spinnerConnectorWidth)); result.setCollapsatorSize(getInt(this.spinnerCollapsatorSize)); result.setCollapsatorBorderWidth(getFloat(this.spinnerCollapsatorWidth)); result.setJumpLinkWidth(getFloat(this.spinnerJumpLinkWidth)); result.setSelectLineWidth(getFloat(this.spinnerSelectionFrameWidth)); result.setSelectLineGap(getInt(this.spinnerSelectionFrameGap)); result.setElementBorderWidth(getFloat(this.spinnerBorderWidth)); result.setShowGrid(this.checkBoxShowGrid.isSelected()); result.setDropShadow(this.checkBoxDropShadow.isSelected()); result.setFirstLevelHorizontalInset(this.slider1stLevelHorzGap.getValue()); result.setFirstLevelVerticalInset(this.slider1stLevelVertGap.getValue()); result.setOtherLevelHorizontalInset(this.slider2ndLevelHorzGap.getValue()); result.setOtherLevelVerticalInset(this.slider2ndLevelVertGap.getValue()); result.setFont(this.theFont); final int scaleModifier = (this.checkBoxScalingModifierALT.isSelected() ? KeyEvent.ALT_MASK : 0) | (this.checkBoxScalingModifierCTRL.isSelected() ? KeyEvent.CTRL_MASK: 0) | (this.checkBoxScalingModifierSHFT.isSelected() ? KeyEvent.SHIFT_MASK: 0) | (this.checkBoxScalingModifierMETA.isSelected() ? KeyEvent.META_MASK: 0); result.setScaleModifiers(scaleModifier); for(final Map.Entry<String,KeyShortcut> e : this.mapKeyShortCuts.entrySet()){ result.setKeyShortCut(e.getValue()); } return result; } public boolean isModified() { final MindMapPanelConfig current = makeConfig(); return this.etalon.hasDifferenceInParameters(current); } }