@Override
  public void saveAllDocuments() {
    ApplicationManager.getApplication().assertIsDispatchThread();

    myMultiCaster.beforeAllDocumentsSaving();
    if (myUnsavedDocuments.isEmpty()) return;

    final Map<Document, IOException> failedToSave = new HashMap<Document, IOException>();
    final Set<Document> vetoed = new HashSet<Document>();
    while (true) {
      int count = 0;

      for (Document document : myUnsavedDocuments) {
        if (failedToSave.containsKey(document)) continue;
        if (vetoed.contains(document)) continue;
        try {
          doSaveDocument(document);
        } catch (IOException e) {
          //noinspection ThrowableResultOfMethodCallIgnored
          failedToSave.put(document, e);
        } catch (SaveVetoException e) {
          vetoed.add(document);
        }
        count++;
      }

      if (count == 0) break;
    }

    if (!failedToSave.isEmpty()) {
      handleErrorsOnSave(failedToSave);
    }
  }
 private void releaseAllEditors() {
   for (final Editor editor : myEditors.values()) {
     if (!editor.isDisposed()) {
       EditorFactory.getInstance().releaseEditor(editor);
     }
   }
   myEditors.clear();
 }
 private PropertiesFile getSelectedPropertiesFile() {
   if (mySelectedEditor == null) return null;
   PropertiesFile selectedFile = null;
   for (Map.Entry<PropertiesFile, Editor> entry : myEditors.entrySet()) {
     Editor editor = entry.getValue();
     if (editor == mySelectedEditor) {
       selectedFile = entry.getKey();
       break;
     }
   }
   return selectedFile;
 }
  private void updateEditorsFromProperties() {
    String propertyName = getSelectedPropertyName();
    ((CardLayout) myValuesPanel.getLayout())
        .show(myValuesPanel, propertyName == null ? NO_PROPERTY_SELECTED : VALUES);
    if (propertyName == null) return;

    for (final PropertiesFile propertiesFile : myResourceBundle.getPropertiesFiles(myProject)) {
      final EditorEx editor = (EditorEx) myEditors.get(propertiesFile);
      if (editor == null) continue;
      final IProperty property = propertiesFile.findPropertyByKey(propertyName);
      final Document document = editor.getDocument();
      CommandProcessor.getInstance()
          .executeCommand(
              null,
              new Runnable() {
                @Override
                public void run() {
                  ApplicationManager.getApplication()
                      .runWriteAction(
                          new Runnable() {
                            @Override
                            public void run() {
                              updateDocumentFromPropertyValue(
                                  getPropertyEditorValue(property), document, propertiesFile);
                            }
                          });
                }
              },
              "",
              this);

      JPanel titledPanel = myTitledPanels.get(propertiesFile);
      ((TitledBorder) titledPanel.getBorder())
          .setTitleColor(property == null ? JBColor.RED : UIUtil.getLabelTextForeground());
      titledPanel.repaint();
    }
  }
  @Override
  public void dispose() {
    if (mySelectedEditor != null) {
      for (final Map.Entry<PropertiesFile, Editor> entry : myEditors.entrySet()) {
        if (mySelectedEditor.equals(entry.getValue())) {
          writeEditorPropertyValue(mySelectedEditor, entry.getKey(), null);
        }
      }
    }

    VirtualFileManager.getInstance().removeVirtualFileListener(myVfsListener);
    myDisposed = true;
    Disposer.dispose(myStructureViewComponent);
    releaseAllEditors();
  }
  protected void handleErrorsOnSave(@NotNull Map<Document, IOException> failures) {
    for (IOException exception : failures.values()) {
      LOG.warn(exception);
    }

    final String text =
        StringUtil.join(
            failures.values(),
            new Function<IOException, String>() {
              @Override
              public String fun(IOException e) {
                return e.getMessage();
              }
            },
            "\n");

    final DialogWrapper dialog =
        new DialogWrapper(null) {
          {
            init();
            setTitle(UIBundle.message("cannot.save.files.dialog.title"));
          }

          @Override
          protected void createDefaultActions() {
            super.createDefaultActions();
            myOKAction.putValue(
                Action.NAME,
                UIBundle.message(
                    myOnClose
                        ? "cannot.save.files.dialog.ignore.changes"
                        : "cannot.save.files.dialog.revert.changes"));
            myOKAction.putValue(DEFAULT_ACTION, null);

            if (!myOnClose) {
              myCancelAction.putValue(Action.NAME, CommonBundle.getCloseButtonText());
            }
          }

          @Override
          protected JComponent createCenterPanel() {
            final JPanel panel = new JPanel(new BorderLayout(0, 5));

            panel.add(
                new JLabel(UIBundle.message("cannot.save.files.dialog.message")),
                BorderLayout.NORTH);

            final JTextPane area = new JTextPane();
            area.setText(text);
            area.setEditable(false);
            area.setMinimumSize(new Dimension(area.getMinimumSize().width, 50));
            panel.add(
                new JBScrollPane(
                    area,
                    ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
                    ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER),
                BorderLayout.CENTER);

            return panel;
          }
        };

    dialog.show();

    if (dialog.isOK()) {
      for (Document document : failures.keySet()) {
        reloadFromDisk(document);
      }
    }
  }
  private void recreateEditorsPanel() {
    myValuesPanel.removeAll();
    myValuesPanel.setLayout(new CardLayout());

    if (!myProject.isOpen()) return;
    JPanel valuesPanelComponent = new MyJPanel(new GridBagLayout());
    myValuesPanel.add(
        new JBScrollPane(valuesPanelComponent) {
          @Override
          public void updateUI() {
            super.updateUI();
            getViewport().setBackground(UIUtil.getPanelBackground());
          }
        },
        VALUES);
    myValuesPanel.add(myNoPropertySelectedPanel, NO_PROPERTY_SELECTED);

    List<PropertiesFile> propertiesFiles = myResourceBundle.getPropertiesFiles();

    GridBagConstraints gc =
        new GridBagConstraints(
            0,
            0,
            0,
            0,
            0,
            0,
            GridBagConstraints.NORTHWEST,
            GridBagConstraints.BOTH,
            new Insets(5, 5, 5, 5),
            0,
            0);
    releaseAllEditors();
    myTitledPanels.clear();
    int y = 0;
    Editor previousEditor = null;
    Editor firstEditor = null;
    for (final PropertiesFile propertiesFile : propertiesFiles) {
      final Editor editor = createEditor();
      final Editor oldEditor = myEditors.put(propertiesFile, editor);
      if (firstEditor == null) {
        firstEditor = editor;
      }
      if (previousEditor != null) {
        editor.putUserData(
            ChooseSubsequentPropertyValueEditorAction.PREV_EDITOR_KEY, previousEditor);
        previousEditor.putUserData(
            ChooseSubsequentPropertyValueEditorAction.NEXT_EDITOR_KEY, editor);
      }
      previousEditor = editor;
      if (oldEditor != null) {
        EditorFactory.getInstance().releaseEditor(oldEditor);
      }
      ((EditorEx) editor)
          .addFocusListener(
              new FocusChangeListener() {
                @Override
                public void focusGained(final Editor editor) {
                  mySelectedEditor = editor;
                }

                @Override
                public void focusLost(final Editor eventEditor) {
                  writeEditorPropertyValue(editor, propertiesFile, null);
                }
              });
      gc.gridx = 0;
      gc.gridy = y++;
      gc.gridheight = 1;
      gc.gridwidth = GridBagConstraints.REMAINDER;
      gc.weightx = 1;
      gc.weighty = 1;
      gc.anchor = GridBagConstraints.CENTER;

      Locale locale = propertiesFile.getLocale();
      List<String> names = new ArrayList<String>();
      if (!Comparing.strEqual(locale.getDisplayLanguage(), null)) {
        names.add(locale.getDisplayLanguage());
      }
      if (!Comparing.strEqual(locale.getDisplayCountry(), null)) {
        names.add(locale.getDisplayCountry());
      }
      if (!Comparing.strEqual(locale.getDisplayVariant(), null)) {
        names.add(locale.getDisplayVariant());
      }

      String title = propertiesFile.getName();
      if (!names.isEmpty()) {
        title += " (" + StringUtil.join(names, "/") + ")";
      }
      JComponent comp =
          new JPanel(new BorderLayout()) {
            @Override
            public Dimension getPreferredSize() {
              Insets insets = getBorder().getBorderInsets(this);
              return new Dimension(100, editor.getLineHeight() * 4 + insets.top + insets.bottom);
            }
          };
      comp.add(editor.getComponent(), BorderLayout.CENTER);
      comp.setBorder(IdeBorderFactory.createTitledBorder(title, true));
      myTitledPanels.put(propertiesFile, (JPanel) comp);

      valuesPanelComponent.add(comp, gc);
    }
    if (previousEditor != null) {
      previousEditor.putUserData(
          ChooseSubsequentPropertyValueEditorAction.NEXT_EDITOR_KEY, firstEditor);
      firstEditor.putUserData(
          ChooseSubsequentPropertyValueEditorAction.PREV_EDITOR_KEY, previousEditor);
    }

    gc.gridx = 0;
    gc.gridy = y;
    gc.gridheight = GridBagConstraints.REMAINDER;
    gc.gridwidth = GridBagConstraints.REMAINDER;
    gc.weightx = 10;
    gc.weighty = 1;

    valuesPanelComponent.add(new JPanel(), gc);
    selectionChanged();
    myValuesPanel.repaint();
    UIUtil.invokeAndWaitIfNeeded(
        new Runnable() {
          @Override
          public void run() {
            updateEditorsFromProperties();
          }
        });
  }