@Override
  public void initialize(
      @NotNull ManagingFS managingFS, @NotNull FileWatcherNotificationSink notificationSink) {
    myManagingFS = managingFS;
    myNotificationSink = notificationSink;

    boolean disabled = Boolean.parseBoolean(System.getProperty(PROPERTY_WATCHER_DISABLED));
    myExecutable = getExecutable();

    if (disabled) {
      LOG.info("Native file watcher is disabled");
    } else if (myExecutable == null) {
      LOG.info("Native file watcher is not supported on this platform");
    } else if (!myExecutable.exists()) {
      notifyOnFailure(ApplicationBundle.message("watcher.exe.not.found"), null);
    } else if (!myExecutable.canExecute()) {
      notifyOnFailure(
          ApplicationBundle.message("watcher.exe.not.exe", myExecutable),
          new NotificationListener() {
            @Override
            public void hyperlinkUpdate(
                @NotNull Notification notification, @NotNull HyperlinkEvent event) {
              ShowFilePathAction.openFile(myExecutable);
            }
          });
    } else {
      try {
        startupProcess(false);
        LOG.info("Native file watcher is operational.");
      } catch (IOException e) {
        LOG.warn(e.getMessage());
        notifyOnFailure(ApplicationBundle.message("watcher.failed.to.start"), null);
      }
    }
  }
  private JComponent createSettingsPanel() {
    JPanel result = new JPanel(new FlowLayout(FlowLayout.RIGHT, 3, 0));
    result.add(new JLabel(ApplicationBundle.message("label.font.size")));
    myFontSizeSlider = new JSlider(JSlider.HORIZONTAL, 0, FontSize.values().length - 1, 3);
    myFontSizeSlider.setMinorTickSpacing(1);
    myFontSizeSlider.setPaintTicks(true);
    myFontSizeSlider.setPaintTrack(true);
    myFontSizeSlider.setSnapToTicks(true);
    UIUtil.setSliderIsFilled(myFontSizeSlider, true);
    result.add(myFontSizeSlider);
    result.setBorder(BorderFactory.createLineBorder(UIUtil.getBorderColor(), 1));

    myFontSizeSlider.addChangeListener(
        new ChangeListener() {
          @Override
          public void stateChanged(ChangeEvent e) {
            if (myIgnoreFontSizeSliderChange) {
              return;
            }
            EditorColorsManager colorsManager = EditorColorsManager.getInstance();
            EditorColorsScheme scheme = colorsManager.getGlobalScheme();
            scheme.setQuickDocFontSize(FontSize.values()[myFontSizeSlider.getValue()]);
            applyFontSize();
          }
        });

    String tooltipText = ApplicationBundle.message("quickdoc.tooltip.font.size.by.wheel");
    result.setToolTipText(tooltipText);
    myFontSizeSlider.setToolTipText(tooltipText);
    result.setVisible(false);
    result.setOpaque(true);
    myFontSizeSlider.setOpaque(true);
    return result;
  }
  private static boolean validateOldConfigDir(
      @Nullable File installationHome,
      @Nullable File oldConfigDir,
      @NotNull ConfigImportSettings settings) {
    if (oldConfigDir == null) {
      if (installationHome != null) {
        JOptionPane.showMessageDialog(
            JOptionPane.getRootFrame(),
            ApplicationBundle.message(
                "error.invalid.installation.home",
                installationHome.getAbsolutePath(),
                settings.getProductName(ThreeState.YES)));
      }
      return false;
    }

    if (!oldConfigDir.exists()) {
      JOptionPane.showMessageDialog(
          JOptionPane.getRootFrame(),
          ApplicationBundle.message("error.no.settings.path", oldConfigDir.getAbsolutePath()),
          ApplicationBundle.message("title.settings.import.failed"),
          JOptionPane.WARNING_MESSAGE);
      return false;
    }
    return true;
  }
  private void checkFsSanity() {
    try {
      String path = myProject.getProjectFilePath();
      if (path == null || FileUtil.isAncestor(PathManager.getConfigPath(), path, true)) {
        return;
      }

      boolean actual = FileUtil.isFileSystemCaseSensitive(path);
      LOG.info(path + " case-sensitivity: " + actual);
      if (actual != SystemInfo.isFileSystemCaseSensitive) {
        int prefix =
            SystemInfo.isFileSystemCaseSensitive ? 1 : 0; // IDE=true -> FS=false -> prefix='in'
        String title = ApplicationBundle.message("fs.case.sensitivity.mismatch.title");
        String text = ApplicationBundle.message("fs.case.sensitivity.mismatch.message", prefix);
        Notifications.Bus.notify(
            new Notification(
                Notifications.SYSTEM_MESSAGES_GROUP_ID,
                title,
                text,
                NotificationType.WARNING,
                NotificationListener.URL_OPENING_LISTENER),
            myProject);
      }
    } catch (FileNotFoundException e) {
      LOG.warn(e);
    }
  }
示例#5
0
 @Override
 public void searchResultsUpdated(SearchResults sr) {
   if (mySearchTextComponent.getText().isEmpty()) {
     updateUIWithEmptyResults();
   } else {
     int count = sr.getMatchesCount();
     boolean notTooMuch = count <= mySearchResults.getMatchesLimit();
     myMatchInfoLabel.setText(
         notTooMuch
             ? ApplicationBundle.message("editorsearch.matches", count)
             : ApplicationBundle.message(
                 "editorsearch.toomuch", mySearchResults.getMatchesLimit()));
     myClickToHighlightLabel.setVisible(!notTooMuch);
     if (notTooMuch) {
       if (count > 0) {
         setRegularBackground();
       } else {
         setNotFoundBackground();
       }
     } else {
       setRegularBackground();
     }
   }
   myReplaceActionsToolbar1.updateActionsImmediately();
 }
  @Override
  public JComponent createComponent() {
    if (myMainComponent == null) {
      myMainComponent = new JPanel(new BorderLayout());
      myCbUseSoftWrapsAtConsole =
          new JCheckBox(ApplicationBundle.message("checkbox.use.soft.wraps.at.console"), false);
      myCommandsHistoryLimitField = new JTextField(3);
      myCbOverrideConsoleCycleBufferSize =
          new JCheckBox(
              ApplicationBundle.message(
                  "checkbox.override.console.cycle.buffer.size",
                  String.valueOf(ConsoleBuffer.getLegacyCycleBufferSize() / 1024)),
              false);
      myCbOverrideConsoleCycleBufferSize.addChangeListener(
          new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent e) {
              myConsoleCycleBufferSizeField.setEnabled(
                  myCbOverrideConsoleCycleBufferSize.isSelected());
            }
          });
      myConsoleCycleBufferSizeField = new JTextField(3);

      JPanel northPanel = new JPanel(new GridBagLayout());
      GridBag gridBag = new GridBag();
      gridBag.anchor(GridBagConstraints.WEST).setDefaultAnchor(GridBagConstraints.WEST);
      northPanel.add(myCbUseSoftWrapsAtConsole, gridBag.nextLine().next());
      northPanel.add(Box.createHorizontalGlue(), gridBag.next().coverLine());
      northPanel.add(
          new JLabel(ApplicationBundle.message("editbox.console.history.limit")),
          gridBag.nextLine().next());
      northPanel.add(myCommandsHistoryLimitField, gridBag.next());
      if (ConsoleBuffer.useCycleBuffer()) {
        northPanel.add(myCbOverrideConsoleCycleBufferSize, gridBag.nextLine().next());
        northPanel.add(myConsoleCycleBufferSizeField, gridBag.next());
      }
      if (!editFoldingsOnly()) {
        JPanel wrapper = new JPanel(new BorderLayout());
        wrapper.add(northPanel, BorderLayout.WEST);
        myMainComponent.add(wrapper, BorderLayout.NORTH);
      }
      Splitter splitter = new Splitter(true);
      myMainComponent.add(splitter, BorderLayout.CENTER);
      myPositivePanel =
          new MyAddDeleteListPanel(
              "Fold console lines that contain",
              "Enter a substring of a console line you'd like to see folded:");
      myNegativePanel =
          new MyAddDeleteListPanel(
              "Exceptions", "Enter a substring of a console line you don't want to fold:");
      splitter.setFirstComponent(myPositivePanel);
      splitter.setSecondComponent(myNegativePanel);

      myPositivePanel.getEmptyText().setText("Fold nothing");
      myNegativePanel.getEmptyText().setText("No exceptions");
    }
    return myMainComponent;
  }
 protected void handleFileTooBigException(
     Logger logger, FilesTooBigForDiffException e, @NotNull PsiFile file) {
   logger.info("Error while calculating changed ranges for: " + file.getVirtualFile(), e);
   if (!ApplicationManager.getApplication().isUnitTestMode()) {
     Notification notification =
         new Notification(
             ApplicationBundle.message("reformat.changed.text.file.too.big.notification.groupId"),
             ApplicationBundle.message("reformat.changed.text.file.too.big.notification.title"),
             ApplicationBundle.message(
                 "reformat.changed.text.file.too.big.notification.text", file.getName()),
             NotificationType.INFORMATION);
     notification.notify(file.getProject());
   }
 }
  private static boolean showConfirmation() {
    final boolean hasUnsafeBgTasks = ProgressManager.getInstance().hasUnsafeProgressIndicator();

    DialogWrapper.DoNotAskOption option =
        new DialogWrapper.DoNotAskOption() {
          @Override
          public boolean isToBeShown() {
            return GeneralSettings.getInstance().isConfirmExit();
          }

          @Override
          public void setToBeShown(boolean value, int exitCode) {
            GeneralSettings.getInstance().setConfirmExit(value);
          }

          @Override
          public boolean canBeHidden() {
            return !hasUnsafeBgTasks;
          }

          @Override
          public boolean shouldSaveOptionsOnCancel() {
            return false;
          }

          @Override
          public String getDoNotShowMessage() {
            return "Do not ask me again";
          }
        };

    if (hasUnsafeBgTasks || option.isToBeShown()) {
      String message =
          ApplicationBundle.message(
              hasUnsafeBgTasks ? "exit.confirm.prompt.tasks" : "exit.confirm.prompt",
              ApplicationNamesInfo.getInstance().getFullProductName());

      if (DialogWrapper.OK_EXIT_CODE
          != Messages.showYesNoDialog(
              message,
              ApplicationBundle.message("exit.confirm.title"),
              ApplicationBundle.message("command.exit"),
              "Cancel",
              Messages.getQuestionIcon(),
              option)) {
        return false;
      }
    }
    return true;
  }
 public static void showReadOnlyMessage(JComponent parent, final boolean sharedScheme) {
   if (!sharedScheme) {
     Messages.showMessageDialog(
         parent,
         ApplicationBundle.message("error.readonly.scheme.cannot.be.modified"),
         ApplicationBundle.message("title.cannot.modify.readonly.scheme"),
         Messages.getInformationIcon());
   } else {
     Messages.showMessageDialog(
         parent,
         ApplicationBundle.message("error.shared.scheme.cannot.be.modified"),
         ApplicationBundle.message("title.cannot.modify.readonly.scheme"),
         Messages.getInformationIcon());
   }
 }
 private static void doImport(
     @NotNull File newConfigDir,
     @NotNull File oldConfigDir,
     ConfigImportSettings settings,
     File installationHome) {
   try {
     copy(oldConfigDir, newConfigDir, settings, installationHome);
   } catch (IOException e) {
     JOptionPane.showMessageDialog(
         JOptionPane.getRootFrame(),
         ApplicationBundle.message("error.unable.to.import.settings", e.getMessage()),
         ApplicationBundle.message("title.settings.import.failed"),
         JOptionPane.WARNING_MESSAGE);
   }
 }
 static {
   ORDER_TYPES.put(
       ArrangementEntryOrderType.KEEP,
       ApplicationBundle.message("arrangement.settings.order.type.keep"));
   ORDER_TYPES.put(
       ArrangementEntryOrderType.BY_NAME,
       ApplicationBundle.message("arrangement.settings.order.type.by.name"));
   ORDER_TYPES.put(
       ArrangementEntryOrderType.DEPTH_FIRST,
       ApplicationBundle.message("arrangement.settings.order.type.depth.first"));
   ORDER_TYPES.put(
       ArrangementEntryOrderType.BREADTH_FIRST,
       ApplicationBundle.message("arrangement.settings.order.type.breadth.first"));
   assert ORDER_TYPES.size() == ArrangementEntryOrderType.values().length;
 }
 static {
   GROUPING_TYPES.put(
       ArrangementGroupingType.GETTERS_AND_SETTERS,
       ApplicationBundle.message("arrangement.settings.groups.getters.and.setters.together"));
   GROUPING_TYPES.put(
       ArrangementGroupingType.OVERRIDDEN_METHODS,
       ApplicationBundle.message("arrangement.settings.groups.overridden.methods"));
   GROUPING_TYPES.put(
       ArrangementGroupingType.DEPENDENT_METHODS,
       ApplicationBundle.message("arrangement.settings.groups.dependent.methods"));
   GROUPING_TYPES.put(
       ArrangementGroupingType.GROUP_PROPERTY_FIELD_WITH_GETTER_SETTER,
       ApplicationBundle.message("arrangement.settings.groups.property.field"));
   assert GROUPING_TYPES.size() == ArrangementGroupingType.values().length;
 }
  private void startupProcess(boolean restart) throws IOException {
    if (myIsShuttingDown) {
      return;
    }
    if (ShutDownTracker.isShutdownHookRunning()) {
      myIsShuttingDown = true;
      return;
    }

    if (myStartAttemptCount++ > MAX_PROCESS_LAUNCH_ATTEMPT_COUNT) {
      notifyOnFailure(ApplicationBundle.message("watcher.failed.to.start"), null);
      return;
    }

    if (restart) {
      shutdownProcess();
    }

    LOG.info("Starting file watcher: " + myExecutable);
    ProcessBuilder processBuilder = new ProcessBuilder(myExecutable.getAbsolutePath());
    Process process = processBuilder.start();
    myProcessHandler = new MyProcessHandler(process);
    myProcessHandler.addProcessListener(new MyProcessAdapter());
    myProcessHandler.startNotify();

    if (restart) {
      List<String> recursive = myRecursiveWatchRoots;
      List<String> flat = myFlatWatchRoots;
      if (recursive.size() + flat.size() > 0) {
        setWatchRoots(recursive, flat, true);
      }
    }
  }
  private void checkProjectRoots() {
    LocalFileSystem fs = LocalFileSystem.getInstance();
    if (!(fs instanceof LocalFileSystemImpl)) return;
    FileWatcher watcher = ((LocalFileSystemImpl) fs).getFileWatcher();
    if (!watcher.isOperational()) return;
    Collection<String> manualWatchRoots = watcher.getManualWatchRoots();
    if (manualWatchRoots.isEmpty()) return;
    VirtualFile[] roots = ProjectRootManager.getInstance(myProject).getContentRoots();
    if (roots.length == 0) return;

    List<String> nonWatched = new SmartList<String>();
    for (VirtualFile root : roots) {
      if (!(root.getFileSystem() instanceof LocalFileSystem)) continue;
      String rootPath = root.getPath();
      for (String manualWatchRoot : manualWatchRoots) {
        if (FileUtil.isAncestor(manualWatchRoot, rootPath, false)) {
          nonWatched.add(rootPath);
        }
      }
    }

    if (!nonWatched.isEmpty()) {
      String message = ApplicationBundle.message("watcher.non.watchable.project");
      watcher.notifyOnFailure(message, null);
      LOG.info("unwatched roots: " + nonWatched);
      LOG.info("manual watches: " + manualWatchRoots);
    }
  }
