コード例 #1
0
 /** Creates a new instance of SaveAllAction */
 public SaveAllAction(JabRefFrame frame) {
   super(IconTheme.getImage("saveAll"));
   this.frame = frame;
   putValue(Action.ACCELERATOR_KEY, Globals.prefs.getKey("Save all"));
   putValue(Action.SHORT_DESCRIPTION, Localization.lang("Save all open databases"));
   putValue(Action.NAME, Localization.menuTitle("Save all"));
 }
コード例 #2
0
/**
 * Dialog to display search results, potentially from more than one BasePanel, with possibility to
 * preview and to locate each entry in the main window.
 *
 * <p>TODO: should be possible to save or export the list.
 */
public class SearchResultsDialog {

  private final JabRefFrame frame;

  private JDialog diag;
  private final String[] fields = new String[] {"author", "title", "year", "journal"};
  private final int FILE_COL = 0;
  private final int URL_COL = 1;
  private final int PAD = 2;
  private final JLabel fileLabel = new JLabel(IconTheme.getImage("psSmall"));
  private final JLabel urlLabel = new JLabel(IconTheme.getImage("wwwSmall"));

  private final Rectangle toRect = new Rectangle(0, 0, 1, 1);

  private EventTableModel<BibtexEntry> model;
  private final EventList<BibtexEntry> entries = new BasicEventList<BibtexEntry>();
  private SortedList<BibtexEntry> sortedEntries;
  private final HashMap<BibtexEntry, BasePanel> entryHome = new HashMap<BibtexEntry, BasePanel>();

  private JTable entryTable;
  private final JSplitPane contentPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
  private PreviewPanel preview;

  public SearchResultsDialog(JabRefFrame frame, String title) {

    this.frame = frame;

    init(title);
  }

  private void init(String title) {
    diag = new JDialog(frame, title, false);

    int activePreview = Globals.prefs.getInt(JabRefPreferences.ACTIVE_PREVIEW);
    preview =
        new PreviewPanel(
            null,
            new MetaData(),
            activePreview == 0
                ? Globals.prefs.get(JabRefPreferences.PREVIEW_0)
                : Globals.prefs.get(JabRefPreferences.PREVIEW_1));

    sortedEntries =
        new SortedList<BibtexEntry>(entries, new EntryComparator(false, true, "author"));
    model = new EventTableModel<BibtexEntry>(sortedEntries, new EntryTableFormat());
    entryTable = new JTable(model);
    GeneralRenderer renderer = new GeneralRenderer(Color.white);
    entryTable.setDefaultRenderer(JLabel.class, renderer);
    entryTable.setDefaultRenderer(String.class, renderer);
    setWidths();
    TableComparatorChooser<BibtexEntry> tableSorter =
        TableComparatorChooser.install(
            entryTable, sortedEntries, AbstractTableComparatorChooser.MULTIPLE_COLUMN_KEYBOARD);
    setupComparatorChooser(tableSorter);
    JScrollPane sp = new JScrollPane(entryTable);

    final EventSelectionModel<BibtexEntry> selectionModel =
        new EventSelectionModel<BibtexEntry>(sortedEntries);
    entryTable.setSelectionModel(selectionModel);
    selectionModel.getSelected().addListEventListener(new EntrySelectionListener());
    entryTable.addMouseListener(new TableClickListener());

    contentPane.setTopComponent(sp);
    contentPane.setBottomComponent(preview);

    // Key bindings:
    AbstractAction closeAction =
        new AbstractAction() {

          @Override
          public void actionPerformed(ActionEvent e) {
            diag.dispose();
          }
        };
    ActionMap am = contentPane.getActionMap();
    InputMap im = contentPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
    im.put(Globals.prefs.getKey("Close dialog"), "close");
    am.put("close", closeAction);

    entryTable
        .getActionMap()
        .put(
            "copy",
            new AbstractAction() {

              @Override
              public void actionPerformed(ActionEvent e) {
                if (!selectionModel.getSelected().isEmpty()) {
                  BibtexEntry[] bes =
                      selectionModel
                          .getSelected()
                          .toArray(new BibtexEntry[selectionModel.getSelected().size()]);
                  TransferableBibtexEntry trbe = new TransferableBibtexEntry(bes);
                  // ! look at ClipBoardManager
                  Toolkit.getDefaultToolkit()
                      .getSystemClipboard()
                      .setContents(trbe, frame.basePanel());
                  frame.output(
                      Localization.lang("Copied")
                          + ' '
                          + (bes.length > 1
                              ? bes.length + " " + Localization.lang("entries")
                              : "1 " + Localization.lang("entry") + '.'));
                }
              }
            });

    diag.addWindowListener(
        new WindowAdapter() {

          @Override
          public void windowOpened(WindowEvent e) {
            contentPane.setDividerLocation(0.5f);
          }

          @Override
          public void windowClosing(WindowEvent event) {
            Globals.prefs.putInt(JabRefPreferences.SEARCH_DIALOG_WIDTH, diag.getSize().width);
            Globals.prefs.putInt(JabRefPreferences.SEARCH_DIALOG_HEIGHT, diag.getSize().height);
          }
        });

    diag.getContentPane().add(contentPane, BorderLayout.CENTER);
    // Remember and default to last size:
    diag.setSize(
        new Dimension(
            Globals.prefs.getInt(JabRefPreferences.SEARCH_DIALOG_WIDTH),
            Globals.prefs.getInt(JabRefPreferences.SEARCH_DIALOG_HEIGHT)));
    diag.setLocationRelativeTo(frame);
  }

