Example #1
0
 @Override
 public void operationCompleted(BasePanel panel) {
   if (couldNotConnect) {
     JOptionPane.showMessageDialog(
         panel.frame(),
         "<HTML>"
             + Localization.lang(
                 "Could not connect to a running gnuserv process. Make sure that "
                     + "Emacs or XEmacs is running,<BR>and that the server has been started "
                     + "(by running the command 'server-start'/'gnuserv-start').")
             + "</HTML>",
         Localization.lang("Error"),
         JOptionPane.ERROR_MESSAGE);
   } else if (couldNotCall) {
     JOptionPane.showMessageDialog(
         panel.frame(),
         Localization.lang(
             "Could not run the gnuclient/emacsclient program. Make sure you have "
                 + "the emacsclient/gnuclient program installed and available in the PATH."),
         Localization.lang("Error"),
         JOptionPane.ERROR_MESSAGE);
   } else {
     super.operationCompleted(panel);
   }
 }
  @Override
  public void actionPerformed(ActionEvent actionEvent) {
    setEnabled(false);
    panel.output(Localization.lang("Writing XMP-metadata..."));
    panel.frame().setProgressBarIndeterminate(true);
    panel.frame().setProgressBarVisible(true);
    BibEntry entry = editor.getEntry();

    // Make a list of all PDFs linked from this entry:
    List<File> files = new ArrayList<>();

    // First check the (legacy) "pdf" field:
    entry
        .getField(FieldName.PDF)
        .ifPresent(
            pdf ->
                FileUtil.expandFilename(
                        pdf,
                        panel
                            .getBibDatabaseContext()
                            .getFileDirectory(
                                FieldName.PDF, Globals.prefs.getFileDirectoryPreferences()))
                    .ifPresent(files::add));

    // Then check the "file" field:
    List<String> dirs =
        panel.getBibDatabaseContext().getFileDirectory(Globals.prefs.getFileDirectoryPreferences());
    if (entry.hasField(FieldName.FILE)) {
      FileListTableModel tm = new FileListTableModel();
      entry.getField(FieldName.FILE).ifPresent(tm::setContent);
      for (int j = 0; j < tm.getRowCount(); j++) {
        FileListEntry flEntry = tm.getEntry(j);
        if ((flEntry.type.isPresent()) && "pdf".equalsIgnoreCase(flEntry.type.get().getName())) {
          FileUtil.expandFilename(flEntry.link, dirs).ifPresent(files::add);
        }
      }
    }

    // We want to offload the actual work to a background thread, so we have a worker
    // thread:
    AbstractWorker worker = new WriteXMPWorker(files, entry);
    // Using Spin, we get a thread that gets synchronously offloaded to a new thread,
    // blocking the execution of this method:
    worker.getWorker().run();
    // After the worker thread finishes, we are unblocked and ready to print the
    // status message:
    panel.output(message);
    panel.frame().setProgressBarVisible(false);
    setEnabled(true);
  }
Example #3
0
  public void moveToGroup(List<BibEntry> entries, NamedCompound undoAll) {
    List<GroupTreeNode> groupsContainingEntries =
        node.getNode()
            .getRoot()
            .getContainingGroups(entries, false)
            .stream()
            .filter(node -> node.getGroup().supportsRemove())
            .collect(Collectors.toList());

    List<AbstractGroup> affectedGroups =
        groupsContainingEntries.stream().map(GroupTreeNode::getGroup).collect(Collectors.toList());
    affectedGroups.add(node.getNode().getGroup());
    if (!WarnAssignmentSideEffects.warnAssignmentSideEffects(affectedGroups, panel.frame())) {
      return; // user aborted operation
    }

    // first remove
    for (GroupTreeNode group : groupsContainingEntries) {
      Optional<EntriesGroupChange> undoRemove = group.getGroup().remove(entries);
      if (undoRemove.isPresent()) {
        undoAll.addEdit(UndoableChangeEntriesOfGroup.getUndoableEdit(node, undoRemove.get()));
      }
    }

    // then add
    Optional<EntriesGroupChange> undoAdd = node.addEntriesToGroup(entries);
    if (undoAdd.isPresent()) {
      undoAll.addEdit(UndoableChangeEntriesOfGroup.getUndoableEdit(node, undoAdd.get()));
    }
  }