示例#15
0
  private boolean disposeSelf() {
    myDisposeInProgress = true;
    final CommandProcessor commandProcessor = CommandProcessor.getInstance();
    final Ref<Boolean> canClose = new Ref<Boolean>(Boolean.TRUE);
    for (final Project project : ProjectManagerEx.getInstanceEx().getOpenProjects()) {
      try {
        commandProcessor.executeCommand(
            project,
            new Runnable() {
              public void run() {
                canClose.set(ProjectUtil.closeAndDispose(project));
              }
            },
            ApplicationBundle.message("command.exit"),
            null);
      } catch (Throwable e) {
        LOG.error(e);
      }
      if (!canClose.get()) {
        myDisposeInProgress = false;
        return false;
      }
    }
    Disposer.dispose(this);

    Disposer.assertIsEmpty();
    return true;
  }
示例#16
0
  public EditorOptionsPanel() {
    if (SystemInfo.isMac) {
      myCbEnableWheelFontChange.setText(
          ApplicationBundle.message("checkbox.enable.ctrl.mousewheel.changes.font.size.macos"));
    }

    myStripTrailingSpacesCombo.addItem(STRIP_CHANGED);
    myStripTrailingSpacesCombo.addItem(STRIP_ALL);
    myStripTrailingSpacesCombo.addItem(STRIP_NONE);

    myHighlightSettingsPanel.setLayout(new BorderLayout());
    myHighlightSettingsPanel.add(myErrorHighlightingPanel.getPanel(), BorderLayout.CENTER);

    myRichCopyColorSchemeComboBox.setRenderer(
        new ListCellRendererWrapper<String>() {
          @Override
          public void customize(
              JList list, String value, int index, boolean selected, boolean hasFocus) {
            final String textToUse;
            if (RichCopySettings.ACTIVE_GLOBAL_SCHEME_MARKER.equals(value)) {
              textToUse = ACTIVE_COLOR_SCHEME;
            } else {
              textToUse = value;
            }
            setText(textToUse);
          }
        });

    myConfigurable = new MyConfigurable();
    initQuickDocProcessing();
    initSoftWrapsSettingsProcessing();
  }
    @Override
    public boolean iteration() {
      if (myStopFormatting) {
        return true;
      }

      if (!myFilesCountingFinished) {
        updateIndicatorText(ApplicationBundle.message("bulk.reformat.prepare.progress.text"), "");
        countingIteration();
        return true;
      }

      updateIndicatorFraction(myFilesProcessed);

      if (myFileTreeIterator.hasNext()) {
        final PsiFile file = myFileTreeIterator.next();
        myFilesProcessed++;
        if (file.isWritable() && canBeFormatted(file) && acceptedByFilters(file)) {
          updateIndicatorText(
              ApplicationBundle.message("bulk.reformat.process.progress.text"),
              getPresentablePath(file));
          ApplicationManager.getApplication()
              .runWriteAction(
                  new Runnable() {
                    @Override
                    public void run() {
                      DumbService.getInstance(myProject)
                          .withAlternativeResolveEnabled(
                              new Runnable() {
                                @Override
                                public void run() {
                                  performFileProcessing(file);
                                }
                              });
                    }
                  });
        }
      }

      return true;
    }
    @Override
    public void onTextAvailable(ProcessEvent event, Key outputType) {
      if (outputType == ProcessOutputTypes.STDERR) {
        LOG.warn(event.getText().trim());
      }
      if (outputType != ProcessOutputTypes.STDOUT) {
        return;
      }

      final String line = event.getText().trim();
      if (LOG.isDebugEnabled()) {
        LOG.debug(">> " + line);
      }

      if (myLastOp == null) {
        final WatcherOp watcherOp;
        try {
          watcherOp = WatcherOp.valueOf(line);
        } catch (IllegalArgumentException e) {
          LOG.error("Illegal watcher command: " + line);
          return;
        }

        if (watcherOp == WatcherOp.GIVEUP) {
          notifyOnFailure(ApplicationBundle.message("watcher.gave.up"), null);
          myIsShuttingDown = true;
        } else if (watcherOp == WatcherOp.RESET) {
          reset();
        } else {
          myLastOp = watcherOp;
        }
      } else if (myLastOp == WatcherOp.MESSAGE) {
        notifyOnFailure(line, NotificationListener.URL_OPENING_LISTENER);
        myLastOp = null;
      } else if (myLastOp == WatcherOp.REMAP || myLastOp == WatcherOp.UNWATCHEABLE) {
        if ("#".equals(line)) {
          if (myLastOp == WatcherOp.REMAP) {
            processRemap();
          } else {
            mySettingRoots.decrementAndGet();
            processUnwatchable();
          }
          myLines.clear();
          myLastOp = null;
        } else {
          myLines.add(line);
        }
      } else {
        String path = line.replace('\0', '\n'); // unescape
        processChange(path, myLastOp);
        myLastOp = null;
      }
    }
  public EditorOptionsPanel() {
    if (SystemInfo.isMac) {
      myCbEnableWheelFontChange.setText(
          ApplicationBundle.message("checkbox.enable.ctrl.mousewheel.changes.font.size.macos"));
    }

    myStripTrailingSpacesCombo.addItem(STRIP_CHANGED);
    myStripTrailingSpacesCombo.addItem(STRIP_ALL);
    myStripTrailingSpacesCombo.addItem(STRIP_NONE);
    ActionListener explainer =
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            explainTrailingSpaces(getStripTrailingSpacesValue());
          }
        };
    myStripTrailingSpacesCombo.addActionListener(explainer);
    myCbVirtualSpace.addActionListener(explainer);

    myHighlightSettingsPanel.setLayout(new BorderLayout());
    myHighlightSettingsPanel.add(myErrorHighlightingPanel.getPanel(), BorderLayout.CENTER);

    myCbRenameLocalVariablesInplace.setVisible(
        OptionsApplicabilityFilter.isApplicable(OptionId.RENAME_IN_PLACE));

    myRichCopyColorSchemeComboBox.setRenderer(
        new ListCellRendererWrapper<String>() {
          @Override
          public void customize(
              JList list, String value, int index, boolean selected, boolean hasFocus) {
            final String textToUse;
            if (RichCopySettings.ACTIVE_GLOBAL_SCHEME_MARKER.equals(value)) {
              textToUse = ACTIVE_COLOR_SCHEME;
            } else {
              textToUse = value;
            }
            setText(textToUse);
          }
        });

    myConfigurable = new MyConfigurable();
    initQuickDocProcessing();
    initSoftWrapsSettingsProcessing();
    initVcsSettingsProcessing();
  }
  protected TreeTable createOptionsTree(CodeStyleSettings settings) {
    DefaultMutableTreeNode rootNode = new DefaultMutableTreeNode();
    Map<String, DefaultMutableTreeNode> groupsMap = new THashMap<String, DefaultMutableTreeNode>();

    List<Option> sorted = sortOptions(ContainerUtil.concat(myOptions, myCustomOptions));
    for (Option each : sorted) {
      if (!(myCustomOptions.contains(each)
          || myAllowedOptions.contains(each.field.getName())
          || myShowAllStandardOptions)) continue;

      String group = each.groupName;
      MyTreeNode newNode = new MyTreeNode(each, each.title, settings);

      DefaultMutableTreeNode groupNode = groupsMap.get(group);
      if (groupNode != null) {
        groupNode.add(newNode);
      } else {
        String groupName;

        if (group == null) {
          groupName = each.title;
          groupNode = newNode;
        } else {
          groupName = group;
          groupNode = new DefaultMutableTreeNode(groupName);
          groupNode.add(newNode);
        }
        groupsMap.put(groupName, groupNode);
        rootNode.add(groupNode);
      }
    }

    ListTreeTableModel model = new ListTreeTableModel(rootNode, COLUMNS);
    TreeTable treeTable =
        new TreeTable(model) {
          @Override
          public TreeTableCellRenderer createTableRenderer(TreeTableModel treeTableModel) {
            TreeTableCellRenderer tableRenderer = super.createTableRenderer(treeTableModel);
            UIUtil.setLineStyleAngled(tableRenderer);
            tableRenderer.setRootVisible(false);
            tableRenderer.setShowsRootHandles(true);

            return tableRenderer;
          }

          @Override
          public TableCellRenderer getCellRenderer(int row, int column) {
            TreePath treePath = getTree().getPathForRow(row);
            if (treePath == null) return super.getCellRenderer(row, column);

            Object node = treePath.getLastPathComponent();

            @SuppressWarnings("unchecked")
            TableCellRenderer renderer = COLUMNS[column].getRenderer(node);
            return renderer == null ? super.getCellRenderer(row, column) : renderer;
          }

          @Override
          public TableCellEditor getCellEditor(int row, int column) {
            TreePath treePath = getTree().getPathForRow(row);
            if (treePath == null) return super.getCellEditor(row, column);

            Object node = treePath.getLastPathComponent();
            @SuppressWarnings("unchecked")
            TableCellEditor editor = COLUMNS[column].getEditor(node);
            return editor == null ? super.getCellEditor(row, column) : editor;
          }
        };
    new TreeTableSpeedSearch(treeTable).setComparator(new SpeedSearchComparator(false));

    treeTable.setRootVisible(false);

    final JTree tree = treeTable.getTree();
    tree.setCellRenderer(myTitleRenderer);
    tree.setShowsRootHandles(true);
    // myTreeTable.setRowHeight(new JComboBox(new String[]{"Sample
    // Text"}).getPreferredSize().height);
    treeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    treeTable.setTableHeader(null);

    expandTree(tree);

    treeTable.getColumnModel().getSelectionModel().setAnchorSelectionIndex(1);
    treeTable.getColumnModel().getSelectionModel().setLeadSelectionIndex(1);

    int maxWidth = tree.getPreferredScrollableViewportSize().width + 10;
    final TableColumn titleColumn = treeTable.getColumnModel().getColumn(0);
    titleColumn.setPreferredWidth(maxWidth);
    titleColumn.setMinWidth(maxWidth);
    titleColumn.setMaxWidth(maxWidth);
    titleColumn.setResizable(false);

    // final TableColumn levelColumn = treeTable.getColumnModel().getColumn(1);
    // TODO[max]: better preffered size...
    // TODO[kb]: Did I fixed it by making the last column floating?
    // levelColumn.setPreferredWidth(valueSize.width);
    // levelColumn.setMaxWidth(valueSize.width);
    // levelColumn.setMinWidth(valueSize.width);
    // levelColumn.setResizable(false);

    final Dimension valueSize =
        new JLabel(ApplicationBundle.message("option.table.sizing.text")).getPreferredSize();
    treeTable.setPreferredScrollableViewportSize(
        new Dimension(maxWidth + valueSize.width + 10, 20));

    return treeTable;
  }
 @Override
 protected String getTabTitle() {
   return ApplicationBundle.message("arrangement.title.settings.tab");
 }
  private static void copy(
      @NotNull File src,
      @NotNull File dest,
      ConfigImportSettings settings,
      File oldInstallationHome)
      throws IOException {
    src = src.getCanonicalFile();
    dest = dest.getCanonicalFile();
    if (!src.isDirectory()) {
      throw new IOException(
          ApplicationBundle.message(
              "config.import.invalid.directory.error", src.getAbsolutePath()));
    }
    if (!dest.isDirectory()) {
      throw new IOException(
          ApplicationBundle.message(
              "config.import.invalid.directory.error", dest.getAbsolutePath()));
    }
    if (FileUtil.filesEqual(src, dest)) {
      return;
    }

    FileUtil.ensureExists(dest);

    File[] childFiles =
        src.listFiles(
            new FilenameFilter() {
              @Override
              public boolean accept(@NotNull File dir, @NotNull String name) {
                // Don't copy plugins just imported. They're most probably incompatible with newer
                // idea version.
                return !StringUtil.startsWithChar(name, '.') && !name.equals(PLUGINS_PATH);
              }
            });

    if (childFiles == null || childFiles.length == 0) {
      return;
    }

    for (File from : childFiles) {
      File to = new File(dest, from.getName());
      if (from.isDirectory()) {
        FileUtil.copyDir(from, to, false);
      } else {
        FileUtil.copy(from, to);
      }
    }

    File plugins = new File(src, PLUGINS_PATH);
    if (!loadOldPlugins(plugins, dest) && SystemInfo.isMac) {
      File oldPluginsDir =
          getOldPath(
              oldInstallationHome,
              settings,
              PathManager.PROPERTY_PLUGINS_PATH,
              new Function<String, String>() {
                @Override
                public String fun(String pathSelector) {
                  return PathManager.getDefaultPluginPathFor(pathSelector);
                }
              });
      if (oldPluginsDir == null) {
        // e.g. installation home referred to config home. Try with default selector, same as config
        // name
        oldPluginsDir = new File(PathManager.getDefaultPluginPathFor(src.getName()));
      }
      loadOldPlugins(oldPluginsDir, dest);
    }
  }