  /**
   * Control the visibility of the dialog.
   *
   * @param visible true to show dialog, false to hide.
   */
  public void setVisible(boolean visible) {
    diag.setVisible(visible);
  }

  public void selectFirstEntry() {
    if (entryTable.getRowCount() > 0) {
      entryTable.setRowSelectionInterval(0, 0);
    } else {
      contentPane.setDividerLocation(1.0f);
    }
  }

  /** Remove all entries from the table. */
  public synchronized void clear() {
    entries.clear();
    entryHome.clear();
  }

  /**
   * Set up the comparators for each column, so the user can modify sort order by clicking the
   * column labels.
   *
   * @param comparatorChooser The comparator chooser controlling the sort order.
   */
  @SuppressWarnings("unchecked")
  private void setupComparatorChooser(TableComparatorChooser<BibtexEntry> comparatorChooser) {
    // First column:
    java.util.List<Comparator> comparators = comparatorChooser.getComparatorsForColumn(0);
    comparators.clear();

    comparators = comparatorChooser.getComparatorsForColumn(1);
    comparators.clear();

    // Icon columns:
    for (int i = 2; i < PAD; i++) {
      comparators = comparatorChooser.getComparatorsForColumn(i);
      comparators.clear();
      if (i == FILE_COL) {
        comparators.add(new IconComparator(new String[] {Globals.FILE_FIELD}));
      } else if (i == URL_COL) {
        comparators.add(new IconComparator(new String[] {"url"}));
      }
    }
    // Remaining columns:
    for (int i = PAD; i < (PAD + fields.length); i++) {
      comparators = comparatorChooser.getComparatorsForColumn(i);
      comparators.clear();
      comparators.add(new FieldComparator(fields[i - PAD]));
    }

    sortedEntries.getReadWriteLock().writeLock().lock();
    comparatorChooser.appendComparator(PAD, 0, false);
    sortedEntries.getReadWriteLock().writeLock().unlock();
  }