Example #4
0
  public void addToGroup(List<BibEntry> entries, NamedCompound undo) {
    if (!WarnAssignmentSideEffects.warnAssignmentSideEffects(
        node.getNode().getGroup(), panel.frame())) {
      return; // user aborted operation
    }

    Optional<EntriesGroupChange> undoAdd = node.addEntriesToGroup(entries);
    if (undoAdd.isPresent()) {
      undo.addEdit(UndoableChangeEntriesOfGroup.getUndoableEdit(node, undoAdd.get()));
    }
  }
  /**
   * This method performs the actual changes.
   *
   * @param panel
   * @param pr
   * @param fileDir The path to the file directory to set, or null if it should not be set.
   */
  private void makeChanges(
      BasePanel panel,
      ParserResult pr,
      boolean upgradePrefs,
      boolean upgradeDatabase,
      String fileDir) {

    if (upgradeDatabase) {
      // Update file links links in the database:
      NamedCompound ce =
          Util.upgradePdfPsToFile(pr.getDatabase(), FileLinksUpgradeWarning.FIELDS_TO_LOOK_FOR);
      panel.undoManager.addEdit(ce);
      panel.markBaseChanged();
    }

    if (fileDir != null) {
      Globals.prefs.put(Globals.FILE_FIELD + Globals.DIR_SUFFIX, fileDir);
    }

    if (upgradePrefs) {
      // Exchange table columns:
      Globals.prefs.putBoolean(JabRefPreferences.FILE_COLUMN, Boolean.TRUE);

      // Modify General fields if necessary:
      // If we don't find the file field, insert it at the bottom of the first tab:
      if (!showsFileInGenFields()) {
        String gfs = Globals.prefs.get(JabRefPreferences.CUSTOM_TAB_FIELDS + "0");
        StringBuilder sb = new StringBuilder(gfs);
        if (!gfs.isEmpty()) {
          sb.append(";");
        }
        sb.append(Globals.FILE_FIELD);
        Globals.prefs.put(JabRefPreferences.CUSTOM_TAB_FIELDS + "0", sb.toString());
        Globals.prefs.updateEntryEditorTabList();
        panel.frame().removeCachedEntryEditors();
      }
      panel.frame().setupAllTables();
    }
  }
  @Override
  public void init() {
    Collection<BibEntry> col = panel.getDatabase().getEntries();
    goOn = true;
    sel = new ArrayList<>(col);

    // Ask about rules for the operation:
    if (optDiag == null) {
      optDiag =
          new SynchronizeFileField.OptionsDialog(panel.frame(), panel.getBibDatabaseContext());
    }
    optDiag.setLocationRelativeTo(panel.frame());
    optDiag.setVisible(true);
    if (optDiag.canceled()) {
      goOn = false;
      return;
    }
    autoSet = !optDiag.isAutoSetNone();
    checkExisting = optDiag.isCheckLinks();

    panel.output(Localization.lang("Synchronizing file links..."));
  }
  @Override
  public void update() {
    if (!goOn) {
      return;
    }

    panel.output(
        Localization.lang(
            "Finished synchronizing file links. Entries changed: %0.",
            String.valueOf(entriesChangedCount)));
    panel.frame().setProgressBarVisible(false);
    if (entriesChangedCount > 0) {
      panel.markBaseChanged();
    }
  }
  /**
   * Set up a mouse listener for opening an external viewer and fetching by DOI
   *
   * @param fieldEditor
   * @param panel
   * @return
   */
  public static Optional<JComponent> getDoiExtraComponent(
      BasePanel panel, EntryEditor entryEditor, FieldEditor fieldEditor) {
    JPanel controls = new JPanel();
    controls.setLayout(new BorderLayout());
    // open doi link
    JButton button = new JButton(Localization.lang("Open"));
    button.setEnabled(false);
    button.addActionListener(
        actionEvent -> {
          try {
            JabRefDesktop.openExternalViewer(
                panel.getBibDatabaseContext(), fieldEditor.getText(), fieldEditor.getFieldName());
          } catch (IOException ex) {
            panel.output(Localization.lang("Unable to open link."));
          }
        });
    // lookup doi
    JButton doiButton = new JButton(Localization.lang("Lookup DOI"));
    doiButton.addActionListener(
        actionEvent -> {
          Optional<DOI> doi = DOI.fromBibEntry(entryEditor.getEntry());
          if (doi.isPresent()) {
            entryEditor.getEntry().setField(FieldName.DOI, doi.get().getDOI());
          } else {
            panel
                .frame()
                .setStatus(
                    Localization.lang("No %0 found", FieldName.getDisplayName(FieldName.DOI)));
          }
        });
    // fetch bibtex data
    JButton fetchButton =
        new JButton(
            Localization.lang("Get BibTeX data from %0", FieldName.getDisplayName(FieldName.DOI)));
    fetchButton.setEnabled(false);
    fetchButton.addActionListener(
        actionEvent -> {
          BibEntry entry = entryEditor.getEntry();
          new FetchAndMergeEntry(entry, panel, FieldName.DOI);
        });

    controls.add(button, BorderLayout.NORTH);
    controls.add(doiButton, BorderLayout.CENTER);
    controls.add(fetchButton, BorderLayout.SOUTH);

    // enable/disable button
    JTextComponent doi = (JTextComponent) fieldEditor;

    doi.getDocument()
        .addDocumentListener(
            new DocumentListener() {
              @Override
              public void changedUpdate(DocumentEvent documentEvent) {
                checkDoi();
              }

              @Override
              public void insertUpdate(DocumentEvent documentEvent) {
                checkDoi();
              }

              @Override
              public void removeUpdate(DocumentEvent documentEvent) {
                checkDoi();
              }

              private void checkDoi() {
                Optional<DOI> doiUrl = DOI.build(doi.getText());
                if (doiUrl.isPresent()) {
                  button.setEnabled(true);
                  fetchButton.setEnabled(true);
                } else {
                  button.setEnabled(false);
                  fetchButton.setEnabled(false);
                }
              }
            });

    return Optional.of(controls);
  }
  /**
   * This method presents a dialog box explaining and offering to make the changes. If the user
   * confirms, the changes are performed.
   *
   * @param panel
   * @param parserResult
   */
  @Override
  public void performAction(BasePanel panel, ParserResult parserResult) {

    if (!isThereSomethingToBeDone()) {
      return; // Nothing to do, just return.
    }

    JCheckBox changeSettings =
        new JCheckBox(
            Localization.lang(
                "Change table column and General fields settings to use the new feature"),
            offerChangeSettings);
    JCheckBox changeDatabase =
        new JCheckBox(
            Localization.lang("Upgrade old external file links to use the new feature"),
            offerChangeDatabase);
    JCheckBox setFileDir =
        new JCheckBox(Localization.lang("Set main external file directory") + ":", offerSetFileDir);
    JTextField fileDir = new JTextField(30);
    JCheckBox doNotShowDialog =
        new JCheckBox(Localization.lang("Do not show these options in the future"), false);

    JPanel message = new JPanel();
    FormBuilder formBuilder = FormBuilder.create().layout(new FormLayout("left:pref", "p"));
    // Keep the formatting of these lines. Otherwise, strings have to be translated again.
    // See updated JabRef_en.properties modifications by python syncLang.py -s -u
    int row = 1;
    formBuilder
        .add(
            new JLabel(
                "<html>"
                    + Localization.lang("This database uses outdated file links.")
                    + "<br><br>"
                    + Localization.lang(
                        "JabRef no longer supports 'ps' or 'pdf' fields.<br>File links are now stored in the 'file' field and files are stored in an external file directory.<br>To make use of this feature, JabRef needs to upgrade file links.<br><br>")
                    + "<p>"
                    + Localization.lang("Do you want JabRef to do the following operations?")
                    + "</html>"))
        .xy(1, row);

    if (offerChangeSettings) {
      formBuilder.appendRows("2dlu, p");
      row += 2;
      formBuilder.add(changeSettings).xy(1, row);
    }
    if (offerChangeDatabase) {
      formBuilder.appendRows("2dlu, p");
      row += 2;
      formBuilder.add(changeDatabase).xy(1, row);
    }
    if (offerSetFileDir) {
      if (Globals.prefs.hasKey("pdfDirectory")) {
        fileDir.setText(Globals.prefs.get("pdfDirectory"));
      } else {
        fileDir.setText(Globals.prefs.get("psDirectory"));
      }
      JPanel builderPanel = new JPanel();
      builderPanel.add(setFileDir);
      builderPanel.add(fileDir);
      JButton browse = new JButton(Localization.lang("Browse"));
      browse.addActionListener(BrowseAction.buildForDir(fileDir));
      builderPanel.add(browse);
      formBuilder.appendRows("2dlu, p");
      row += 2;
      formBuilder.add(builderPanel).xy(1, row);
    }
    formBuilder.appendRows("6dlu, p");
    formBuilder.add(doNotShowDialog).xy(1, row + 2);

    message.add(formBuilder.build());

    int answer =
        JOptionPane.showConfirmDialog(
            panel.frame(), message, Localization.lang("Upgrade file"), JOptionPane.YES_NO_OPTION);
    if (doNotShowDialog.isSelected()) {
      Globals.prefs.putBoolean(JabRefPreferences.SHOW_FILE_LINKS_UPGRADE_WARNING, false);
    }

    if (answer == JOptionPane.YES_OPTION) {
      makeChanges(
          panel,
          parserResult,
          changeSettings.isSelected(),
          changeDatabase.isSelected(),
          setFileDir.isSelected() ? fileDir.getText() : null);
    }
  }