public class ColorAndFontOptions extends SearchableConfigurable.Parent.Abstract
    implements EditorOptionsProvider {
  private HashMap<String, MyColorScheme> mySchemes;
  private MyColorScheme mySelectedScheme;
  public static final String DIFF_GROUP = ApplicationBundle.message("title.diff");
  public static final String FILE_STATUS_GROUP = ApplicationBundle.message("title.file.status");
  public static final String SCOPES_GROUP = ApplicationBundle.message("title.scope.based");

  private boolean mySomeSchemesDeleted = false;
  private Map<ColorAndFontPanelFactory, InnerSearchableConfigurable> mySubPanelFactories;

  private SchemesPanel myRootSchemesPanel;

  private boolean myInitResetCompleted = false;
  private boolean myInitResetInvoked = false;

  private boolean myRevertChangesCompleted = false;

  private boolean myApplyCompleted = false;
  private boolean myDisposeCompleted = false;
  private final Disposable myDisposable = Disposer.newDisposable();
  private static final Logger LOG =
      Logger.getInstance("#com.intellij.application.options.colors.ColorAndFontOptions");

  @Override
  public boolean isModified() {
    boolean listModified = isSchemeListModified();
    boolean schemeModified = isSomeSchemeModified();

    if (listModified || schemeModified) {
      myApplyCompleted = false;
    }

    return listModified;
  }

  private boolean isSchemeListModified() {
    if (mySomeSchemesDeleted) return true;

    if (!mySelectedScheme
        .getName()
        .equals(EditorColorsManager.getInstance().getGlobalScheme().getName())) return true;

    for (MyColorScheme scheme : mySchemes.values()) {
      if (scheme.isNew()) return true;
    }

    return false;
  }

  private boolean isSomeSchemeModified() {
    for (MyColorScheme scheme : mySchemes.values()) {
      if (scheme.isModified()) return true;
    }
    return false;
  }

  public EditorColorsScheme selectScheme(@NotNull String name) {
    mySelectedScheme = getScheme(name);
    return mySelectedScheme;
  }

  private MyColorScheme getScheme(String name) {
    return mySchemes.get(name);
  }

  public EditorColorsScheme getSelectedScheme() {
    return mySelectedScheme;
  }

  public EditorColorsScheme getOriginalSelectedScheme() {
    return mySelectedScheme == null ? null : mySelectedScheme.getOriginalScheme();
  }

  public EditorSchemeAttributeDescriptor[] getCurrentDescriptions() {
    return mySelectedScheme.getDescriptors();
  }

  public static boolean isReadOnly(@NotNull final EditorColorsScheme scheme) {
    return ((MyColorScheme) scheme).isReadOnly();
  }

  @NotNull
  public String[] getSchemeNames() {
    List<MyColorScheme> schemes = new ArrayList<MyColorScheme>(mySchemes.values());
    Collections.sort(
        schemes,
        new Comparator<MyColorScheme>() {
          @Override
          public int compare(@NotNull MyColorScheme o1, @NotNull MyColorScheme o2) {
            if (isReadOnly(o1) && !isReadOnly(o2)) return -1;
            if (!isReadOnly(o1) && isReadOnly(o2)) return 1;

            return o1.getName().compareToIgnoreCase(o2.getName());
          }
        });

    List<String> names = new ArrayList<String>(schemes.size());
    for (MyColorScheme scheme : schemes) {
      names.add(scheme.getName());
    }

    return ArrayUtil.toStringArray(names);
  }

  @NotNull
  public Collection<EditorColorsScheme> getSchemes() {
    return new ArrayList<EditorColorsScheme>(mySchemes.values());
  }

  public void saveSchemeAs(String name) {
    MyColorScheme scheme = mySelectedScheme;
    if (scheme == null) return;

    EditorColorsScheme clone = (EditorColorsScheme) scheme.getOriginalScheme().clone();

    scheme.apply(clone);

    clone.setName(name);
    MyColorScheme newScheme = new MyColorScheme(clone);
    initScheme(newScheme);

    newScheme.setIsNew();

    mySchemes.put(name, newScheme);
    selectScheme(newScheme.getName());
    resetSchemesCombo(null);
  }

  public void addImportedScheme(@NotNull final EditorColorsScheme imported) {
    MyColorScheme newScheme = new MyColorScheme(imported);
    initScheme(newScheme);

    mySchemes.put(imported.getName(), newScheme);
    selectScheme(newScheme.getName());
    resetSchemesCombo(null);
  }

  public void removeScheme(String name) {
    if (mySelectedScheme.getName().equals(name)) {
      //noinspection HardCodedStringLiteral
      selectScheme("Default");
    }

    boolean deletedNewlyCreated = false;

    MyColorScheme toDelete = mySchemes.get(name);

    if (toDelete != null) {
      deletedNewlyCreated = toDelete.isNew();
    }

    mySchemes.remove(name);
    resetSchemesCombo(null);
    mySomeSchemesDeleted = mySomeSchemesDeleted || !deletedNewlyCreated;
  }

  @Override
  public void apply() throws ConfigurationException {
    if (myApplyCompleted) {
      return;
    }
    try {
      EditorColorsManager myColorsManager = EditorColorsManager.getInstance();

      myColorsManager.removeAllSchemes();
      for (MyColorScheme scheme : mySchemes.values()) {
        if (!scheme.isDefault()) {
          scheme.apply();
          myColorsManager.addColorsScheme(scheme.getOriginalScheme());
        }
      }

      EditorColorsScheme originalScheme = mySelectedScheme.getOriginalScheme();
      myColorsManager.setGlobalScheme(originalScheme);
      if (originalScheme != null
          && DarculaLaf.NAME.equals(originalScheme.getName())
          && !UIUtil.isUnderDarcula()) {
        int ok =
            Messages.showYesNoDialog(
                "Darcula color scheme has been set for editors. Would you like to set Darcula as default Look and Feel?",
                "Darcula Look and Feel",
                Messages.getQuestionIcon());
        if (ok == Messages.YES) {
          LafManager.getInstance().setCurrentLookAndFeel(new DarculaLookAndFeelInfo());
          DarculaInstaller.install();
        }
      }
      applyChangesToEditors();

      reset();
    } finally {
      myApplyCompleted = true;
    }
  }

  private static void applyChangesToEditors() {
    EditorFactory.getInstance().refreshAllEditors();

    TodoConfiguration.getInstance().colorSettingsChanged();
    Project[] openProjects = ProjectManager.getInstance().getOpenProjects();
    for (Project openProject : openProjects) {
      FileStatusManager.getInstance(openProject).fileStatusesChanged();
      DaemonCodeAnalyzer.getInstance(openProject).restart();
    }
  }

  private boolean myIsReset = false;

  private void resetSchemesCombo(Object source) {
    myIsReset = true;
    try {
      myRootSchemesPanel.resetSchemesCombo(source);
      if (mySubPanelFactories != null) {
        for (NewColorAndFontPanel subPartialConfigurable : getPanels()) {
          subPartialConfigurable.reset(source);
        }
      }
    } finally {
      myIsReset = false;
    }
  }

  @Override
  public JComponent createComponent() {
    if (myRootSchemesPanel == null) {
      ensureSchemesPanel();
    }
    return myRootSchemesPanel;
  }

  @Override
  public boolean hasOwnContent() {
    return true;
  }

  @NotNull
  @Override
  public Configurable[] buildConfigurables() {
    myDisposeCompleted = false;
    initAll();

    List<ColorAndFontPanelFactory> panelFactories = createPanelFactories();

    List<Configurable> result = new ArrayList<Configurable>();
    mySubPanelFactories =
        new LinkedHashMap<ColorAndFontPanelFactory, InnerSearchableConfigurable>(
            panelFactories.size());
    for (ColorAndFontPanelFactory panelFactory : panelFactories) {
      mySubPanelFactories.put(panelFactory, new InnerSearchableConfigurable(panelFactory));
    }

    result.addAll(new ArrayList<SearchableConfigurable>(mySubPanelFactories.values()));
    return result.toArray(new Configurable[result.size()]);
  }

  @NotNull
  private Set<NewColorAndFontPanel> getPanels() {
    Set<NewColorAndFontPanel> result = new HashSet<NewColorAndFontPanel>();
    for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
      NewColorAndFontPanel panel = configurable.getSubPanelIfInitialized();
      if (panel != null) {
        result.add(panel);
      }
    }
    return result;
  }

  protected List<ColorAndFontPanelFactory> createPanelFactories() {
    List<ColorAndFontPanelFactory> result = new ArrayList<ColorAndFontPanelFactory>();
    result.add(new FontConfigurableFactory());

    List<ColorAndFontPanelFactory> extensions = new ArrayList<ColorAndFontPanelFactory>();
    extensions.add(new ConsoleFontConfigurableFactory());
    ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
    for (final ColorSettingsPage page : pages) {
      extensions.add(
          new ColorAndFontPanelFactoryEx() {
            @Override
            @NotNull
            public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
              final SimpleEditorPreview preview = new SimpleEditorPreview(options, page);
              return NewColorAndFontPanel.create(
                  preview, page.getDisplayName(), options, null, page);
            }

            @Override
            @NotNull
            public String getPanelDisplayName() {
              return page.getDisplayName();
            }

            @Override
            public DisplayPriority getPriority() {
              if (page instanceof DisplayPrioritySortable) {
                return ((DisplayPrioritySortable) page).getPriority();
              }
              return DisplayPriority.LANGUAGE_SETTINGS;
            }
          });
    }
    Collections.addAll(extensions, Extensions.getExtensions(ColorAndFontPanelFactory.EP_NAME));
    Collections.sort(
        extensions,
        new Comparator<ColorAndFontPanelFactory>() {
          @Override
          public int compare(ColorAndFontPanelFactory f1, ColorAndFontPanelFactory f2) {
            if (f1 instanceof DisplayPrioritySortable) {
              if (f2 instanceof DisplayPrioritySortable) {
                int result =
                    ((DisplayPrioritySortable) f1)
                        .getPriority()
                        .compareTo(((DisplayPrioritySortable) f2).getPriority());
                if (result != 0) return result;
              } else {
                return 1;
              }
            } else if (f2 instanceof DisplayPrioritySortable) {
              return -1;
            }
            return f1.getPanelDisplayName().compareToIgnoreCase(f2.getPanelDisplayName());
          }
        });
    result.addAll(extensions);

    result.add(new DiffColorsPageFactory());
    result.add(new FileStatusColorsPageFactory());
    result.add(new ScopeColorsPageFactory());

    return result;
  }

  private static class FontConfigurableFactory implements ColorAndFontPanelFactory {
    @Override
    @NotNull
    public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
      FontEditorPreview previewPanel = new FontEditorPreview(options, true);
      return new NewColorAndFontPanel(
          new SchemesPanel(options), new FontOptions(options), previewPanel, "Font", null, null) {
        @Override
        public boolean containsFontOptions() {
          return true;
        }
      };
    }

    @Override
    @NotNull
    public String getPanelDisplayName() {
      return "Font";
    }
  }

  private static class ConsoleFontConfigurableFactory implements ColorAndFontPanelFactoryEx {
    @Override
    @NotNull
    public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
      FontEditorPreview previewPanel =
          new FontEditorPreview(options, false) {
            @Override
            protected EditorColorsScheme updateOptionsScheme(EditorColorsScheme selectedScheme) {
              return ConsoleViewUtil.updateConsoleColorScheme(selectedScheme);
            }
          };
      return new NewColorAndFontPanel(
          new SchemesPanel(options),
          new ConsoleFontOptions(options),
          previewPanel,
          "Font",
          null,
          null) {
        @Override
        public boolean containsFontOptions() {
          return true;
        }
      };
    }

    @Override
    @NotNull
    public String getPanelDisplayName() {
      return "Console Font";
    }

    @NotNull
    @Override
    public DisplayPriority getPriority() {
      return DisplayPriority.COMMON_SETTINGS;
    }
  }

  private class DiffColorsPageFactory implements ColorAndFontPanelFactory {
    @Override
    @NotNull
    public NewColorAndFontPanel createPanel(@NotNull ColorAndFontOptions options) {
      final DiffOptionsPanel optionsPanel = new DiffOptionsPanel(options);
      SchemesPanel schemesPanel = new SchemesPanel(options);
      PreviewPanel previewPanel;
      try {
        final DiffPreviewPanel diffPreviewPanel = new DiffPreviewPanel(myDisposable);
        diffPreviewPanel.setMergeRequest(null);
        schemesPanel.addListener(
            new ColorAndFontSettingsListener.Abstract() {
              @Override
              public void schemeChanged(final Object source) {
                diffPreviewPanel.setColorScheme(getSelectedScheme());
                optionsPanel.updateOptionsList();
                diffPreviewPanel.updateView();
              }
            });
        previewPanel = diffPreviewPanel;
      } catch (FilesTooBigForDiffException e) {
        LOG.info(e);
        previewPanel = new PreviewPanel.Empty();
      }

      return new NewColorAndFontPanel(
          schemesPanel, optionsPanel, previewPanel, DIFF_GROUP, null, null);
    }

    @Override
    @NotNull
    public String getPanelDisplayName() {
      return DIFF_GROUP;
    }
  }

  private void initAll() {
    EditorColorsManager colorsManager = EditorColorsManager.getInstance();
    EditorColorsScheme[] allSchemes = colorsManager.getAllSchemes();

    mySchemes = new HashMap<String, MyColorScheme>();
    for (EditorColorsScheme allScheme : allSchemes) {
      MyColorScheme schemeDelegate = new MyColorScheme(allScheme);
      initScheme(schemeDelegate);
      mySchemes.put(schemeDelegate.getName(), schemeDelegate);
    }

    mySelectedScheme = mySchemes.get(EditorColorsManager.getInstance().getGlobalScheme().getName());
    assert mySelectedScheme != null
        : EditorColorsManager.getInstance().getGlobalScheme().getName()
            + "; myschemes="
            + mySchemes;
  }

  private static void initScheme(@NotNull MyColorScheme scheme) {
    List<EditorSchemeAttributeDescriptor> descriptions =
        new ArrayList<EditorSchemeAttributeDescriptor>();
    initPluggedDescriptions(descriptions, scheme);
    initDiffDescriptors(descriptions, scheme);
    initFileStatusDescriptors(descriptions, scheme);
    initScopesDescriptors(descriptions, scheme);

    scheme.setDescriptors(
        descriptions.toArray(new EditorSchemeAttributeDescriptor[descriptions.size()]));
  }

  private static void initPluggedDescriptions(
      @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
    ColorSettingsPage[] pages = ColorSettingsPages.getInstance().getRegisteredPages();
    for (ColorSettingsPage page : pages) {
      initDescriptions(page, descriptions, scheme);
    }
    for (ColorAndFontDescriptorsProvider provider :
        Extensions.getExtensions(ColorAndFontDescriptorsProvider.EP_NAME)) {
      initDescriptions(provider, descriptions, scheme);
    }
  }

  private static void initDescriptions(
      @NotNull ColorAndFontDescriptorsProvider provider,
      @NotNull List<EditorSchemeAttributeDescriptor> descriptions,
      @NotNull MyColorScheme scheme) {
    String group = provider.getDisplayName();
    List<AttributesDescriptor> attributeDescriptors =
        ColorSettingsUtil.getAllAttributeDescriptors(provider);
    for (AttributesDescriptor descriptor : attributeDescriptors) {
      addSchemedDescription(
          descriptions,
          descriptor.getDisplayName(),
          group,
          descriptor.getKey(),
          scheme,
          null,
          null);
    }

    ColorDescriptor[] colorDescriptors = provider.getColorDescriptors();
    for (ColorDescriptor descriptor : colorDescriptors) {
      ColorKey back =
          descriptor.getKind() == ColorDescriptor.Kind.BACKGROUND ? descriptor.getKey() : null;
      ColorKey fore =
          descriptor.getKind() == ColorDescriptor.Kind.FOREGROUND ? descriptor.getKey() : null;
      addEditorSettingDescription(
          descriptions, descriptor.getDisplayName(), group, back, fore, scheme);
    }
  }

  private static void initDiffDescriptors(
      @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
    DiffOptionsPanel.addSchemeDescriptions(descriptions, scheme);
  }

  private static void initFileStatusDescriptors(
      @NotNull List<EditorSchemeAttributeDescriptor> descriptions, MyColorScheme scheme) {

    FileStatus[] statuses = FileStatusFactory.getInstance().getAllFileStatuses();

    for (FileStatus fileStatus : statuses) {
      addEditorSettingDescription(
          descriptions,
          fileStatus.getText(),
          FILE_STATUS_GROUP,
          null,
          fileStatus.getColorKey(),
          scheme);
    }
  }

  private static void initScopesDescriptors(
      @NotNull List<EditorSchemeAttributeDescriptor> descriptions, @NotNull MyColorScheme scheme) {
    Set<Pair<NamedScope, NamedScopesHolder>> namedScopes =
        new THashSet<Pair<NamedScope, NamedScopesHolder>>(
            new TObjectHashingStrategy<Pair<NamedScope, NamedScopesHolder>>() {
              @Override
              public int computeHashCode(
                  @NotNull final Pair<NamedScope, NamedScopesHolder> object) {
                return object.getFirst().getName().hashCode();
              }

              @Override
              public boolean equals(
                  @NotNull final Pair<NamedScope, NamedScopesHolder> o1,
                  @NotNull final Pair<NamedScope, NamedScopesHolder> o2) {
                return o1.getFirst().getName().equals(o2.getFirst().getName());
              }
            });
    Project[] projects = ProjectManager.getInstance().getOpenProjects();
    for (Project project : projects) {
      DependencyValidationManagerImpl validationManager =
          (DependencyValidationManagerImpl) DependencyValidationManager.getInstance(project);
      List<Pair<NamedScope, NamedScopesHolder>> cachedScopes =
          validationManager.getScopeBasedHighlightingCachedScopes();
      namedScopes.addAll(cachedScopes);
    }

    List<Pair<NamedScope, NamedScopesHolder>> list =
        new ArrayList<Pair<NamedScope, NamedScopesHolder>>(namedScopes);

    Collections.sort(
        list,
        new Comparator<Pair<NamedScope, NamedScopesHolder>>() {
          @Override
          public int compare(
              @NotNull final Pair<NamedScope, NamedScopesHolder> o1,
              @NotNull final Pair<NamedScope, NamedScopesHolder> o2) {
            return o1.getFirst().getName().compareToIgnoreCase(o2.getFirst().getName());
          }
        });
    for (Pair<NamedScope, NamedScopesHolder> pair : list) {
      NamedScope namedScope = pair.getFirst();
      String name = namedScope.getName();
      TextAttributesKey textAttributesKey = ScopeAttributesUtil.getScopeTextAttributeKey(name);
      if (scheme.getAttributes(textAttributesKey) == null) {
        scheme.setAttributes(textAttributesKey, new TextAttributes());
      }
      NamedScopesHolder holder = pair.getSecond();

      PackageSet value = namedScope.getValue();
      String toolTip = holder.getDisplayName() + (value == null ? "" : ": " + value.getText());
      addSchemedDescription(
          descriptions, name, SCOPES_GROUP, textAttributesKey, scheme, holder.getIcon(), toolTip);
    }
  }

  private static void addEditorSettingDescription(
      @NotNull List<EditorSchemeAttributeDescriptor> array,
      String name,
      String group,
      @Nullable ColorKey backgroundKey,
      @Nullable ColorKey foregroundKey,
      EditorColorsScheme scheme) {
    String type = null;
    if (foregroundKey != null) {
      type = foregroundKey.getExternalName();
    } else {
      if (backgroundKey != null) {
        type = backgroundKey.getExternalName();
      }
    }
    ColorAndFontDescription descr =
        new EditorSettingColorDescription(name, group, backgroundKey, foregroundKey, type, scheme);
    array.add(descr);
  }

  private static void addSchemedDescription(
      @NotNull List<EditorSchemeAttributeDescriptor> array,
      String name,
      String group,
      @NotNull TextAttributesKey key,
      @NotNull MyColorScheme scheme,
      Icon icon,
      String toolTip) {
    ColorAndFontDescription descr =
        new SchemeTextAttributesDescription(name, group, key, scheme, icon, toolTip);
    array.add(descr);
  }

  @Override
  public String getDisplayName() {
    return ApplicationBundle.message("title.colors.and.fonts");
  }

  private void revertChanges() {
    if (isSchemeListModified() || isSomeSchemeModified()) {
      myRevertChangesCompleted = false;
    }

    if (!myRevertChangesCompleted) {
      ensureSchemesPanel();

      try {
        resetImpl();
      } finally {
        myRevertChangesCompleted = true;
      }
    }
  }

  private void resetImpl() {
    mySomeSchemesDeleted = false;
    initAll();
    resetSchemesCombo(null);
  }

  @Override
  public synchronized void reset() {
    if (!myInitResetInvoked) {
      try {
        super.reset();
        if (!myInitResetCompleted) {
          ensureSchemesPanel();

          try {
            resetImpl();
          } finally {
            myInitResetCompleted = true;
          }
        }
      } finally {
        myInitResetInvoked = true;
      }

    } else {
      revertChanges();
    }
  }

  public synchronized void resetFromChild() {
    if (!myInitResetCompleted) {
      ensureSchemesPanel();

      try {
        resetImpl();
      } finally {
        myInitResetCompleted = true;
      }
    }
  }

  private void ensureSchemesPanel() {
    if (myRootSchemesPanel == null) {
      myRootSchemesPanel = new SchemesPanel(this);

      myRootSchemesPanel.addListener(
          new ColorAndFontSettingsListener.Abstract() {
            @Override
            public void schemeChanged(final Object source) {
              if (!myIsReset) {
                resetSchemesCombo(source);
              }
            }
          });
    }
  }

  @Override
  public void disposeUIResources() {
    try {
      if (!myDisposeCompleted) {
        try {
          super.disposeUIResources();
          Disposer.dispose(myDisposable);
          if (myRootSchemesPanel != null) {
            myRootSchemesPanel.disposeUIResources();
          }
        } finally {
          myDisposeCompleted = true;
        }
      }
    } finally {
      mySubPanelFactories = null;

      myInitResetCompleted = false;
      myInitResetInvoked = false;
      myRevertChangesCompleted = false;

      myApplyCompleted = false;
      myRootSchemesPanel = null;
    }
  }

  public boolean currentSchemeIsReadOnly() {
    return isReadOnly(mySelectedScheme);
  }

  public boolean currentSchemeIsShared() {
    return ColorSettingsUtil.isSharedScheme(mySelectedScheme);
  }

  private static class SchemeTextAttributesDescription extends TextAttributesDescription {
    @NotNull private final TextAttributes myAttributesToApply;
    @NotNull private final TextAttributesKey key;
    private TextAttributes myFallbackAttributes;
    private Pair<ColorSettingsPage, AttributesDescriptor> myBaseAttributeDescriptor;
    private boolean myIsInheritedInitial = false;

    private SchemeTextAttributesDescription(
        String name,
        String group,
        @NotNull TextAttributesKey key,
        @NotNull MyColorScheme scheme,
        Icon icon,
        String toolTip) {
      super(name, group, getInitialAttributes(scheme, key).clone(), key, scheme, icon, toolTip);
      this.key = key;
      myAttributesToApply = getInitialAttributes(scheme, key);
      TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
      if (fallbackKey != null) {
        myFallbackAttributes = scheme.getAttributes(fallbackKey);
        myBaseAttributeDescriptor =
            ColorSettingsPages.getInstance().getAttributeDescriptor(fallbackKey);
        if (myBaseAttributeDescriptor == null) {
          myBaseAttributeDescriptor =
              new Pair<ColorSettingsPage, AttributesDescriptor>(
                  null, new AttributesDescriptor(fallbackKey.getExternalName(), fallbackKey));
        }
      }
      myIsInheritedInitial = isInherited(scheme);
      setInherited(myIsInheritedInitial);
      initCheckedStatus();
    }

    @NotNull
    private static TextAttributes getInitialAttributes(
        @NotNull MyColorScheme scheme, @NotNull TextAttributesKey key) {
      TextAttributes attributes = scheme.getAttributes(key);
      return attributes != null ? attributes : new TextAttributes();
    }

    private boolean isInherited(@NotNull MyColorScheme scheme) {
      TextAttributes attributes = scheme.getAttributes(key);
      TextAttributesKey fallbackKey = key.getFallbackAttributeKey();
      if (fallbackKey != null && !scheme.containsKey(key)) {
        TextAttributes fallbackAttributes = scheme.getAttributes(fallbackKey);
        if (attributes != null && attributes == fallbackAttributes) {
          return true;
        }
      }
      return false;
    }

    @Override
    public void apply(EditorColorsScheme scheme) {
      if (scheme == null) scheme = getScheme();
      scheme.setAttributes(key, isInherited() ? new TextAttributes() : getTextAttributes());
    }

    @Override
    public boolean isModified() {
      return !Comparing.equal(myAttributesToApply, getTextAttributes())
          || myIsInheritedInitial != isInherited();
    }

    @Override
    public boolean isErrorStripeEnabled() {
      return true;
    }

    @Nullable
    @Override
    public TextAttributes getBaseAttributes() {
      return myFallbackAttributes;
    }

    @Nullable
    @Override
    public Pair<ColorSettingsPage, AttributesDescriptor> getBaseAttributeDescriptor() {
      return myBaseAttributeDescriptor;
    }

    @Override
    public void setInherited(boolean isInherited) {
      super.setInherited(isInherited);
    }
  }

  private static class GetSetColor {
    private final ColorKey myKey;
    private final EditorColorsScheme myScheme;
    private boolean isModified = false;
    private Color myColor;

    private GetSetColor(ColorKey key, EditorColorsScheme scheme) {
      myKey = key;
      myScheme = scheme;
      myColor = myScheme.getColor(myKey);
    }

    public Color getColor() {
      return myColor;
    }

    public void setColor(Color col) {
      if (getColor() == null || !getColor().equals(col)) {
        isModified = true;
        myColor = col;
      }
    }

    public void apply(EditorColorsScheme scheme) {
      if (scheme == null) scheme = myScheme;
      scheme.setColor(myKey, myColor);
    }

    public boolean isModified() {
      return isModified;
    }
  }

  private static class EditorSettingColorDescription extends ColorAndFontDescription {
    private GetSetColor myGetSetForeground;
    private GetSetColor myGetSetBackground;

    private EditorSettingColorDescription(
        String name,
        String group,
        ColorKey backgroundKey,
        ColorKey foregroundKey,
        String type,
        EditorColorsScheme scheme) {
      super(name, group, type, scheme, null, null);
      if (backgroundKey != null) {
        myGetSetBackground = new GetSetColor(backgroundKey, scheme);
      }
      if (foregroundKey != null) {
        myGetSetForeground = new GetSetColor(foregroundKey, scheme);
      }
      initCheckedStatus();
    }

    @Override
    public int getFontType() {
      return 0;
    }

    @Override
    public void setFontType(int type) {}

    @Override
    public Color getExternalEffectColor() {
      return null;
    }

    @Override
    public void setExternalEffectColor(Color color) {}

    @Override
    public void setExternalEffectType(EffectType type) {}

    @NotNull
    @Override
    public EffectType getExternalEffectType() {
      return EffectType.LINE_UNDERSCORE;
    }

    @Override
    public Color getExternalForeground() {
      if (myGetSetForeground == null) {
        return null;
      }
      return myGetSetForeground.getColor();
    }

    @Override
    public void setExternalForeground(Color col) {
      if (myGetSetForeground == null) {
        return;
      }
      myGetSetForeground.setColor(col);
    }

    @Override
    public Color getExternalBackground() {
      if (myGetSetBackground == null) {
        return null;
      }
      return myGetSetBackground.getColor();
    }

    @Override
    public void setExternalBackground(Color col) {
      if (myGetSetBackground == null) {
        return;
      }
      myGetSetBackground.setColor(col);
    }

    @Override
    public Color getExternalErrorStripe() {
      return null;
    }

    @Override
    public void setExternalErrorStripe(Color col) {}

    @Override
    public boolean isFontEnabled() {
      return false;
    }

    @Override
    public boolean isForegroundEnabled() {
      return myGetSetForeground != null;
    }

    @Override
    public boolean isBackgroundEnabled() {
      return myGetSetBackground != null;
    }

    @Override
    public boolean isEffectsColorEnabled() {
      return false;
    }

    @Override
    public boolean isModified() {
      return myGetSetBackground != null && myGetSetBackground.isModified()
          || myGetSetForeground != null && myGetSetForeground.isModified();
    }

    @Override
    public void apply(EditorColorsScheme scheme) {
      if (myGetSetBackground != null) {
        myGetSetBackground.apply(scheme);
      }
      if (myGetSetForeground != null) {
        myGetSetForeground.apply(scheme);
      }
    }
  }

  @Override
  @NotNull
  public String getHelpTopic() {
    return "reference.settingsdialog.IDE.editor.colors";
  }

  private static class MyColorScheme extends EditorColorsSchemeImpl {

    private EditorSchemeAttributeDescriptor[] myDescriptors;
    private String myName;
    private boolean myIsNew = false;

    private MyColorScheme(@NotNull EditorColorsScheme parentScheme) {
      super(parentScheme, DefaultColorSchemesManager.getInstance());
      parentScheme.getFontPreferences().copyTo(getFontPreferences());
      setLineSpacing(parentScheme.getLineSpacing());

      parentScheme.getConsoleFontPreferences().copyTo(getConsoleFontPreferences());
      setConsoleLineSpacing(parentScheme.getConsoleLineSpacing());

      setQuickDocFontSize(parentScheme.getQuickDocFontSize());
      myName = parentScheme.getName();
      if (parentScheme instanceof ExternalizableScheme) {
        getExternalInfo().copy(((ExternalizableScheme) parentScheme).getExternalInfo());
      }
      initFonts();
    }

    @Override
    public String getName() {
      return myName;
    }

    @Override
    public void setName(String name) {
      myName = name;
    }

    public void setDescriptors(EditorSchemeAttributeDescriptor[] descriptors) {
      myDescriptors = descriptors;
    }

    public EditorSchemeAttributeDescriptor[] getDescriptors() {
      return myDescriptors;
    }

    public boolean isDefault() {
      return myParentScheme instanceof DefaultColorsScheme;
    }

    public boolean isReadOnly() {
      return myParentScheme instanceof ReadOnlyColorsScheme;
    }

    public boolean isModified() {
      if (isFontModified() || isConsoleFontModified()) return true;

      for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
        if (descriptor.isModified()) {
          return true;
        }
      }

      return false;
    }

    private boolean isFontModified() {
      if (!getFontPreferences().equals(myParentScheme.getFontPreferences())) return true;
      if (getLineSpacing() != myParentScheme.getLineSpacing()) return true;
      return getQuickDocFontSize() != myParentScheme.getQuickDocFontSize();
    }

    private boolean isConsoleFontModified() {
      if (!getConsoleFontPreferences().equals(myParentScheme.getConsoleFontPreferences()))
        return true;
      return getConsoleLineSpacing() != myParentScheme.getConsoleLineSpacing();
    }

    public void apply() {
      apply(myParentScheme);
    }

    public void apply(@NotNull EditorColorsScheme scheme) {
      scheme.setFontPreferences(getFontPreferences());
      scheme.setLineSpacing(myLineSpacing);
      scheme.setQuickDocFontSize(getQuickDocFontSize());
      scheme.setConsoleFontPreferences(getConsoleFontPreferences());
      scheme.setConsoleLineSpacing(getConsoleLineSpacing());

      for (EditorSchemeAttributeDescriptor descriptor : myDescriptors) {
        descriptor.apply(scheme);
      }
    }

    @Override
    public Object clone() {
      return null;
    }

    public EditorColorsScheme getOriginalScheme() {
      return myParentScheme;
    }

    public void setIsNew() {
      myIsNew = true;
    }

    public boolean isNew() {
      return myIsNew;
    }

    @NotNull
    @Override
    public String toString() {
      return "temporary scheme for " + myName;
    }
  }

  @Override
  @NotNull
  public String getId() {
    return getHelpTopic();
  }

  @Override
  @Nullable
  public Runnable enableSearch(final String option) {
    return null;
  }

  @Nullable
  public InnerSearchableConfigurable findSubConfigurable(@NotNull final Class pageClass) {
    if (mySubPanelFactories == null) {
      buildConfigurables();
    }
    for (Map.Entry<ColorAndFontPanelFactory, InnerSearchableConfigurable> entry :
        mySubPanelFactories.entrySet()) {
      if (pageClass.isInstance(entry.getValue().createPanel().getSettingsPage())) {
        return entry.getValue();
      }
    }
    return null;
  }

  @Nullable
  public NewColorAndFontPanel findPage(String pageName) {
    if (mySubPanelFactories == null) {
      buildConfigurables();
    }
    for (InnerSearchableConfigurable configurable : mySubPanelFactories.values()) {
      if (configurable.getDisplayName().equals(pageName)) {
        return configurable.createPanel();
      }
    }
    return null;
  }

  private class InnerSearchableConfigurable
      implements SearchableConfigurable, OptionsContainingConfigurable, NoScroll {
    private NewColorAndFontPanel mySubPanel;
    private boolean mySubInitInvoked = false;
    @NotNull private final ColorAndFontPanelFactory myFactory;

    private InnerSearchableConfigurable(@NotNull ColorAndFontPanelFactory factory) {
      myFactory = factory;
    }

    @NotNull
    @Override
    @Nls
    public String getDisplayName() {
      return myFactory.getPanelDisplayName();
    }

    public NewColorAndFontPanel getSubPanelIfInitialized() {
      return mySubPanel;
    }

    private NewColorAndFontPanel createPanel() {
      if (mySubPanel == null) {
        mySubPanel = myFactory.createPanel(ColorAndFontOptions.this);
        mySubPanel.reset(this);
        mySubPanel.addSchemesListener(
            new ColorAndFontSettingsListener.Abstract() {
              @Override
              public void schemeChanged(final Object source) {
                if (!myIsReset) {
                  resetSchemesCombo(source);
                }
              }
            });

        mySubPanel.addDescriptionListener(
            new ColorAndFontSettingsListener.Abstract() {
              @Override
              public void fontChanged() {
                for (NewColorAndFontPanel panel : getPanels()) {
                  panel.updatePreview();
                }
              }
            });
      }
      return mySubPanel;
    }

    @Override
    public String getHelpTopic() {
      return null;
    }

    @Override
    public JComponent createComponent() {
      return createPanel().getPanel();
    }

    @Override
    public boolean isModified() {
      createPanel();
      for (MyColorScheme scheme : mySchemes.values()) {
        if (mySubPanel.containsFontOptions()) {
          if (scheme.isFontModified() || scheme.isConsoleFontModified()) {
            myRevertChangesCompleted = false;
            return true;
          }
        } else {
          for (EditorSchemeAttributeDescriptor descriptor : scheme.getDescriptors()) {
            if (mySubPanel.contains(descriptor) && descriptor.isModified()) {
              myRevertChangesCompleted = false;
              return true;
            }
          }
        }
      }

      return false;
    }

    @Override
    public void apply() throws ConfigurationException {
      ColorAndFontOptions.this.apply();
    }

    @Override
    public void reset() {
      if (!mySubInitInvoked) {
        if (!myInitResetCompleted) {
          resetFromChild();
        }
        mySubInitInvoked = true;
      } else {
        revertChanges();
      }
    }

    @Override
    public void disposeUIResources() {
      if (mySubPanel != null) {
        mySubPanel.disposeUIResources();
        mySubPanel = null;
      }
    }

    @Override
    @NotNull
    public String getId() {
      return ColorAndFontOptions.this.getId() + "." + getDisplayName();
    }

    @Override
    public Runnable enableSearch(final String option) {
      return createPanel().showOption(option);
    }

    @NotNull
    @Override
    public Set<String> processListOptions() {
      return createPanel().processListOptions();
    }

    @NotNull
    @NonNls
    @Override
    public String toString() {
      return "Color And Fonts for " + getDisplayName();
    }
  }
}
 @Override
 protected String getTabTitle() {
   return ApplicationBundle.message("wrapping.and.braces");
 }