  /**
   * Set column widths according to which field is shown, and lock icon columns to a suitable width.
   */
  private void setWidths() {
    TableColumnModel cm = entryTable.getColumnModel();
    for (int i = 0; i < PAD; i++) {
      cm.getColumn(i).setPreferredWidth(GUIGlobals.WIDTH_ICON_COL);
      cm.getColumn(i).setMinWidth(GUIGlobals.WIDTH_ICON_COL);
      cm.getColumn(i).setMaxWidth(GUIGlobals.WIDTH_ICON_COL);
    }

    for (int i = 0; i < fields.length; i++) {
      int width = BibtexFields.getFieldLength(fields[i]);
      cm.getColumn(i + PAD).setPreferredWidth(width);
    }
  }

  /**
   * Add a list of entries to the table.
   *
   * @param newEntries The list of entries.
   * @param panel A reference to the BasePanel where the entries belong.
   */
  public synchronized void addEntries(java.util.List<BibtexEntry> newEntries, BasePanel panel) {
    for (BibtexEntry entry : newEntries) {
      entries.add(entry);
      entryHome.put(entry, panel);
    }
  }

  /**
   * Add a single entry to the table.
   *
   * @param entry The entry to add.
   * @param panel A reference to the BasePanel where the entry belongs.
   */
  public synchronized void addEntry(BibtexEntry entry, BasePanel panel) {
    entries.add(entry);
    entryHome.put(entry, panel);
  }

  /**
   * Mouse listener for the entry table. Processes icon clicks to open external files or urls, as
   * well as the opening of the context menu.
   */
  class TableClickListener extends MouseAdapter {

    @Override
    public void mouseReleased(MouseEvent e) {
      if (e.isPopupTrigger()) {
        processPopupTrigger(e);
      }
    }

    @Override
    public void mousePressed(MouseEvent e) {
      if (e.isPopupTrigger()) {
        processPopupTrigger(e);
        return;
      }

      // First find the row on which the user has clicked.
      final int row = entryTable.rowAtPoint(e.getPoint());

      // A double click on an entry should highlight the entry in its BasePanel:
      if (e.getClickCount() == 2) {
        // Get the selected entry:
        BibtexEntry toShow = model.getElementAt(row);
        // Look up which BasePanel it belongs to:
        BasePanel p = entryHome.get(toShow);
        // Show the correct tab in the main window:
        frame.showBasePanel(p);
        // Highlight the entry:
        p.highlightEntry(toShow);
      }
    }

    @Override
    public void mouseClicked(MouseEvent e) {
      if (e.isPopupTrigger()) {
        processPopupTrigger(e);
        return;
      }
      // if (e.)
      final int col = entryTable.columnAtPoint(e.getPoint());
      final int row = entryTable.rowAtPoint(e.getPoint());
      if (col < PAD) {
        BibtexEntry entry = sortedEntries.get(row);
        BasePanel p = entryHome.get(entry);
        switch (col) {
          case FILE_COL:
            Object o = entry.getField(Globals.FILE_FIELD);
            if (o != null) {
              FileListTableModel tableModel = new FileListTableModel();
              tableModel.setContent((String) o);
              if (tableModel.getRowCount() == 0) {
                return;
              }
              FileListEntry fl = tableModel.getEntry(0);
              (new ExternalFileMenuItem(
                      frame, entry, "", fl.getLink(), null, p.metaData(), fl.getType()))
                  .actionPerformed(null);
            }
            break;
          case URL_COL:
            Object link = entry.getField("url");
            try {
              if (link != null) {
                JabRefDesktop.openExternalViewer(p.metaData(), (String) link, "url");
              }
            } catch (IOException ex) {
              ex.printStackTrace();
            }
            break;
        }
      }
    }

