/** * Checks if the two entries represent the same publication. * * @param one BibEntry * @param two BibEntry * @return boolean */ public static boolean isDuplicate(BibEntry one, BibEntry two, BibDatabaseMode bibDatabaseMode) { // First check if they are of the same type - a necessary condition: if (!one.getType().equals(two.getType())) { return false; } EntryType type = EntryTypes.getTypeOrDefault(one.getType(), bibDatabaseMode); // The check if they have the same required fields: java.util.List<String> var = type.getRequiredFieldsFlat(); String[] fields = var.toArray(new String[var.size()]); double[] req; if (fields == null) { req = new double[] {0., 0.}; } else { req = DuplicateCheck.compareFieldSet(fields, one, two); } if (Math.abs(req[0] - DuplicateCheck.duplicateThreshold) > DuplicateCheck.DOUBT_RANGE) { // Far from the threshold value, so we base our decision on the req. fields only return req[0] >= DuplicateCheck.duplicateThreshold; } // Close to the threshold value, so we take a look at the optional fields, if any: java.util.List<String> optionalFields = type.getOptionalFields(); fields = optionalFields.toArray(new String[optionalFields.size()]); if (fields != null) { double[] opt = DuplicateCheck.compareFieldSet(fields, one, two); double totValue = ((DuplicateCheck.REQUIRED_WEIGHT * req[0] * req[1]) + (opt[0] * opt[1])) / ((req[1] * DuplicateCheck.REQUIRED_WEIGHT) + opt[1]); return totValue >= DuplicateCheck.duplicateThreshold; } return req[0] >= DuplicateCheck.duplicateThreshold; }
private Optional<BibEntry> createNewEntry() { // Find out what type is desired EntryTypeDialog etd = new EntryTypeDialog(frame); // We want to center the dialog, to make it look nicer. etd.setLocationRelativeTo(frame); etd.setVisible(true); EntryType type = etd.getChoice(); if (type != null) { // Only if the dialog was not canceled. String id = IdGenerator.next(); final BibEntry bibEntry = new BibEntry(id, type.getName()); try { panel.getDatabase().insertEntry(bibEntry); // Set owner/timestamp if options are enabled: List<BibEntry> list = new ArrayList<>(); list.add(bibEntry); UpdateField.setAutomaticFields(list, true, true, Globals.prefs.getUpdateFieldPreferences()); // Create an UndoableInsertEntry object. panel .getUndoManager() .addEdit(new UndoableInsertEntry(panel.getDatabase(), bibEntry, panel)); panel.output( Localization.lang("Added new") + " '" + type.getName().toLowerCase() + "' " + Localization.lang("entry") + "."); // We are going to select the new entry. Before that, make sure that we are in // show-entry mode. If we aren't already in that mode, enter the WILL_SHOW_EDITOR // mode which makes sure the selection will trigger display of the entry editor // and adjustment of the splitter. if (panel.getMode() != BasePanelMode.SHOWING_EDITOR) { panel.setMode(BasePanelMode.WILL_SHOW_EDITOR); } SwingUtilities.invokeLater(() -> panel.showEntry(bibEntry)); // The database just changed. panel.markBaseChanged(); return Optional.of(bibEntry); } catch (KeyCollisionException ex) { LOGGER.info("Key collision occurred", ex); } } return Optional.empty(); }
private JTextField addEntryType(Container c, EntryType type, int y) { JLabel lab = new JLabel(type.getName()); con.gridx = 0; con.gridy = y; con.fill = GridBagConstraints.BOTH; con.weightx = 0; con.weighty = 0; con.anchor = GridBagConstraints.WEST; con.insets = new Insets(0, 5, 0, 5); gbl.setConstraints(lab, con); c.add(lab); JTextField tf = new JTextField(); tf.setColumns(15); con.gridx = 1; con.fill = GridBagConstraints.HORIZONTAL; con.weightx = 1; con.weighty = 0; con.anchor = GridBagConstraints.CENTER; con.insets = new Insets(0, 5, 0, 5); gbl.setConstraints(tf, con); c.add(tf); JButton but = new JButton(Localization.lang("Default")); con.gridx = 2; con.fill = GridBagConstraints.BOTH; con.weightx = 0; con.weighty = 0; con.anchor = GridBagConstraints.CENTER; con.insets = new Insets(0, 5, 0, 5); gbl.setConstraints(but, con); but.setActionCommand(type.getName().toLowerCase()); but.addActionListener( e -> { JTextField tField = textFields.get(e.getActionCommand()); tField.setText(""); }); c.add(but); return tf; }
private void buildGUI() { JPanel pan = new JPanel(); JScrollPane sp = new JScrollPane(pan); sp.setPreferredSize(new Dimension(100, 100)); sp.setBorder(BorderFactory.createEmptyBorder()); pan.setLayout(gbl); setLayout(gbl); // The header - can be removed JLabel lblEntryType = new JLabel(Localization.lang("Entry type")); Font f = new Font("plain", Font.BOLD, 12); lblEntryType.setFont(f); con.gridx = 0; con.gridy = 0; con.gridwidth = 1; con.gridheight = 1; con.fill = GridBagConstraints.VERTICAL; con.anchor = GridBagConstraints.WEST; con.insets = new Insets(5, 5, 10, 0); gbl.setConstraints(lblEntryType, con); pan.add(lblEntryType); JLabel lblKeyPattern = new JLabel(Localization.lang("Key pattern")); lblKeyPattern.setFont(f); con.gridx = 1; con.gridy = 0; con.gridheight = 1; con.fill = GridBagConstraints.HORIZONTAL; con.anchor = GridBagConstraints.WEST; con.insets = new Insets(5, 5, 10, 5); gbl.setConstraints(lblKeyPattern, con); pan.add(lblKeyPattern); con.gridy = 1; con.gridx = 0; JLabel lab = new JLabel(Localization.lang("Default pattern")); gbl.setConstraints(lab, con); pan.add(lab); con.gridx = 1; gbl.setConstraints(defaultPat, con); pan.add(defaultPat); con.insets = new Insets(5, 5, 10, 5); JButton btnDefault = new JButton(Localization.lang("Default")); btnDefault.addActionListener( e -> defaultPat.setText( (String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN))); con.gridx = 2; int y = 2; gbl.setConstraints(btnDefault, con); pan.add(btnDefault); BibDatabaseMode mode; // check mode of currently used DB if (panel != null) { mode = panel.getBibDatabaseContext().getMode(); } else { // use preferences value if no DB is open mode = Globals.prefs.getDefaultBibDatabaseMode(); } for (EntryType type : EntryTypes.getAllValues(mode)) { textFields.put(type.getName().toLowerCase(), addEntryType(pan, type, y)); y++; } con.fill = GridBagConstraints.BOTH; con.gridx = 0; con.gridy = 1; con.gridwidth = 3; con.weightx = 1; con.weighty = 1; gbl.setConstraints(sp, con); add(sp); // A help button con.gridwidth = 1; con.gridx = 1; con.gridy = 2; con.fill = GridBagConstraints.HORIZONTAL; // con.weightx = 0; con.weighty = 0; con.anchor = GridBagConstraints.SOUTHEAST; con.insets = new Insets(0, 5, 0, 5); JButton hlb = new JButton(IconTheme.JabRefIcon.HELP.getSmallIcon()); hlb.setToolTipText(Localization.lang("Help on key patterns")); gbl.setConstraints(hlb, con); add(hlb); hlb.addActionListener(help); // And finally a button to reset everything JButton btnDefaultAll = new JButton(Localization.lang("Reset all")); con.gridx = 2; con.gridy = 2; con.weightx = 1; con.weighty = 0; con.anchor = GridBagConstraints.SOUTHEAST; con.insets = new Insets(20, 5, 0, 5); gbl.setConstraints(btnDefaultAll, con); btnDefaultAll.addActionListener( e -> { // reset all fields for (JTextField field : textFields.values()) { field.setText(""); } // also reset the default pattern defaultPat.setText( (String) Globals.prefs.defaults.get(JabRefPreferences.DEFAULT_BIBTEX_KEY_PATTERN)); }); add(btnDefaultAll); }
/** Main function for building the merge entry JPanel */ private void initialize() { joint = new TreeSet<>(one.getFieldNames()); joint.addAll(two.getFieldNames()); // Remove field starting with __ TreeSet<String> toberemoved = new TreeSet<>(); for (String field : joint) { if (field.startsWith("__")) { toberemoved.add(field); } } for (String field : toberemoved) { joint.remove(field); } // Create storage arrays rb = new JRadioButton[3][joint.size() + 1]; ButtonGroup[] rbg = new ButtonGroup[joint.size() + 1]; identical = new Boolean[joint.size() + 1]; jointStrings = new String[joint.size()]; // Create main layout String colSpecMain = "left:pref, 5px, center:3cm:grow, 5px, center:pref, 3px, center:pref, 3px, center:pref, 5px, center:3cm:grow"; String colSpecMerge = "left:pref, 5px, fill:3cm:grow, 5px, center:pref, 3px, center:pref, 3px, center:pref, 5px, fill:3cm:grow"; String rowSpec = "pref, pref, 10px, fill:5cm:grow, 10px, pref, 10px, fill:3cm:grow"; StringBuilder rowBuilder = new StringBuilder(""); for (int i = 0; i < joint.size(); i++) { rowBuilder.append("pref, "); } rowBuilder.append("pref"); FormLayout mainLayout = new FormLayout(colSpecMain, rowSpec); FormLayout mergeLayout = new FormLayout(colSpecMerge, rowBuilder.toString()); mainPanel.setLayout(mainLayout); mergePanel.setLayout(mergeLayout); JLabel label = new JLabel(Localization.lang("Use")); Font font = label.getFont(); label.setFont(font.deriveFont(font.getStyle() | Font.BOLD)); mainPanel.add(label, cc.xyw(4, 1, 7, "center, bottom")); // Set headings JLabel headingLabels[] = new JLabel[6]; for (int i = 0; i < 6; i++) { headingLabels[i] = new JLabel(columnHeadings[i]); font = headingLabels[i].getFont(); headingLabels[i].setFont(font.deriveFont(font.getStyle() | Font.BOLD)); mainPanel.add(headingLabels[i], cc.xy(1 + (i * 2), 2)); } mainPanel.add(new JSeparator(), cc.xyw(1, 3, 11)); // Start with entry type EntryType type1 = one.getType(); EntryType type2 = two.getType(); mergedEntry.setType(type1); label = new JLabel(Localization.lang("Entry type")); font = label.getFont(); label.setFont(font.deriveFont(font.getStyle() | Font.BOLD)); mergePanel.add(label, cc.xy(1, 1)); JTextArea type1ta = new JTextArea(type1.getName()); type1ta.setEditable(false); mergePanel.add(type1ta, cc.xy(3, 1)); if (type1.compareTo(type2) != 0) { identical[0] = false; rbg[0] = new ButtonGroup(); for (int k = 0; k < 3; k += 2) { rb[k][0] = new JRadioButton(); rbg[0].add(rb[k][0]); mergePanel.add(rb[k][0], cc.xy(5 + (k * 2), 1)); rb[k][0].addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateAll(); } }); } rb[0][0].setSelected(true); } else { identical[0] = true; } JTextArea type2ta = new JTextArea(type2.getName()); type2ta.setEditable(false); mergePanel.add(type2ta, cc.xy(11, 1)); // For all fields in joint add a row and possibly radio buttons int row = 2; int maxLabelWidth = -1; int tmpLabelWidth = 0; for (String field : joint) { jointStrings[row - 2] = field; label = new JLabel(CaseChangers.UPPER_FIRST.format(field)); font = label.getFont(); label.setFont(font.deriveFont(font.getStyle() | Font.BOLD)); mergePanel.add(label, cc.xy(1, row)); String string1 = one.getField(field); String string2 = two.getField(field); identical[row - 1] = false; if ((string1 != null) && (string2 != null)) { if (string1.equals(string2)) { identical[row - 1] = true; } } tmpLabelWidth = label.getPreferredSize().width; if (tmpLabelWidth > maxLabelWidth) { maxLabelWidth = tmpLabelWidth; } if ("abstract".equals(field) || "review".equals(field)) { // Treat the abstract and review fields special JTextArea tf = new JTextArea(); tf.setLineWrap(true); tf.setEditable(false); JScrollPane jsptf = new JScrollPane(tf); mergeLayout.setRowSpec(row, RowSpec.decode("center:2cm:grow")); mergePanel.add(jsptf, cc.xy(3, row, "f, f")); tf.setText(string1); tf.setCaretPosition(0); } else { JTextArea tf = new JTextArea(string1); mergePanel.add(tf, cc.xy(3, row)); tf.setCaretPosition(0); tf.setEditable(false); } // Add radio buttons if the two entries do not have identical fields if (!identical[row - 1]) { rbg[row - 1] = new ButtonGroup(); for (int k = 0; k < 3; k++) { rb[k][row - 1] = new JRadioButton(); rbg[row - 1].add(rb[k][row - 1]); mergePanel.add(rb[k][row - 1], cc.xy(5 + (k * 2), row)); rb[k][row - 1].addChangeListener( new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { updateAll(); } }); } if (string1 != null) { mergedEntry.setField(field, string1); rb[0][row - 1].setSelected(true); if (string2 == null) { rb[2][row - 1].setEnabled(false); } } else { rb[0][row - 1].setEnabled(false); mergedEntry.setField(field, string2); rb[2][row - 1].setSelected(true); } } else { mergedEntry.setField(field, string1); } if ("abstract".equals(field) || "review".equals(field)) { // Again, treat abstract and review special JTextArea tf = new JTextArea(); tf.setLineWrap(true); tf.setEditable(false); JScrollPane jsptf = new JScrollPane(tf); mergePanel.add(jsptf, cc.xy(11, row, "f, f")); tf.setText(string2); tf.setCaretPosition(0); } else { JTextArea tf = new JTextArea(string2); mergePanel.add(tf, cc.xy(11, row)); tf.setCaretPosition(0); tf.setEditable(false); } row++; } JScrollPane scrollPane = new JScrollPane( mergePanel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); scrollPane.setBorder(BorderFactory.createEmptyBorder()); mainPanel.add(scrollPane, cc.xyw(1, 4, 11)); mainPanel.add(new JSeparator(), cc.xyw(1, 5, 11)); // Synchronize column widths String rbAlign[] = {"right", "center", "left"}; mainLayout.setColumnSpec(1, ColumnSpec.decode(Integer.toString(maxLabelWidth) + "px")); Integer maxRBWidth = -1; Integer tmpRBWidth; for (int k = 0; k < 3; k++) { tmpRBWidth = headingLabels[k + 2].getPreferredSize().width; if (tmpRBWidth > maxRBWidth) { maxRBWidth = tmpRBWidth; } } for (int k = 0; k < 3; k++) { mergeLayout.setColumnSpec( 5 + (k * 2), ColumnSpec.decode(rbAlign[k] + ":" + maxRBWidth + "px")); } // Setup a PreviewPanel and a Bibtex source box for the merged entry label = new JLabel(Localization.lang("Merged entry")); font = label.getFont(); label.setFont(font.deriveFont(font.getStyle() | Font.BOLD)); mainPanel.add(label, cc.xyw(1, 6, 6)); String layoutString = Globals.prefs.get(JabRefPreferences.PREVIEW_0); pp = new PreviewPanel(null, mergedEntry, null, new MetaData(), layoutString); // JScrollPane jsppp = new JScrollPane(pp, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, // JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); mainPanel.add(pp, cc.xyw(1, 8, 6)); label = new JLabel(Localization.lang("Merged BibTeX source code")); font = label.getFont(); label.setFont(font.deriveFont(font.getStyle() | Font.BOLD)); mainPanel.add(label, cc.xyw(8, 6, 4)); jta = new JTextArea(); jta.setLineWrap(true); JScrollPane jspta = new JScrollPane(jta); mainPanel.add(jspta, cc.xyw(8, 8, 4)); jta.setEditable(false); StringWriter sw = new StringWriter(); try { new BibtexEntryWriter(new LatexFieldFormatter(), false).write(mergedEntry, sw); } catch (IOException ex) { LOGGER.error("Error in entry" + ": " + ex.getMessage(), ex); } jta.setText(sw.getBuffer().toString()); jta.setCaretPosition(0); // Add some margin around the layout mainLayout.appendRow(RowSpec.decode("10px")); mainLayout.appendColumn(ColumnSpec.decode("10px")); mainLayout.insertRow(1, RowSpec.decode("10px")); mainLayout.insertColumn(1, ColumnSpec.decode("10px")); if (mainPanel.getHeight() > DIM.height) { mainPanel.setSize(new Dimension(mergePanel.getWidth(), DIM.height)); } if (mainPanel.getWidth() > DIM.width) { mainPanel.setSize(new Dimension(DIM.width, mergePanel.getHeight())); } // Everything done, allow any action to actually update the merged entry doneBuilding = true; // Show what we've got mainPanel.setVisible(true); javax.swing.SwingUtilities.invokeLater( new Runnable() { @Override public void run() { scrollPane.getVerticalScrollBar().setValue(0); } }); }
public ChangeTypeAction(EntryType type, BasePanel bp) { super(type.getName()); this.type = type.getName(); panel = bp; }