Example #10
0
 public CleanupAction(BasePanel panel, JabRefPreferences preferences) {
   this.panel = panel;
   this.frame = panel.frame();
   this.preferences = Objects.requireNonNull(preferences);
   this.presetPanel = new CleanupPresetPanel(CleanupPreset.loadFromPreferences(preferences));
 }
Example #11
0
 public CleanUpAction(BasePanel panel) {
   this.panel = panel;
   this.frame = panel.frame();
   initOptionsPanel();
 }
  @Override
  public void run() {
    if (!goOn) {
      panel.output(
          Localization.lang("This operation requires one or more entries to be selected."));
      return;
    }
    entriesChangedCount = 0;
    panel.frame().setProgressBarValue(0);
    panel.frame().setProgressBarVisible(true);
    int weightAutoSet = 10; // autoSet takes 10 (?) times longer than checkExisting
    int progressBarMax =
        (autoSet ? weightAutoSet * sel.size() : 0) + (checkExisting ? sel.size() : 0);
    panel.frame().setProgressBarMaximum(progressBarMax);
    int progress = 0;
    final NamedCompound ce = new NamedCompound(Localization.lang("Automatically set file links"));

    Set<BibEntry> changedEntries = new HashSet<>();

    // First we try to autoset fields
    if (autoSet) {
      Collection<BibEntry> entries = new ArrayList<>(sel);

      // Start the automatically setting process:
      Runnable r =
          AutoSetLinks.autoSetLinks(
              entries, ce, changedEntries, null, panel.getBibDatabaseContext(), null, null);
      JabRefExecutorService.INSTANCE.executeAndWait(r);
    }
    progress += sel.size() * weightAutoSet;
    panel.frame().setProgressBarValue(progress);
    // The following loop checks all external links that are already set.
    if (checkExisting) {
      boolean removeAllBroken = false;
      mainLoop:
      for (BibEntry aSel : sel) {
        panel.frame().setProgressBarValue(progress++);
        final String old = aSel.getField(Globals.FILE_FIELD);
        // Check if a extension is set:
        if ((old != null) && !(old.isEmpty())) {
          FileListTableModel tableModel = new FileListTableModel();
          tableModel.setContentDontGuessTypes(old);

          // We need to specify which directories to search in for Util.expandFilename:
          List<String> dirsS = panel.getBibDatabaseContext().getFileDirectory();
          List<File> dirs = new ArrayList<>();
          for (String dirs1 : dirsS) {
            dirs.add(new File(dirs1));
          }

          for (int j = 0; j < tableModel.getRowCount(); j++) {
            FileListEntry flEntry = tableModel.getEntry(j);
            // See if the link looks like an URL:
            boolean httpLink = flEntry.link.toLowerCase(Locale.ENGLISH).startsWith("http");
            if (httpLink) {
              continue; // Don't check the remote file.
              // TODO: should there be an option to check remote links?
            }

            // A variable to keep track of whether this link gets deleted:
            boolean deleted = false;

            // Get an absolute path representation:
            Optional<File> file = FileUtil.expandFilename(flEntry.link, dirsS);
            if ((!file.isPresent()) || !file.get().exists()) {
              int answer;
              if (removeAllBroken) {
                answer = 2; // We should delete this link.
              } else {
                answer =
                    JOptionPane.showOptionDialog(
                        panel.frame(),
                        Localization.lang(
                            "<HTML>Could not find file '%0'<BR>linked from entry '%1'</HTML>",
                            flEntry.link, aSel.getCiteKey()),
                        Localization.lang("Broken link"),
                        JOptionPane.YES_NO_CANCEL_OPTION,
                        JOptionPane.QUESTION_MESSAGE,
                        null,
                        brokenLinkOptions,
                        brokenLinkOptions[0]);
              }
              switch (answer) {
                case 1:
                  // Assign new file.
                  FileListEntryEditor flEditor =
                      new FileListEntryEditor(
                          panel.frame(), flEntry, false, true, panel.getBibDatabaseContext());
                  flEditor.setVisible(true, true);
                  break;
                case 2:
                  // Clear field:
                  tableModel.removeEntry(j);
                  deleted = true; // Make sure we don't investigate this link further.
                  j--; // Step back in the iteration, because we removed an entry.
                  break;
                case 3:
                  // Clear field:
                  tableModel.removeEntry(j);
                  deleted = true; // Make sure we don't investigate this link further.
                  j--; // Step back in the iteration, because we removed an entry.
                  removeAllBroken = true; // Notify for further cases.
                  break;
                default:
                  // Cancel
                  break mainLoop;
              }
            }

            // Unless we deleted this link, see if its file type is recognized:
            if (!deleted
                && flEntry.type.isPresent()
                && (flEntry.type.get() instanceof UnknownExternalFileType)) {
              String[] options =
                  new String[] {
                    Localization.lang("Define '%0'", flEntry.type.get().getName()),
                    Localization.lang("Change file type"),
                    Localization.lang("Cancel")
                  };
              String defOption = options[0];
              int answer =
                  JOptionPane.showOptionDialog(
                      panel.frame(),
                      Localization.lang(
                          "One or more file links are of the type '%0', which is undefined. What do you want to do?",
                          flEntry.type.get().getName()),
                      Localization.lang("Undefined file type"),
                      JOptionPane.YES_NO_CANCEL_OPTION,
                      JOptionPane.QUESTION_MESSAGE,
                      null,
                      options,
                      defOption);
              if (answer == JOptionPane.CANCEL_OPTION) {
                // User doesn't want to handle this unknown link type.
              } else if (answer == JOptionPane.YES_OPTION) {
                // User wants to define the new file type. Show the dialog:
                ExternalFileType newType =
                    new ExternalFileType(
                        flEntry.type.get().getName(),
                        "",
                        "",
                        "",
                        "new",
                        IconTheme.JabRefIcon.FILE.getSmallIcon());
                ExternalFileTypeEntryEditor editor =
                    new ExternalFileTypeEntryEditor(panel.frame(), newType);
                editor.setVisible(true);
                if (editor.okPressed()) {
                  // Get the old list of types, add this one, and update the list in prefs:
                  List<ExternalFileType> fileTypes =
                      new ArrayList<>(
                          ExternalFileTypes.getInstance().getExternalFileTypeSelection());
                  fileTypes.add(newType);
                  Collections.sort(fileTypes);
                  ExternalFileTypes.getInstance().setExternalFileTypes(fileTypes);
                  panel.getMainTable().repaint();
                }
              } else {
                // User wants to change the type of this link.
                // First get a model of all file links for this entry:
                FileListEntryEditor editor =
                    new FileListEntryEditor(
                        panel.frame(), flEntry, false, true, panel.getBibDatabaseContext());
                editor.setVisible(true, false);
              }
            }
          }

          if (!tableModel.getStringRepresentation().equals(old)) {
            // The table has been modified. Store the change:
            String toSet = tableModel.getStringRepresentation();
            if (toSet.isEmpty()) {
              ce.addEdit(new UndoableFieldChange(aSel, Globals.FILE_FIELD, old, null));
              aSel.clearField(Globals.FILE_FIELD);
            } else {
              ce.addEdit(new UndoableFieldChange(aSel, Globals.FILE_FIELD, old, toSet));
              aSel.setField(Globals.FILE_FIELD, toSet);
            }
            changedEntries.add(aSel);
          }
        }
      }
    }

    if (!changedEntries.isEmpty()) {
      // Add the undo edit:
      ce.end();
      panel.getUndoManager().addEdit(ce);
      panel.markBaseChanged();
      entriesChangedCount = changedEntries.size();
    }
  }