    /**
     * If the user has signalled the opening of a context menu, the event gets redirected to this
     * method. Here we open a file link menu if the user is pointing at a file link icon. Otherwise
     * a general context menu should be shown.
     *
     * @param e The triggering mouse event.
     */
    public void processPopupTrigger(MouseEvent e) {
      BibtexEntry entry = sortedEntries.get(entryTable.rowAtPoint(e.getPoint()));
      BasePanel p = entryHome.get(entry);
      int col = entryTable.columnAtPoint(e.getPoint());
      JPopupMenu menu = new JPopupMenu();
      int count = 0;

      if (col == FILE_COL) {
        // We use a FileListTableModel to parse the field content:
        Object o = entry.getField(Globals.FILE_FIELD);
        FileListTableModel fileList = new FileListTableModel();
        fileList.setContent((String) o);
        // If there are one or more links, open the first one:
        for (int i = 0; i < fileList.getRowCount(); i++) {
          FileListEntry flEntry = fileList.getEntry(i);
          String description = flEntry.getDescription();
          if ((description == null) || (description.trim().isEmpty())) {
            description = flEntry.getLink();
          }
          menu.add(
              new ExternalFileMenuItem(
                  p.frame(),
                  entry,
                  description,
                  flEntry.getLink(),
                  flEntry.getType().getIcon(),
                  p.metaData(),
                  flEntry.getType()));
          count++;
        }
      }

      if (count > 0) {
        menu.show(entryTable, e.getX(), e.getY());
      }
    }
  }

  /**
   * The listener for the Glazed list monitoring the current selection. When selection changes, we
   * need to update the preview panel.
   */
  private class EntrySelectionListener implements ListEventListener<BibtexEntry> {

    @Override
    public void listChanged(ListEvent<BibtexEntry> listEvent) {
      if (listEvent.getSourceList().size() == 1) {
        BibtexEntry entry = listEvent.getSourceList().get(0);
        // Find out which BasePanel the selected entry belongs to:
        BasePanel p = entryHome.get(entry);
        // Update the preview's metadata reference:
        preview.setMetaData(p.metaData());
        // Update the preview's entry:
        preview.setEntry(entry);
        contentPane.setDividerLocation(0.5f);
        SwingUtilities.invokeLater(
            new Runnable() {

              @Override
              public void run() {
                preview.scrollRectToVisible(toRect);
              }
            });
      }
    }
  }

  /**
   * TableFormat for the table shown in the dialog. Handles the display of entry fields and icons
   * for linked files and urls.
   */
  private class EntryTableFormat implements AdvancedTableFormat<BibtexEntry> {

    @Override
    public int getColumnCount() {
      return PAD + fields.length;
    }

    @Override
    public String getColumnName(int column) {
      if (column >= PAD) {
        return StringUtil.capitalizeFirst(fields[column - PAD]);
      } else {
        return "";
      }
    }

    @Override
    public Object getColumnValue(BibtexEntry entry, int column) {
      if (column < PAD) {
        Object o;
        switch (column) {
          case FILE_COL:
            o = entry.getField(Globals.FILE_FIELD);
            if (o != null) {
              FileListTableModel model = new FileListTableModel();
              model.setContent((String) o);
              fileLabel.setToolTipText(model.getToolTipHTMLRepresentation());
              if (model.getRowCount() > 0) {
                fileLabel.setIcon(model.getEntry(0).getType().getIcon());
              }
              return fileLabel;
            } else {
              return null;
            }
          case URL_COL:
            o = entry.getField("url");
            if (o != null) {
              urlLabel.setToolTipText((String) o);
              return urlLabel;
            } else {
              return null;
            }
          default:
            return null;
        }
      } else {
        String field = fields[column - PAD];
        if (field.equals("author") || field.equals("editor")) {
          // For name fields, tap into a MainTableFormat instance and use
          // the same name formatting as is used in the entry table:
          if (frame.basePanel() != null) {
            return frame.basePanel().tableFormat.formatName(entry.getField(field));
          }
        }
        return entry.getField(field);
      }
    }

    @Override
    public Class<?> getColumnClass(int i) {
      if (i < PAD) {
        return JLabel.class;
      } else {
        return String.class;
      }
    }

    @Override
    public Comparator<?> getColumnComparator(int i) {
      return null;
    }
  }
}