public class FontOptions extends JPanel implements OptionsPanel {
  private static final FontInfoRenderer RENDERER =
      new FontInfoRenderer() {
        @Override
        protected AntialiasingType getAntialiasingType() {
          return UISettings.getShadowInstance().EDITOR_AA_TYPE;
        }
      };

  private final EventDispatcher<ColorAndFontSettingsListener> myDispatcher =
      EventDispatcher.create(ColorAndFontSettingsListener.class);

  @NotNull private final ColorAndFontOptions myOptions;

  @NotNull private final JTextField myEditorFontSizeField = new JTextField(4);
  @NotNull private final JTextField myLineSpacingField = new JTextField(4);
  private final FontComboBox myPrimaryCombo = new FontComboBox();
  private final JCheckBox myUseSecondaryFontCheckbox =
      new JCheckBox(ApplicationBundle.message("secondary.font"));
  private final JCheckBox myEnableLigaturesCheckbox =
      new JCheckBox(ApplicationBundle.message("use.ligatures"));
  private final JLabel myLigaturesInfoLinkLabel;
  private final FontComboBox mySecondaryCombo = new FontComboBox();

  @NotNull
  private final JBCheckBox myOnlyMonospacedCheckBox =
      new JBCheckBox(ApplicationBundle.message("checkbox.show.only.monospaced.fonts"));

