@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); }
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())); } }
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); } }
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)); }
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(); } }