  private boolean myIsInSchemeChange;

  public FontOptions(ColorAndFontOptions options) {
    this(options, ApplicationBundle.message("group.editor.font"));
  }

  protected FontOptions(@NotNull ColorAndFontOptions options, final String title) {
    setLayout(new MigLayout("ins 0, gap 5, flowx"));
    Insets borderInsets =
        new Insets(
            IdeBorderFactory.TITLED_BORDER_TOP_INSET,
            IdeBorderFactory.TITLED_BORDER_LEFT_INSET,
            0,
            IdeBorderFactory.TITLED_BORDER_RIGHT_INSET);
    setBorder(IdeBorderFactory.createTitledBorder(title, false, borderInsets));
    myOptions = options;
    add(myOnlyMonospacedCheckBox, "sgx b, sx 2");

    add(new JLabel(ApplicationBundle.message("primary.font")), "newline, ax right");
    add(myPrimaryCombo, "sgx b");
    add(new JLabel(ApplicationBundle.message("editbox.font.size")), "gapleft 20");
    add(myEditorFontSizeField);
    add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), "gapleft 20");
    add(myLineSpacingField);

    add(
        new JLabel(
            ApplicationBundle.message("label.fallback.fonts.list.description"),
            MessageType.INFO.getDefaultIcon(),
            SwingConstants.LEFT),
        "newline, sx 5");
    add(myUseSecondaryFontCheckbox, "newline, ax right");
    add(mySecondaryCombo, "sgx b");
    JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
    myEnableLigaturesCheckbox.setBorder(null);
    panel.add(myEnableLigaturesCheckbox);
    myLigaturesInfoLinkLabel =
        new LinkLabel<Void>(
            ApplicationBundle.message("ligatures.more.info"),
            null,
            new LinkListener<Void>() {
              @Override
              public void linkSelected(LinkLabel aSource, Void aLinkData) {
                BrowserUtil.browse(
                    "https://confluence.jetbrains.com/display/IDEADEV/Support+for+Ligatures+in+Editor");
              }
            });
    myLigaturesInfoLinkLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
    panel.add(myLigaturesInfoLinkLabel);
    add(panel, "newline, sx 2");

    myOnlyMonospacedCheckBox.setBorder(null);
    myUseSecondaryFontCheckbox.setBorder(null);
    mySecondaryCombo.setEnabled(false);

    myOnlyMonospacedCheckBox.setSelected(
        EditorColorsManager.getInstance().isUseOnlyMonospacedFonts());
    myOnlyMonospacedCheckBox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            EditorColorsManager.getInstance()
                .setUseOnlyMonospacedFonts(myOnlyMonospacedCheckBox.isSelected());
            myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
            mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
          }
        });
    myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
    myPrimaryCombo.setRenderer(RENDERER);

    mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
    mySecondaryCombo.setRenderer(RENDERER);

    myUseSecondaryFontCheckbox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            mySecondaryCombo.setEnabled(myUseSecondaryFontCheckbox.isSelected());
            syncFontFamilies();
          }
        });
    ItemListener itemListener =
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
              syncFontFamilies();
            }
          }
        };
    myPrimaryCombo.addItemListener(itemListener);
    mySecondaryCombo.addItemListener(itemListener);

    ActionListener actionListener =
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            syncFontFamilies();
          }
        };
    myPrimaryCombo.addActionListener(actionListener);
    mySecondaryCombo.addActionListener(actionListener);

    myEditorFontSizeField
        .getDocument()
        .addDocumentListener(
            new DocumentAdapter() {
              @Override
              public void textChanged(DocumentEvent event) {
                if (myIsInSchemeChange || !SwingUtilities.isEventDispatchThread()) return;
                String selectedFont = myPrimaryCombo.getFontName();
                if (selectedFont != null) {
                  FontPreferences fontPreferences = getFontPreferences();
                  fontPreferences.register(selectedFont, getFontSizeFromField());
                }
                updateDescription(true);
              }
            });
    myEditorFontSizeField.addKeyListener(
        new KeyAdapter() {
          @Override
          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
            boolean up = e.getKeyCode() == KeyEvent.VK_UP;
            try {
              int value = Integer.parseInt(myEditorFontSizeField.getText());
              value += (up ? 1 : -1);
              value =
                  Math.min(
                      OptionsConstants.MAX_EDITOR_FONT_SIZE,
                      Math.max(OptionsConstants.MIN_EDITOR_FONT_SIZE, value));
              myEditorFontSizeField.setText(String.valueOf(value));
            } catch (NumberFormatException ignored) {
            }
          }
        });

    myLineSpacingField
        .getDocument()
        .addDocumentListener(
            new DocumentAdapter() {
              @Override
              public void textChanged(DocumentEvent event) {
                if (myIsInSchemeChange) return;
                float lineSpacing = getLineSpacingFromField();
                if (getLineSpacing() != lineSpacing) {
                  setCurrentLineSpacing(lineSpacing);
                }
                updateDescription(true);
              }
            });
    myLineSpacingField.addKeyListener(
        new KeyAdapter() {
          @Override
          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
            boolean up = e.getKeyCode() == KeyEvent.VK_UP;
            try {
              float value = Float.parseFloat(myLineSpacingField.getText());
              value += (up ? 1 : -1) * .1F;
              value =
                  Math.min(
                      OptionsConstants.MAX_EDITOR_LINE_SPACING,
                      Math.max(OptionsConstants.MIN_EDITOR_LINE_SPACING, value));
              myLineSpacingField.setText(String.format(Locale.ENGLISH, "%.1f", value));
            } catch (NumberFormatException ignored) {
            }
          }
        });
    myEnableLigaturesCheckbox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            getFontPreferences().setUseLigatures(myEnableLigaturesCheckbox.isSelected());
          }
        });
  }

  private int getFontSizeFromField() {
    try {
      return Math.min(
          OptionsConstants.MAX_EDITOR_FONT_SIZE,
          Math.max(
              OptionsConstants.MIN_EDITOR_FONT_SIZE,
              Integer.parseInt(myEditorFontSizeField.getText())));
    } catch (NumberFormatException e) {
      return OptionsConstants.DEFAULT_EDITOR_FONT_SIZE;
    }
  }

  private float getLineSpacingFromField() {
    try {
      return Math.min(
          OptionsConstants.MAX_EDITOR_LINE_SPACING,
          Math.max(
              OptionsConstants.MIN_EDITOR_LINE_SPACING,
              Float.parseFloat(myLineSpacingField.getText())));
    } catch (NumberFormatException e) {
      return OptionsConstants.DEFAULT_EDITOR_LINE_SPACING;
    }
  }

  private void syncFontFamilies() {
    if (myIsInSchemeChange) {
      return;
    }
    FontPreferences fontPreferences = getFontPreferences();
    fontPreferences.clearFonts();
    String primaryFontFamily = myPrimaryCombo.getFontName();
    String secondaryFontFamily =
        mySecondaryCombo.isEnabled() ? mySecondaryCombo.getFontName() : null;
    int fontSize = getFontSizeFromField();
    if (primaryFontFamily != null) {
      if (!FontPreferences.DEFAULT_FONT_NAME.equals(primaryFontFamily)) {
        fontPreferences.addFontFamily(primaryFontFamily);
      }
      fontPreferences.register(primaryFontFamily, JBUI.scale(fontSize));
    }
    if (secondaryFontFamily != null) {
      if (!FontPreferences.DEFAULT_FONT_NAME.equals(secondaryFontFamily)) {
        fontPreferences.addFontFamily(secondaryFontFamily);
      }
      fontPreferences.register(secondaryFontFamily, JBUI.scale(fontSize));
    }
    updateDescription(true);
  }

  public static void showReadOnlyMessage(JComponent parent, final boolean sharedScheme) {
    if (!sharedScheme) {
      Messages.showMessageDialog(
          parent,
          ApplicationBundle.message("error.readonly.scheme.cannot.be.modified"),
          ApplicationBundle.message("title.cannot.modify.readonly.scheme"),
          Messages.getInformationIcon());
    } else {
      Messages.showMessageDialog(
          parent,
          ApplicationBundle.message("error.shared.scheme.cannot.be.modified"),
          ApplicationBundle.message("title.cannot.modify.readonly.scheme"),
          Messages.getInformationIcon());
    }
  }

  @Override
  public void updateOptionsList() {
    myIsInSchemeChange = true;

    myLineSpacingField.setText(Float.toString(getLineSpacing()));
    FontPreferences fontPreferences = getFontPreferences();
    List<String> fontFamilies = fontPreferences.getEffectiveFontFamilies();
    myPrimaryCombo.setFontName(fontPreferences.getFontFamily());
    boolean isThereSecondaryFont = fontFamilies.size() > 1;
    myUseSecondaryFontCheckbox.setSelected(isThereSecondaryFont);
    mySecondaryCombo.setFontName(isThereSecondaryFont ? fontFamilies.get(1) : null);
    myEditorFontSizeField.setText(
        String.valueOf(fontPreferences.getSize(fontPreferences.getFontFamily())));

    boolean readOnly = ColorAndFontOptions.isReadOnly(myOptions.getSelectedScheme());
    myPrimaryCombo.setEnabled(!readOnly);
    mySecondaryCombo.setEnabled(isThereSecondaryFont && !readOnly);
    myOnlyMonospacedCheckBox.setEnabled(!readOnly);
    myLineSpacingField.setEnabled(!readOnly);
    myEditorFontSizeField.setEnabled(!readOnly);
    myUseSecondaryFontCheckbox.setEnabled(!readOnly);

    myEnableLigaturesCheckbox.setEnabled(!readOnly);
    myLigaturesInfoLinkLabel.setEnabled(!readOnly);
    myEnableLigaturesCheckbox.setSelected(fontPreferences.useLigatures());

    myIsInSchemeChange = false;
  }

  @NotNull
  protected FontPreferences getFontPreferences() {
    return getCurrentScheme().getFontPreferences();
  }

  protected float getLineSpacing() {
    return getCurrentScheme().getLineSpacing();
  }

  protected void setCurrentLineSpacing(float lineSpacing) {
    getCurrentScheme().setLineSpacing(lineSpacing);
  }

  @Override
  @Nullable
  public Runnable showOption(final String option) {
    return null;
  }

  @Override
  public void applyChangesToScheme() {}

  @Override
  public void selectOption(final String typeToSelect) {}

  protected EditorColorsScheme getCurrentScheme() {
    return myOptions.getSelectedScheme();
  }

  public boolean updateDescription(boolean modified) {
    EditorColorsScheme scheme = myOptions.getSelectedScheme();

    if (modified
        && (ColorAndFontOptions.isReadOnly(scheme) || ColorSettingsUtil.isSharedScheme(scheme))) {
      showReadOnlyMessage(this, ColorSettingsUtil.isSharedScheme(scheme));
      return false;
    }

    myDispatcher.getMulticaster().fontChanged();

    return true;
  }

  @Override
  public void addListener(ColorAndFontSettingsListener listener) {
    myDispatcher.addListener(listener);
  }

  @Override
  public JPanel getPanel() {
    return this;
  }

  @Override
  public Set<String> processListOptions() {
    return new HashSet<String>();
  }
}
 public FontOptions(ColorAndFontOptions options) {
   this(options, ApplicationBundle.message("group.editor.font"));
 }
  public static void deletePsiElement(
      final PsiElement[] elementsToDelete, final Project project, boolean needConfirmation) {
    if (elementsToDelete == null || elementsToDelete.length == 0) return;

    final PsiElement[] elements = PsiTreeUtil.filterAncestors(elementsToDelete);

    boolean safeDeleteApplicable = true;
    for (int i = 0; i < elements.length && safeDeleteApplicable; i++) {
      PsiElement element = elements[i];
      safeDeleteApplicable = SafeDeleteProcessor.validElement(element);
    }

    final boolean dumb = DumbService.getInstance(project).isDumb();
    if (safeDeleteApplicable && !dumb) {
      DeleteDialog dialog =
          new DeleteDialog(
              project,
              elements,
              new DeleteDialog.Callback() {
                public void run(final DeleteDialog dialog) {
                  if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(
                      project, Arrays.asList(elements), true)) return;
                  SafeDeleteProcessor.createInstance(
                          project,
                          new Runnable() {
                            public void run() {
                              dialog.close(DialogWrapper.CANCEL_EXIT_CODE);
                            }
                          },
                          elements,
                          dialog.isSearchInComments(),
                          dialog.isSearchInNonJava(),
                          true)
                      .run();
                }
              });
      if (needConfirmation) {
        dialog.show();
        if (!dialog.isOK()) return;
      }
    } else {
      @SuppressWarnings({"UnresolvedPropertyKey"})
      String warningMessage =
          DeleteUtil.generateWarningMessage(IdeBundle.message("prompt.delete.elements"), elements);

      boolean anyDirectories = false;
      String directoryName = null;
      for (PsiElement psiElement : elementsToDelete) {
        if (psiElement instanceof PsiDirectory
            && !PsiUtilBase.isSymLink((PsiDirectory) psiElement)) {
          anyDirectories = true;
          directoryName = ((PsiDirectory) psiElement).getName();
          break;
        }
      }
      if (anyDirectories) {
        if (elements.length == 1) {
          warningMessage +=
              IdeBundle.message("warning.delete.all.files.and.subdirectories", directoryName);
        } else {
          warningMessage +=
              IdeBundle.message(
                  "warning.delete.all.files.and.subdirectories.in.the.selected.directory");
        }
      }

      if (safeDeleteApplicable && dumb) {
        warningMessage +=
            "\n\nWarning:\n  Safe delete is not available while "
                + ApplicationNamesInfo.getInstance().getFullProductName()
                + " updates indices,\n  no usages will be checked.";
      }

      if (needConfirmation) {
        int result =
            Messages.showOkCancelDialog(
                project,
                warningMessage,
                IdeBundle.message("title.delete"),
                ApplicationBundle.message("button.delete"),
                CommonBundle.getCancelButtonText(),
                Messages.getQuestionIcon());
        if (result != 0) return;
      }
    }

    final FileTypeManager ftManager = FileTypeManager.getInstance();
    CommandProcessor.getInstance()
        .executeCommand(
            project,
            new Runnable() {
              public void run() {
                if (!CommonRefactoringUtil.checkReadOnlyStatusRecursively(
                    project, Arrays.asList(elements), false)) {
                  return;
                }

                // deleted from project view or something like that.
                if (PlatformDataKeys.EDITOR.getData(DataManager.getInstance().getDataContext())
                    == null) {
                  CommandProcessor.getInstance().markCurrentCommandAsGlobal(project);
                }

                for (final PsiElement elementToDelete : elements) {
                  if (!elementToDelete.isValid()) continue; // was already deleted
                  if (elementToDelete instanceof PsiDirectory) {
                    VirtualFile virtualFile = ((PsiDirectory) elementToDelete).getVirtualFile();
                    if (virtualFile.isInLocalFileSystem() && !virtualFile.isSymLink()) {
                      ArrayList<VirtualFile> readOnlyFiles = new ArrayList<VirtualFile>();
                      getReadOnlyVirtualFiles(virtualFile, readOnlyFiles, ftManager);

                      if (!readOnlyFiles.isEmpty()) {
                        int _result =
                            Messages.showYesNoDialog(
                                project,
                                IdeBundle.message(
                                    "prompt.directory.contains.read.only.files",
                                    virtualFile.getPresentableUrl()),
                                IdeBundle.message("title.delete"),
                                Messages.getQuestionIcon());
                        if (_result != 0) continue;

                        boolean success = true;
                        for (VirtualFile file : readOnlyFiles) {
                          success = clearReadOnlyFlag(file, project);
                          if (!success) break;
                        }
                        if (!success) continue;
                      }
                    }
                  } else if (!elementToDelete.isWritable()
                      && !(elementToDelete instanceof PsiFileSystemItem
                          && PsiUtilBase.isSymLink((PsiFileSystemItem) elementToDelete))) {
                    final PsiFile file = elementToDelete.getContainingFile();
                    if (file != null) {
                      final VirtualFile virtualFile = file.getVirtualFile();
                      if (virtualFile.isInLocalFileSystem()) {
                        int _result =
                            MessagesEx.fileIsReadOnly(project, virtualFile)
                                .setTitle(IdeBundle.message("title.delete"))
                                .appendMessage(IdeBundle.message("prompt.delete.it.anyway"))
                                .askYesNo();
                        if (_result != 0) continue;

                        boolean success = clearReadOnlyFlag(virtualFile, project);
                        if (!success) continue;
                      }
                    }
                  }

                  try {
                    elementToDelete.checkDelete();
                  } catch (IncorrectOperationException ex) {
                    Messages.showMessageDialog(
                        project,
                        ex.getMessage(),
                        CommonBundle.getErrorTitle(),
                        Messages.getErrorIcon());
                    continue;
                  }

                  ApplicationManager.getApplication()
                      .runWriteAction(
                          new Runnable() {
                            public void run() {
                              try {
                                elementToDelete.delete();
                              } catch (final IncorrectOperationException ex) {
                                ApplicationManager.getApplication()
                                    .invokeLater(
                                        new Runnable() {
                                          public void run() {
                                            Messages.showMessageDialog(
                                                project,
                                                ex.getMessage(),
                                                CommonBundle.getErrorTitle(),
                                                Messages.getErrorIcon());
                                          }
                                        });
                              }
                            }
                          });
                }
              }
            },
            RefactoringBundle.message(
                "safe.delete.command",
                RefactoringUIUtil.calculatePsiElementDescriptionList(elements)),
            null);
  }
  protected FontOptions(@NotNull ColorAndFontOptions options, final String title) {
    setLayout(new MigLayout("ins 0, gap 5, flowx"));
    Insets borderInsets =
        new Insets(
            IdeBorderFactory.TITLED_BORDER_TOP_INSET,
            IdeBorderFactory.TITLED_BORDER_LEFT_INSET,
            0,
            IdeBorderFactory.TITLED_BORDER_RIGHT_INSET);
    setBorder(IdeBorderFactory.createTitledBorder(title, false, borderInsets));
    myOptions = options;
    add(myOnlyMonospacedCheckBox, "sgx b, sx 2");

    add(new JLabel(ApplicationBundle.message("primary.font")), "newline, ax right");
    add(myPrimaryCombo, "sgx b");
    add(new JLabel(ApplicationBundle.message("editbox.font.size")), "gapleft 20");
    add(myEditorFontSizeField);
    add(new JLabel(ApplicationBundle.message("editbox.line.spacing")), "gapleft 20");
    add(myLineSpacingField);

    add(
        new JLabel(
            ApplicationBundle.message("label.fallback.fonts.list.description"),
            MessageType.INFO.getDefaultIcon(),
            SwingConstants.LEFT),
        "newline, sx 5");
    add(myUseSecondaryFontCheckbox, "newline, ax right");
    add(mySecondaryCombo, "sgx b");
    JPanel panel = new JPanel(new FlowLayout(FlowLayout.CENTER, 0, 0));
    myEnableLigaturesCheckbox.setBorder(null);
    panel.add(myEnableLigaturesCheckbox);
    myLigaturesInfoLinkLabel =
        new LinkLabel<Void>(
            ApplicationBundle.message("ligatures.more.info"),
            null,
            new LinkListener<Void>() {
              @Override
              public void linkSelected(LinkLabel aSource, Void aLinkData) {
                BrowserUtil.browse(
                    "https://confluence.jetbrains.com/display/IDEADEV/Support+for+Ligatures+in+Editor");
              }
            });
    myLigaturesInfoLinkLabel.setBorder(new EmptyBorder(0, 5, 0, 0));
    panel.add(myLigaturesInfoLinkLabel);
    add(panel, "newline, sx 2");

    myOnlyMonospacedCheckBox.setBorder(null);
    myUseSecondaryFontCheckbox.setBorder(null);
    mySecondaryCombo.setEnabled(false);

    myOnlyMonospacedCheckBox.setSelected(
        EditorColorsManager.getInstance().isUseOnlyMonospacedFonts());
    myOnlyMonospacedCheckBox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            EditorColorsManager.getInstance()
                .setUseOnlyMonospacedFonts(myOnlyMonospacedCheckBox.isSelected());
            myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
            mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
          }
        });
    myPrimaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
    myPrimaryCombo.setRenderer(RENDERER);

    mySecondaryCombo.setMonospacedOnly(myOnlyMonospacedCheckBox.isSelected());
    mySecondaryCombo.setRenderer(RENDERER);

    myUseSecondaryFontCheckbox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            mySecondaryCombo.setEnabled(myUseSecondaryFontCheckbox.isSelected());
            syncFontFamilies();
          }
        });
    ItemListener itemListener =
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            if (e.getStateChange() == ItemEvent.SELECTED) {
              syncFontFamilies();
            }
          }
        };
    myPrimaryCombo.addItemListener(itemListener);
    mySecondaryCombo.addItemListener(itemListener);

    ActionListener actionListener =
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            syncFontFamilies();
          }
        };
    myPrimaryCombo.addActionListener(actionListener);
    mySecondaryCombo.addActionListener(actionListener);

    myEditorFontSizeField
        .getDocument()
        .addDocumentListener(
            new DocumentAdapter() {
              @Override
              public void textChanged(DocumentEvent event) {
                if (myIsInSchemeChange || !SwingUtilities.isEventDispatchThread()) return;
                String selectedFont = myPrimaryCombo.getFontName();
                if (selectedFont != null) {
                  FontPreferences fontPreferences = getFontPreferences();
                  fontPreferences.register(selectedFont, getFontSizeFromField());
                }
                updateDescription(true);
              }
            });
    myEditorFontSizeField.addKeyListener(
        new KeyAdapter() {
          @Override
          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
            boolean up = e.getKeyCode() == KeyEvent.VK_UP;
            try {
              int value = Integer.parseInt(myEditorFontSizeField.getText());
              value += (up ? 1 : -1);
              value =
                  Math.min(
                      OptionsConstants.MAX_EDITOR_FONT_SIZE,
                      Math.max(OptionsConstants.MIN_EDITOR_FONT_SIZE, value));
              myEditorFontSizeField.setText(String.valueOf(value));
            } catch (NumberFormatException ignored) {
            }
          }
        });

    myLineSpacingField
        .getDocument()
        .addDocumentListener(
            new DocumentAdapter() {
              @Override
              public void textChanged(DocumentEvent event) {
                if (myIsInSchemeChange) return;
                float lineSpacing = getLineSpacingFromField();
                if (getLineSpacing() != lineSpacing) {
                  setCurrentLineSpacing(lineSpacing);
                }
                updateDescription(true);
              }
            });
    myLineSpacingField.addKeyListener(
        new KeyAdapter() {
          @Override
          public void keyPressed(KeyEvent e) {
            if (e.getKeyCode() != KeyEvent.VK_UP && e.getKeyCode() != KeyEvent.VK_DOWN) return;
            boolean up = e.getKeyCode() == KeyEvent.VK_UP;
            try {
              float value = Float.parseFloat(myLineSpacingField.getText());
              value += (up ? 1 : -1) * .1F;
              value =
                  Math.min(
                      OptionsConstants.MAX_EDITOR_LINE_SPACING,
                      Math.max(OptionsConstants.MIN_EDITOR_LINE_SPACING, value));
              myLineSpacingField.setText(String.format(Locale.ENGLISH, "%.1f", value));
            } catch (NumberFormatException ignored) {
            }
          }
        });
    myEnableLigaturesCheckbox.addActionListener(
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            getFontPreferences().setUseLigatures(myEnableLigaturesCheckbox.isSelected());
          }
        });
  }
 @Override
 public String getDisplayName() {
   return ApplicationBundle.message("tab.editor.settings.behavior");
 }
public class EditorOptionsPanel {
  private JPanel myBehaviourPanel;
  private JCheckBox myCbHighlightBraces;
  private static final String STRIP_CHANGED =
      ApplicationBundle.message("combobox.strip.modified.lines");

  private static final String STRIP_ALL = ApplicationBundle.message("combobox.strip.all");
  private static final String STRIP_NONE = ApplicationBundle.message("combobox.strip.none");
  private JComboBox myStripTrailingSpacesCombo;

  private JCheckBox myCbVirtualSpace;
  private JCheckBox myCbCaretInsideTabs;

  private JTextField myRecentFilesLimitField;

  private JCheckBox myCbHighlightScope;

  private JTextField myClipboardContentLimitTextField;
  private JCheckBox myCbSmoothScrolling;
  private JCheckBox myCbVirtualPageAtBottom;
  private JCheckBox myCbEnableDnD;
  private JCheckBox myCbEnableWheelFontChange;
  private JCheckBox myCbHonorCamelHumpsWhenSelectingByClicking;

  private JPanel myHighlightSettingsPanel;
  private JRadioButton myRbPreferScrolling;
  private JRadioButton myRbPreferMovingCaret;
  private JCheckBox myCbRenameLocalVariablesInplace;
  private JCheckBox myCbHighlightIdentifierUnderCaret;
  private JCheckBox myCbEnsureBlankLineBeforeCheckBox;
  private JCheckBox myShowNotificationAfterReformatCodeCheckBox;
  private JCheckBox myShowNotificationAfterOptimizeImportsCheckBox;
  private JCheckBox myCbUseSoftWrapsAtEditor;
  private JCheckBox myCbUseCustomSoftWrapIndent;
  private JTextField myCustomSoftWrapIndent;
  private JLabel myCustomSoftWrapIndentLabel;
  private JCheckBox myCbShowSoftWrapsOnlyOnCaretLine;
  private JCheckBox myPreselectCheckBox;
  private JBCheckBox myCbShowQuickDocOnMouseMove;
  private JBLabel myQuickDocDelayLabel;
  private JTextField myQuickDocDelayTextField;
  private JComboBox myRichCopyColorSchemeComboBox;
  private JCheckBox myShowInlineDialogForCheckBox;
  private JBLabel myStripTrailingSpacesExplanationLabel;
  private JCheckBox myCbEnableRichCopyByDefault;
  private JCheckBox myShowLSTInGutterCheckBox;
  private JCheckBox myShowWhitespacesModificationsInLSTGutterCheckBox;

  private static final String ACTIVE_COLOR_SCHEME =
      ApplicationBundle.message("combobox.richcopy.color.scheme.active");

  private final ErrorHighlightingPanel myErrorHighlightingPanel = new ErrorHighlightingPanel();
  private final MyConfigurable myConfigurable;

  public EditorOptionsPanel() {
    if (SystemInfo.isMac) {
      myCbEnableWheelFontChange.setText(
          ApplicationBundle.message("checkbox.enable.ctrl.mousewheel.changes.font.size.macos"));
    }

    myStripTrailingSpacesCombo.addItem(STRIP_CHANGED);
    myStripTrailingSpacesCombo.addItem(STRIP_ALL);
    myStripTrailingSpacesCombo.addItem(STRIP_NONE);
    ActionListener explainer =
        new ActionListener() {
          @Override
          public void actionPerformed(ActionEvent e) {
            explainTrailingSpaces(getStripTrailingSpacesValue());
          }
        };
    myStripTrailingSpacesCombo.addActionListener(explainer);
    myCbVirtualSpace.addActionListener(explainer);

    myHighlightSettingsPanel.setLayout(new BorderLayout());
    myHighlightSettingsPanel.add(myErrorHighlightingPanel.getPanel(), BorderLayout.CENTER);

    myCbRenameLocalVariablesInplace.setVisible(
        OptionsApplicabilityFilter.isApplicable(OptionId.RENAME_IN_PLACE));

    myRichCopyColorSchemeComboBox.setRenderer(
        new ListCellRendererWrapper<String>() {
          @Override
          public void customize(
              JList list, String value, int index, boolean selected, boolean hasFocus) {
            final String textToUse;
            if (RichCopySettings.ACTIVE_GLOBAL_SCHEME_MARKER.equals(value)) {
              textToUse = ACTIVE_COLOR_SCHEME;
            } else {
              textToUse = value;
            }
            setText(textToUse);
          }
        });

    myConfigurable = new MyConfigurable();
    initQuickDocProcessing();
    initSoftWrapsSettingsProcessing();
    initVcsSettingsProcessing();
  }

  public void reset() {
    EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
    CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance();
    UISettings uiSettings = UISettings.getInstance();
    VcsApplicationSettings vcsSettings = VcsApplicationSettings.getInstance();

    // Display

    myCbSmoothScrolling.setSelected(editorSettings.isSmoothScrolling());

    // Brace highlighting

    myCbHighlightBraces.setSelected(codeInsightSettings.HIGHLIGHT_BRACES);
    myCbHighlightScope.setSelected(codeInsightSettings.HIGHLIGHT_SCOPE);
    myCbHighlightIdentifierUnderCaret.setSelected(
        codeInsightSettings.HIGHLIGHT_IDENTIFIER_UNDER_CARET);

    // Virtual space

    myCbUseSoftWrapsAtEditor.setSelected(
        editorSettings.isUseSoftWraps(SoftWrapAppliancePlaces.MAIN_EDITOR));
    myCbUseCustomSoftWrapIndent.setSelected(editorSettings.isUseCustomSoftWrapIndent());
    myCustomSoftWrapIndent.setText(Integer.toString(editorSettings.getCustomSoftWrapIndent()));
    myCbShowSoftWrapsOnlyOnCaretLine.setSelected(!editorSettings.isAllSoftWrapsShown());
    updateSoftWrapSettingsRepresentation();

    myCbVirtualSpace.setSelected(editorSettings.isVirtualSpace());
    myCbCaretInsideTabs.setSelected(editorSettings.isCaretInsideTabs());
    myCbVirtualPageAtBottom.setSelected(editorSettings.isAdditionalPageAtBottom());

    // Limits
    myClipboardContentLimitTextField.setText(Integer.toString(uiSettings.MAX_CLIPBOARD_CONTENTS));

    // Strip trailing spaces on save

    String stripTrailingSpaces = editorSettings.getStripTrailingSpaces();
    if (EditorSettingsExternalizable.STRIP_TRAILING_SPACES_NONE.equals(stripTrailingSpaces)) {
      myStripTrailingSpacesCombo.setSelectedItem(STRIP_NONE);
    } else if (EditorSettingsExternalizable.STRIP_TRAILING_SPACES_CHANGED.equals(
        stripTrailingSpaces)) {
      myStripTrailingSpacesCombo.setSelectedItem(STRIP_CHANGED);
    } else if (EditorSettingsExternalizable.STRIP_TRAILING_SPACES_WHOLE.equals(
        stripTrailingSpaces)) {
      myStripTrailingSpacesCombo.setSelectedItem(STRIP_ALL);
    }
    explainTrailingSpaces(stripTrailingSpaces);

    myCbEnsureBlankLineBeforeCheckBox.setSelected(editorSettings.isEnsureNewLineAtEOF());
    myCbShowQuickDocOnMouseMove.setSelected(editorSettings.isShowQuickDocOnMouseOverElement());
    myQuickDocDelayTextField.setText(
        Long.toString(editorSettings.getQuickDocOnMouseOverElementDelayMillis()));
    myQuickDocDelayTextField.setEnabled(editorSettings.isShowQuickDocOnMouseOverElement());
    myQuickDocDelayLabel.setEnabled(editorSettings.isShowQuickDocOnMouseOverElement());

    // Advanced mouse
    myCbEnableDnD.setSelected(editorSettings.isDndEnabled());
    myCbEnableWheelFontChange.setSelected(editorSettings.isWheelFontChangeEnabled());
    myCbHonorCamelHumpsWhenSelectingByClicking.setSelected(
        editorSettings.isMouseClickSelectionHonorsCamelWords());

    myRbPreferMovingCaret.setSelected(editorSettings.isRefrainFromScrolling());
    myRbPreferScrolling.setSelected(!editorSettings.isRefrainFromScrolling());

    myRecentFilesLimitField.setText(Integer.toString(uiSettings.RECENT_FILES_LIMIT));

    myCbRenameLocalVariablesInplace.setSelected(editorSettings.isVariableInplaceRenameEnabled());
    myPreselectCheckBox.setSelected(editorSettings.isPreselectRename());
    myShowInlineDialogForCheckBox.setSelected(editorSettings.isShowInlineLocalDialog());

    myShowNotificationAfterReformatCodeCheckBox.setSelected(
        editorSettings.getOptions().SHOW_NOTIFICATION_AFTER_REFORMAT_CODE_ACTION);
    myShowNotificationAfterOptimizeImportsCheckBox.setSelected(
        editorSettings.getOptions().SHOW_NOTIFICATION_AFTER_OPTIMIZE_IMPORTS_ACTION);

    myShowLSTInGutterCheckBox.setSelected(vcsSettings.SHOW_LST_GUTTER_MARKERS);
    myShowWhitespacesModificationsInLSTGutterCheckBox.setSelected(
        vcsSettings.SHOW_WHITESPACES_IN_LST);
    myShowWhitespacesModificationsInLSTGutterCheckBox.setEnabled(
        myShowLSTInGutterCheckBox.isSelected());

    myErrorHighlightingPanel.reset();

    RichCopySettings settings = RichCopySettings.getInstance();
    myCbEnableRichCopyByDefault.setSelected(settings.isEnabled());
    myRichCopyColorSchemeComboBox.removeAllItems();
    EditorColorsScheme[] schemes = EditorColorsManager.getInstance().getAllSchemes();
    myRichCopyColorSchemeComboBox.addItem(RichCopySettings.ACTIVE_GLOBAL_SCHEME_MARKER);
    for (EditorColorsScheme scheme : schemes) {
      myRichCopyColorSchemeComboBox.addItem(scheme.getName());
    }
    String toSelect = settings.getSchemeName();
    if (!StringUtil.isEmpty(toSelect)) {
      myRichCopyColorSchemeComboBox.setSelectedItem(toSelect);
    }
  }

  private void explainTrailingSpaces(
      @NotNull @EditorSettingsExternalizable.StripTrailingSpaces String stripTrailingSpaces) {
    if (EditorSettingsExternalizable.STRIP_TRAILING_SPACES_NONE.equals(stripTrailingSpaces)) {
      myStripTrailingSpacesExplanationLabel.setVisible(false);
      return;
    }
    myStripTrailingSpacesExplanationLabel.setVisible(true);
    boolean isVirtualSpace = myCbVirtualSpace.isSelected();
    String text;
    String virtSpaceText = myCbVirtualSpace.getText();
    if (isVirtualSpace) {
      text =
          "Trailing spaces will be trimmed even in the line under caret.<br>To disable trimming in that line uncheck the '<b>"
              + virtSpaceText
              + "</b>' above.";
    } else {
      text =
          "Trailing spaces will <b><font color=red>NOT</font></b> be trimmed in the line under caret.<br>To enable trimming in that line too check the '<b>"
              + virtSpaceText
              + "</b>' above.";
    }
    myStripTrailingSpacesExplanationLabel.setText(XmlStringUtil.wrapInHtml(text));
  }

  public void apply() throws ConfigurationException {
    EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
    CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance();
    UISettings uiSettings = UISettings.getInstance();
    VcsApplicationSettings vcsSettings = VcsApplicationSettings.getInstance();

    // Display

    editorSettings.setSmoothScrolling(myCbSmoothScrolling.isSelected());

    // Brace Highlighting

    codeInsightSettings.HIGHLIGHT_BRACES = myCbHighlightBraces.isSelected();
    codeInsightSettings.HIGHLIGHT_SCOPE = myCbHighlightScope.isSelected();
    codeInsightSettings.HIGHLIGHT_IDENTIFIER_UNDER_CARET =
        myCbHighlightIdentifierUnderCaret.isSelected();
    clearAllIdentifierHighlighters();

    // Virtual space

    editorSettings.setUseSoftWraps(
        myCbUseSoftWrapsAtEditor.isSelected(), SoftWrapAppliancePlaces.MAIN_EDITOR);
    editorSettings.setUseCustomSoftWrapIndent(myCbUseCustomSoftWrapIndent.isSelected());
    editorSettings.setCustomSoftWrapIndent(getCustomSoftWrapIndent());
    editorSettings.setAllSoftwrapsShown(!myCbShowSoftWrapsOnlyOnCaretLine.isSelected());
    editorSettings.setVirtualSpace(myCbVirtualSpace.isSelected());
    editorSettings.setCaretInsideTabs(myCbCaretInsideTabs.isSelected());
    editorSettings.setAdditionalPageAtBottom(myCbVirtualPageAtBottom.isSelected());

    // Limits

    boolean uiSettingsChanged = false;
    int maxClipboardContents = getMaxClipboardContents();
    if (uiSettings.MAX_CLIPBOARD_CONTENTS != maxClipboardContents) {
      uiSettings.MAX_CLIPBOARD_CONTENTS = maxClipboardContents;
      uiSettingsChanged = true;
    }

    if (uiSettingsChanged) {
      uiSettings.fireUISettingsChanged();
    }

    // Strip trailing spaces on save

    if (STRIP_NONE.equals(myStripTrailingSpacesCombo.getSelectedItem())) {
      editorSettings.setStripTrailingSpaces(
          EditorSettingsExternalizable.STRIP_TRAILING_SPACES_NONE);
    } else if (STRIP_CHANGED.equals(myStripTrailingSpacesCombo.getSelectedItem())) {
      editorSettings.setStripTrailingSpaces(
          EditorSettingsExternalizable.STRIP_TRAILING_SPACES_CHANGED);
    } else {
      editorSettings.setStripTrailingSpaces(
          EditorSettingsExternalizable.STRIP_TRAILING_SPACES_WHOLE);
    }

    editorSettings.setEnsureNewLineAtEOF(myCbEnsureBlankLineBeforeCheckBox.isSelected());

    if (myCbShowQuickDocOnMouseMove.isSelected()
        ^ editorSettings.isShowQuickDocOnMouseOverElement()) {
      boolean enabled = myCbShowQuickDocOnMouseMove.isSelected();
      editorSettings.setShowQuickDocOnMouseOverElement(enabled);
      ServiceManager.getService(QuickDocOnMouseOverManager.class).setEnabled(enabled);
    }

    Long quickDocDelay = getQuickDocDelayFromGui();
    if (quickDocDelay != null) {
      editorSettings.setQuickDocOnMouseOverElementDelayMillis(quickDocDelay);
    }

    editorSettings.setDndEnabled(myCbEnableDnD.isSelected());

    editorSettings.setWheelFontChangeEnabled(myCbEnableWheelFontChange.isSelected());
    editorSettings.setMouseClickSelectionHonorsCamelWords(
        myCbHonorCamelHumpsWhenSelectingByClicking.isSelected());
    editorSettings.setRefrainFromScrolling(myRbPreferMovingCaret.isSelected());

    editorSettings.setVariableInplaceRenameEnabled(myCbRenameLocalVariablesInplace.isSelected());
    editorSettings.setPreselectRename(myPreselectCheckBox.isSelected());
    editorSettings.setShowInlineLocalDialog(myShowInlineDialogForCheckBox.isSelected());

    editorSettings.getOptions().SHOW_NOTIFICATION_AFTER_REFORMAT_CODE_ACTION =
        myShowNotificationAfterReformatCodeCheckBox.isSelected();
    editorSettings.getOptions().SHOW_NOTIFICATION_AFTER_OPTIMIZE_IMPORTS_ACTION =
        myShowNotificationAfterOptimizeImportsCheckBox.isSelected();

    boolean updateVcsSettings = false;
    if (vcsSettings.SHOW_WHITESPACES_IN_LST
        != myShowWhitespacesModificationsInLSTGutterCheckBox.isSelected()) {
      vcsSettings.SHOW_WHITESPACES_IN_LST =
          myShowWhitespacesModificationsInLSTGutterCheckBox.isSelected();
      updateVcsSettings = true;
    }
    if (vcsSettings.SHOW_LST_GUTTER_MARKERS != myShowLSTInGutterCheckBox.isSelected()) {
      vcsSettings.SHOW_LST_GUTTER_MARKERS = myShowLSTInGutterCheckBox.isSelected();
      updateVcsSettings = true;
    }
    if (updateVcsSettings) {
      ApplicationManager.getApplication()
          .getMessageBus()
          .syncPublisher(LineStatusTrackerSettingListener.TOPIC)
          .settingsUpdated();
    }

    reinitAllEditors();

    String temp = myRecentFilesLimitField.getText();
    if (temp.trim().length() > 0) {
      try {
        int newRecentFilesLimit = Integer.parseInt(temp);
        if (newRecentFilesLimit > 0 && uiSettings.RECENT_FILES_LIMIT != newRecentFilesLimit) {
          uiSettings.RECENT_FILES_LIMIT = newRecentFilesLimit;
          uiSettingsChanged = true;
        }
      } catch (NumberFormatException ignored) {
      }
    }
    if (uiSettingsChanged) {
      uiSettings.fireUISettingsChanged();
    }

    myErrorHighlightingPanel.apply();

    RichCopySettings settings = RichCopySettings.getInstance();
    settings.setEnabled(myCbEnableRichCopyByDefault.isSelected());
    Object item = myRichCopyColorSchemeComboBox.getSelectedItem();
    if (item instanceof String) {
      settings.setSchemeName(item.toString());
    }

    restartDaemons();
  }

  @Nullable
  private Long getQuickDocDelayFromGui() {
    String quickDocDelayAsText = myQuickDocDelayTextField.getText();
    if (StringUtil.isEmptyOrSpaces(quickDocDelayAsText)) {
      return null;
    }

    try {
      long delay = Long.parseLong(quickDocDelayAsText);
      return delay > 0 ? delay : null;
    } catch (NumberFormatException e) {
      // Ignore incorrect value.
      return null;
    }
  }

  public static void restartDaemons() {
    Project[] projects = ProjectManager.getInstance().getOpenProjects();
    for (Project project : projects) {
      DaemonCodeAnalyzer.getInstance(project).settingsChanged();
    }
  }

  private static void clearAllIdentifierHighlighters() {
    for (Project project : ProjectManager.getInstance().getOpenProjects()) {
      for (FileEditor fileEditor : FileEditorManager.getInstance(project).getAllEditors()) {
        if (fileEditor instanceof TextEditor) {
          Document document = ((TextEditor) fileEditor).getEditor().getDocument();
          IdentifierHighlighterPass.clearMyHighlights(document, project);
        }
      }
    }
  }

  public static void reinitAllEditors() {
    Editor[] editors = EditorFactory.getInstance().getAllEditors();
    for (Editor editor : editors) {
      ((EditorEx) editor).reinitSettings();
    }
  }

  public void disposeUIResources() {
    myErrorHighlightingPanel.disposeUIResources();
  }

  private int getMaxClipboardContents() {
    int maxClipboardContents = -1;
    try {
      maxClipboardContents = Integer.parseInt(myClipboardContentLimitTextField.getText());
    } catch (NumberFormatException ignored) {
    }
    if (maxClipboardContents <= 0) {
      maxClipboardContents = 1;
    }
    return maxClipboardContents;
  }

  public boolean isModified() {
    EditorSettingsExternalizable editorSettings = EditorSettingsExternalizable.getInstance();
    CodeInsightSettings codeInsightSettings = CodeInsightSettings.getInstance();
    UISettings uiSettings = UISettings.getInstance();
    VcsApplicationSettings vcsSettings = VcsApplicationSettings.getInstance();

    // Display
    boolean isModified = isModified(myCbSmoothScrolling, editorSettings.isSmoothScrolling());

    // Brace highlighting
    isModified |= isModified(myCbHighlightBraces, codeInsightSettings.HIGHLIGHT_BRACES);
    isModified |= isModified(myCbHighlightScope, codeInsightSettings.HIGHLIGHT_SCOPE);
    isModified |=
        isModified(
            myCbHighlightIdentifierUnderCaret,
            codeInsightSettings.HIGHLIGHT_IDENTIFIER_UNDER_CARET);

    // Virtual space
    isModified |=
        isModified(
            myCbUseSoftWrapsAtEditor,
            editorSettings.isUseSoftWraps(SoftWrapAppliancePlaces.MAIN_EDITOR));
    isModified |=
        isModified(myCbUseCustomSoftWrapIndent, editorSettings.isUseCustomSoftWrapIndent());
    isModified |= editorSettings.getCustomSoftWrapIndent() != getCustomSoftWrapIndent();
    isModified |=
        isModified(myCbShowSoftWrapsOnlyOnCaretLine, !editorSettings.isAllSoftWrapsShown());
    isModified |= isModified(myCbVirtualSpace, editorSettings.isVirtualSpace());
    isModified |= isModified(myCbCaretInsideTabs, editorSettings.isCaretInsideTabs());
    isModified |= isModified(myCbVirtualPageAtBottom, editorSettings.isAdditionalPageAtBottom());

    // Limits

    isModified |= getMaxClipboardContents() != uiSettings.MAX_CLIPBOARD_CONTENTS;

    // Paste

    // Strip trailing spaces, ensure EOL on EOF on save
    isModified |= !getStripTrailingSpacesValue().equals(editorSettings.getStripTrailingSpaces());
    isModified |=
        isModified(myCbEnsureBlankLineBeforeCheckBox, editorSettings.isEnsureNewLineAtEOF());

    isModified |=
        isModified(myCbShowQuickDocOnMouseMove, editorSettings.isShowQuickDocOnMouseOverElement());
    Long quickDocDelay = getQuickDocDelayFromGui();
    if (quickDocDelay != null
        && !quickDocDelay.equals(
            Long.valueOf(editorSettings.getQuickDocOnMouseOverElementDelayMillis()))) {
      return true;
    }

    // advanced mouse
    isModified |= isModified(myCbEnableDnD, editorSettings.isDndEnabled());
    isModified |= isModified(myCbEnableWheelFontChange, editorSettings.isWheelFontChangeEnabled());
    isModified |=
        isModified(
            myCbHonorCamelHumpsWhenSelectingByClicking,
            editorSettings.isMouseClickSelectionHonorsCamelWords());

    isModified |= myRbPreferMovingCaret.isSelected() != editorSettings.isRefrainFromScrolling();

    isModified |= isModified(myRecentFilesLimitField, UISettings.getInstance().RECENT_FILES_LIMIT);
    isModified |=
        isModified(
            myCbRenameLocalVariablesInplace, editorSettings.isVariableInplaceRenameEnabled());
    isModified |= isModified(myPreselectCheckBox, editorSettings.isPreselectRename());
    isModified |=
        isModified(myShowInlineDialogForCheckBox, editorSettings.isShowInlineLocalDialog());

    isModified |=
        isModified(
            myShowNotificationAfterReformatCodeCheckBox,
            editorSettings.getOptions().SHOW_NOTIFICATION_AFTER_REFORMAT_CODE_ACTION);
    isModified |=
        isModified(
            myShowNotificationAfterOptimizeImportsCheckBox,
            editorSettings.getOptions().SHOW_NOTIFICATION_AFTER_OPTIMIZE_IMPORTS_ACTION);

    isModified |= isModified(myShowLSTInGutterCheckBox, vcsSettings.SHOW_LST_GUTTER_MARKERS);
    isModified |=
        isModified(
            myShowWhitespacesModificationsInLSTGutterCheckBox, vcsSettings.SHOW_WHITESPACES_IN_LST);

    isModified |= myErrorHighlightingPanel.isModified();

    RichCopySettings settings = RichCopySettings.getInstance();
    isModified |= isModified(myCbEnableRichCopyByDefault, settings.isEnabled());
    isModified |=
        !Comparing.equal(settings.getSchemeName(), myRichCopyColorSchemeComboBox.getSelectedItem());

    return isModified;
  }

  private static boolean isModified(JToggleButton checkBox, boolean value) {
    return checkBox.isSelected() != value;
  }

  private static boolean isModified(JTextField textField, int value) {
    try {
      int fieldValue = Integer.parseInt(textField.getText().trim());
      return fieldValue != value;
    } catch (NumberFormatException e) {
      return false;
    }
  }

  @NotNull
  @EditorSettingsExternalizable.StripTrailingSpaces
  private String getStripTrailingSpacesValue() {
    Object selectedItem = myStripTrailingSpacesCombo.getSelectedItem();
    if (STRIP_NONE.equals(selectedItem)) {
      return EditorSettingsExternalizable.STRIP_TRAILING_SPACES_NONE;
    }
    if (STRIP_CHANGED.equals(selectedItem)) {
      return EditorSettingsExternalizable.STRIP_TRAILING_SPACES_CHANGED;
    }
    return EditorSettingsExternalizable.STRIP_TRAILING_SPACES_WHOLE;
  }

  private int getCustomSoftWrapIndent() {
    String indentAsString = myCustomSoftWrapIndent.getText();
    int defaultIndent = 0;
    if (indentAsString == null) {
      return defaultIndent;
    }
    try {
      int indent = Integer.parseInt(indentAsString.trim());
      return indent >= 0 ? indent : defaultIndent;
    } catch (IllegalArgumentException e) {
      // Ignore
    }
    return defaultIndent;
  }

  private void initQuickDocProcessing() {
    myCbShowQuickDocOnMouseMove.addItemListener(
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            myQuickDocDelayTextField.setEnabled(myCbShowQuickDocOnMouseMove.isSelected());
            myQuickDocDelayLabel.setEnabled(myCbShowQuickDocOnMouseMove.isSelected());
          }
        });
  }

  private void initSoftWrapsSettingsProcessing() {
    ItemListener listener =
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            updateSoftWrapSettingsRepresentation();
          }
        };
    myCbUseSoftWrapsAtEditor.addItemListener(listener);
    myCbUseCustomSoftWrapIndent.addItemListener(listener);
  }

  private void updateSoftWrapSettingsRepresentation() {
    boolean softWrapsEnabled = myCbUseSoftWrapsAtEditor.isSelected();
    myCbUseCustomSoftWrapIndent.setEnabled(softWrapsEnabled);
    myCustomSoftWrapIndent.setEnabled(
        myCbUseCustomSoftWrapIndent.isEnabled() && myCbUseCustomSoftWrapIndent.isSelected());
    myCustomSoftWrapIndentLabel.setEnabled(myCustomSoftWrapIndent.isEnabled());
    myCbShowSoftWrapsOnlyOnCaretLine.setEnabled(softWrapsEnabled);
  }

  private void initVcsSettingsProcessing() {
    myShowLSTInGutterCheckBox.addItemListener(
        new ItemListener() {
          @Override
          public void itemStateChanged(ItemEvent e) {
            myShowWhitespacesModificationsInLSTGutterCheckBox.setEnabled(
                myShowLSTInGutterCheckBox.isSelected());
          }
        });
  }

  public JComponent getComponent() {
    return myBehaviourPanel;
  }

  public class MyConfigurable implements SearchableConfigurable {
    @Override
    @NotNull
    public String getId() {
      return "Editor.Behavior";
    }

    @Override
    public Runnable enableSearch(final String option) {
      return null;
    }

    @Override
    public String getDisplayName() {
      return ApplicationBundle.message("tab.editor.settings.behavior");
    }

    @Override
    public String getHelpTopic() {
      return null;
    }

    @Override
    public JComponent createComponent() {
      return myBehaviourPanel;
    }

    @Override
    public boolean isModified() {
      return EditorOptionsPanel.this.isModified();
    }

    @Override
    public void apply() throws ConfigurationException {
      EditorOptionsPanel.this.apply();
    }

    @Override
    public void reset() {
      EditorOptionsPanel.this.reset();
    }

    @Override
    public void disposeUIResources() {
      EditorOptionsPanel.this.disposeUIResources();
    }
  }
}