2 Copyright (C) 2003 Morten O. Alver, Nizar N. Batada
4 All programs in this directory and
5 subdirectories are published under the GNU General Public License as
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or (at
11 your option) any later version.
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
23 Further information about the GNU GPL is available at:
24 http://www.gnu.org/copyleft/gpl.ja.html
28 package net.sf.jabref;
30 import net.sf.jabref.gui.*;
31 import net.sf.jabref.label.*;
32 import net.sf.jabref.export.FileActions;
33 import net.sf.jabref.export.ExpandEndnoteFilters;
34 import net.sf.jabref.imports.*;
35 import net.sf.jabref.wizard.auximport.gui.*;
40 import java.awt.event.*;
42 import java.util.List;
45 import net.sf.jabref.undo.NamedCompound;
46 import net.sf.jabref.undo.UndoableInsertEntry;
47 import net.sf.jabref.undo.UndoableRemoveEntry;
48 import net.sf.jabref.export.ExportCustomizationDialog;
49 import net.sf.jabref.export.ExportFormats;
51 import java.lang.reflect.*;
52 import javax.swing.event.*;
53 import net.sf.jabref.wizard.integrity.gui.*;
54 import net.sf.jabref.groups.GroupSelector;
55 import net.sf.jabref.groups.EntryTableTransferHandler;
56 import net.sf.jabref.journals.ManageJournalsAction;
57 import net.sf.jabref.external.*;
58 import net.sf.jabref.util.MassSetFieldAction;
59 import com.jgoodies.uif_lite.component.UIFSplitPane;
60 import com.jgoodies.looks.Options;
61 import com.jgoodies.looks.HeaderStyle;
65 * The main window of the application.
67 public class JabRefFrame extends JFrame {
70 JabRefFrame ths = this;
71 UIFSplitPane contentPane = new UIFSplitPane();
73 JabRefPreferences prefs = Globals.prefs; //new JabRefPreferences();
74 PrefsDialog3 prefsDialog = null;
76 private int lastTabbedPanelSelectionIndex = -1 ;
78 // The sidepane manager takes care of populating the sidepane.
79 public SidePaneManager sidePaneManager;
81 JTabbedPane tabbedPane = new JTabbedPane();
83 final Insets marg = new Insets(1,0,2,0);
85 class ToolBar extends JToolBar {
86 void addAction(Action a) {
87 JButton b = new JButton(a);
94 ToolBar tlb = new ToolBar();
96 JMenuBar mb = new JMenuBar();
98 GridBagLayout gbl = new GridBagLayout();
100 GridBagConstraints con = new GridBagConstraints();
102 JLabel statusLine = new JLabel("", SwingConstants.LEFT), statusLabel = new JLabel(Globals
104 + ":", SwingConstants.LEFT);
106 // SearchManager searchManager = new SearchManager(ths, prefs);
108 private FileHistory fileHistory = new FileHistory(prefs, this);
110 LabelMaker labelMaker;
113 public HelpDialog helpDiag = new HelpDialog(this);
115 // Here we instantiate menu/toolbar actions. Actions regarding
116 // the currently open database are defined as a GeneralAction
117 // with a unique command string. This causes the appropriate
118 // BasePanel's runCommand() method to be called with that command.
119 // Note: GeneralAction's constructor automatically gets translations
120 // for the name and message strings.
122 // References to the toggle buttons in the toolbar:
123 public JToggleButton groupToggle, searchToggle, previewToggle, highlightAny,
127 open = new OpenDatabaseAction(this, true);
129 close = new CloseDatabaseAction(),
130 quit = new CloseAction(),
131 selectKeys = new SelectKeysAction(),
132 newDatabaseAction = new NewDatabaseAction(),
133 newSubDatabaseAction = new NewSubDatabaseAction(),
134 integrityCheckAction = new IntegrityCheckAction(),
135 help = new HelpAction("JabRef help", helpDiag,
136 GUIGlobals.baseFrameHelp, "JabRef help",
137 prefs.getKey("Help")),
138 contents = new HelpAction("Help contents", helpDiag,
139 GUIGlobals.helpContents, "Help contents",
140 GUIGlobals.getIconUrl("helpContents")),
141 about = new HelpAction("About JabRef", helpDiag,
142 GUIGlobals.aboutPage, "About JabRef",
143 GUIGlobals.getIconUrl("about")),
144 editEntry = new GeneralAction("edit", "Edit entry",
146 prefs.getKey("Edit entry")),
147 save = new GeneralAction("save", "Save database",
149 prefs.getKey("Save database")),
150 saveAs = new GeneralAction("saveAs", "Save database as ...",
151 "Save database as ...",
152 prefs.getKey("Save database as ...")),
153 saveSelectedAs = new GeneralAction("saveSelectedAs",
154 "Save selected as ...",
155 "Save selected as ...",
156 GUIGlobals.getIconUrl("saveAs")),
157 exportAll = ExportFormats.getExportAction(this, false),
158 exportSelected = ExportFormats.getExportAction(this, true),
159 importCurrent = ImportFormats.getImportAction(this, false),
160 importNew = ImportFormats.getImportAction(this, true),
161 nextTab = new ChangeTabAction(true),
162 prevTab = new ChangeTabAction(false),
163 sortTabs = new SortTabsAction(this),
164 undo = new GeneralAction("undo", "Undo", "Undo",
165 prefs.getKey("Undo")),
166 redo = new GeneralAction("redo", "Redo", "Redo",
167 prefs.getKey("Redo")),
168 /*cut = new GeneralAction("cut", "Cut", "Cut",
169 GUIGlobals.cutIconFile,
170 prefs.getKey("Cut")),*/
171 delete = new GeneralAction("delete", "Delete", "Delete",
172 prefs.getKey("Delete")),
173 /*copy = new GeneralAction("copy", "Copy", "Copy",
174 GUIGlobals.copyIconFile,
175 prefs.getKey("Copy")),*/
176 copy = new EditAction("copy", GUIGlobals.getIconUrl("copy")),
177 paste = new EditAction("paste", GUIGlobals.getIconUrl("paste")),
178 cut = new EditAction("cut", GUIGlobals.getIconUrl("cut")),
179 mark = new GeneralAction("markEntries", "Mark entries",
181 prefs.getKey("Mark entries")),
182 unmark = new GeneralAction("unmarkEntries", "Unmark entries",
184 prefs.getKey("Unmark entries")),
185 unmarkAll = new GeneralAction("unmarkAll", "Unmark all"),
186 manageSelectors = new GeneralAction("manageSelectors", "Manage content selectors"),
187 saveSessionAction = new SaveSessionAction(),
188 loadSessionAction = new LoadSessionAction(),
189 incrementalSearch = new GeneralAction("incSearch", "Incremental search",
190 "Start incremental search",
191 prefs.getKey("Incremental search")),
192 normalSearch = new GeneralAction("search", "Search", "Search",
193 prefs.getKey("Search")),
194 toggleSearch = new GeneralAction("toggleSearch", "Search", "Toggle search panel"),
196 fetchCiteSeer = new FetchCiteSeerAction(),
197 importCiteSeer = new ImportCiteSeerAction(),
198 fetchMedline = new FetchMedlineAction(),
199 citeSeerPanelAction = new CiteSeerPanelAction(),
200 //fetchAuthorMedline = new FetchAuthorMedlineAction(),
201 copyKey = new GeneralAction("copyKey", "Copy BibTeX key"),
202 //"Put a BibTeX reference to the selected entries on the clipboard",
203 copyCiteKey = new GeneralAction("copyCiteKey", "Copy \\cite{BibTeX key}",
204 //"Put a BibTeX reference to the selected entries on the clipboard",
205 prefs.getKey("Copy \\cite{BibTeX key}")),
206 mergeDatabaseAction = new GeneralAction("mergeDatabase",
208 "Append contents from a BibTeX database into the currently viewed database",
209 GUIGlobals.getIconUrl("open")),
210 //prefs.getKey("Open")),
211 /*remove = new GeneralAction("remove", "Remove", "Remove selected entries",
212 GUIGlobals.removeIconFile),*/
213 selectAll = new GeneralAction("selectAll", "Select all",
214 prefs.getKey("Select all")),
215 replaceAll = new GeneralAction("replaceAll", "Replace string",
216 prefs.getKey("Replace string")),
218 editPreamble = new GeneralAction("editPreamble", "Edit preamble",
220 prefs.getKey("Edit preamble")),
221 editStrings = new GeneralAction("editStrings", "Edit strings",
223 prefs.getKey("Edit strings")),
224 toggleGroups = new GeneralAction("toggleGroups",
225 "Toggle groups interface",
226 "Toggle groups interface",
227 prefs.getKey("Toggle groups interface")),
228 togglePreview = new GeneralAction("togglePreview",
229 "Toggle entry preview",
230 "Toggle entry preview",
231 prefs.getKey("Toggle entry preview")),
232 toggleHighlightAny = new GeneralAction("toggleHighlightGroupsMatchingAny",
233 "Highlight groups matching any selected entry",
234 "Highlight groups matching any selected entry",
235 GUIGlobals.getIconUrl("groupsHighlightAny")),
236 toggleHighlightAll = new GeneralAction("toggleHighlightGroupsMatchingAll",
237 "Highlight groups matching all selected entries",
238 "Highlight groups matching all selected entries",
239 GUIGlobals.getIconUrl("groupsHighlightAll")),
240 switchPreview = new GeneralAction("switchPreview",
241 "Switch preview layout",
242 prefs.getKey("Switch preview layout")),
243 makeKeyAction = new GeneralAction("makeKey", "Autogenerate BibTeX keys",
244 "Autogenerate BibTeX keys",
245 prefs.getKey("Autogenerate BibTeX keys")),
247 lyxPushAction = new PushToApplicationAction(ths, new PushToLyx()),
249 winEdtPushAction = new PushToApplicationAction(ths, new PushToWinEdt()),
250 latexEditorPushAction = new PushToApplicationAction(ths, new PushToLatexEditor()),
252 writeXmpAction = new GeneralAction("writeXMP", "Write XMP-metadata to PDFs", "Will write XMP-metadata to the PDFs linked from selected entries.", prefs.getKey("Write XMP")),
254 openFile = new GeneralAction("openFile", "Open PDF or PS",
256 prefs.getKey("Open PDF or PS")),
257 openUrl = new GeneralAction("openUrl", "Open URL or DOI",
259 prefs.getKey("Open URL or DOI")),
260 dupliCheck = new GeneralAction("dupliCheck", "Find duplicates"),
261 strictDupliCheck = new GeneralAction("strictDupliCheck", "Find and remove exact duplicates"),
262 plainTextImport = new GeneralAction("plainTextImport",
263 "New entry from plain text",
264 prefs.getKey("New from plain text")),
267 customExpAction = new CustomizeExportsAction(),
268 customImpAction = new CustomizeImportsAction(),
269 exportCSV = new ExportCSV(),
270 exportToClipboard = new GeneralAction("exportToClipboard", "Export selected entries to clipboard"),
271 expandEndnoteZip = new ExpandEndnoteFilters(this),
272 autoSetPdf = new GeneralAction("autoSetPdf", Globals.lang("Synchronize %0 links", "PDF"), Globals.prefs.getKey("Synchronize PDF")),
273 autoSetPs = new GeneralAction("autoSetPs", Globals.lang("Synchronize %0 links", "PS"), Globals.prefs.getKey("Synchronize PS")),
275 abbreviateMedline = new GeneralAction("abbreviateMedline", "Abbreviate journal names (MEDLINE)",
276 "Abbreviate journal names of the selected entries (MEDLINE abbreviation)"),
277 abbreviateIso = new GeneralAction("abbreviateIso", "Abbreviate journal names (ISO)",
278 "Abbreviate journal names of the selected entries (ISO abbreviation)",
279 Globals.prefs.getKey("Abbreviate")),
282 unabbreviate = new GeneralAction("unabbreviate", "Unabbreviate journal names",
283 "Unabbreviate journal names of the selected entries",
284 Globals.prefs.getKey("Unabbreviate")),
285 manageJournals = new ManageJournalsAction(this),
286 databaseProperties = new DatabasePropertiesAction(),
287 emacsPushAction = new PushToApplicationAction(ths, new PushToEmacs()),
289 errorConsole = Globals.errorConsole.getAction(this),
290 test = new GeneralAction("test", "Test");
292 PushToApplicationButton pushExternalButton;
293 /*setupSelector = new GeneralAction("setupSelector", "", "",
294 GUIGlobals.pasteIconFile,
298 MedlineFetcher medlineFetcher;
299 CiteSeerFetcher citeSeerFetcher;
300 CiteSeerFetcherPanel citeSeerFetcherPanel;
301 IEEEXploreFetcher ieeexplorerFetcher;
303 OAI2Fetcher arxivFetcher;
304 GeneralFetcher arxiv;
305 SearchManager2 searchManager;
306 public GroupSelector groupSelector;
308 // The menus for importing/appending other formats
309 JMenu importMenu = subMenu("Import into current database"),
310 importNewMenu = subMenu("Import into new database"),
311 exportMenu = subMenu("Export"),
312 customExportMenu = subMenu("Custom export"),
313 newDatabaseMenu = subMenu("New database" );
316 JMenu checkAndFix = subMenu("Scan database...");
319 // The action for adding a new entry of unspecified type.
320 NewEntryAction newEntryAction = new NewEntryAction(prefs.getKey("New entry"));
321 NewEntryAction[] newSpecificEntryAction = new NewEntryAction[]
323 new NewEntryAction("article", prefs.getKey("New article")),
324 new NewEntryAction("book", prefs.getKey("New book")),
325 new NewEntryAction("phdthesis", prefs.getKey("New phdthesis")),
326 new NewEntryAction("inbook", prefs.getKey("New inbook")),
327 new NewEntryAction("mastersthesis", prefs.getKey("New mastersthesis")),
328 new NewEntryAction("proceedings", prefs.getKey("New proceedings")),
329 new NewEntryAction("inproceedings"),
330 new NewEntryAction("conference"),
331 new NewEntryAction("incollection"),
332 new NewEntryAction("booklet"),
333 new NewEntryAction("manual"),
334 new NewEntryAction("techreport"),
335 new NewEntryAction("unpublished",
336 prefs.getKey("New unpublished")),
337 new NewEntryAction("misc"),
338 new NewEntryAction("other")
341 public JabRefFrame() {
343 updateEnabledState();
346 private void init() {
348 macOSXRegistration();
349 MyGlassPane glassPane = new MyGlassPane();
350 setGlassPane(glassPane);
351 // glassPane.setVisible(true);
353 setTitle(GUIGlobals.frameTitle);
354 setIconImage(GUIGlobals.getImage("jabrefIcon").getImage());
355 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
356 addWindowListener(new WindowAdapter() {
357 public void windowClosing(WindowEvent e) {
358 (new CloseAction()).actionPerformed(null);
370 if (Globals.prefs.getBoolean("rememberWindowLocation")) {
371 setSize(new Dimension(prefs.getInt("sizeX"), prefs.getInt("sizeY")));
372 setLocation(new Point(prefs.getInt("posX"), prefs.getInt("posY")));
374 tabbedPane.setBorder(null);
375 tabbedPane.setForeground(GUIGlobals.inActiveTabbed);
378 * The following state listener makes sure focus is registered with the
379 * correct database when the user switches tabs. Without this,
380 * cut/paste/copy operations would some times occur in the wrong tab.
382 tabbedPane.addChangeListener(new ChangeListener() {
383 public void stateChanged(ChangeEvent e) {
384 markActiveBasePanel();
386 BasePanel bp = basePanel();
388 groupToggle.setSelected(sidePaneManager.isComponentVisible("groups"));
389 searchToggle.setSelected(sidePaneManager.isComponentVisible("search"));
390 previewToggle.setSelected(Globals.prefs.getBoolean("previewEnabled"));
392 .setSelected(Globals.prefs.getBoolean("highlightGroupsMatchingAny"));
394 .setSelected(Globals.prefs.getBoolean("highlightGroupsMatchingAll"));
395 Globals.focusListener.setFocused(bp.mainTable);
397 new FocusRequester(bp.mainTable);
405 private void initSidePane() {
406 sidePaneManager = new SidePaneManager(this);
408 Globals.sidePaneManager = this.sidePaneManager;
409 Globals.helpDiag = this.helpDiag;
411 ieeexplorerFetcher = new IEEEXploreFetcher();
412 arxivFetcher = new OAI2Fetcher();
413 medlineFetcher = new MedlineFetcher(sidePaneManager);
414 citeSeerFetcher = new CiteSeerFetcher(sidePaneManager);
415 citeSeerFetcherPanel = new CiteSeerFetcherPanel(sidePaneManager,
416 (CiteSeerFetcher) citeSeerFetcher);
417 groupSelector = new GroupSelector(this, sidePaneManager);
418 searchManager = new SearchManager2(this, sidePaneManager);
420 sidePaneManager.register("fetchMedline", medlineFetcher);
421 sidePaneManager.register("CiteSeerProgress", citeSeerFetcher);
422 sidePaneManager.register("CiteSeerPanel", citeSeerFetcherPanel);
423 sidePaneManager.register("groups", groupSelector);
424 sidePaneManager.register("search", searchManager);
426 // Show the search panel if it was visible at last shutdown:
427 if (Globals.prefs.getBoolean("searchPanelVisible"))
428 sidePaneManager.show("search");
432 AboutAction aboutAction = new AboutAction();
434 extends AbstractAction {
435 public AboutAction() {
436 super(Globals.lang("About JabRef"));
440 public void actionPerformed(ActionEvent e) {
446 // General info dialog. The OSXAdapter calls this method when "About OSXAdapter"
447 // is selected from the application menu.
448 public void about() {
449 JDialog about = new JDialog(ths, Globals.lang("About JabRef"),
451 JEditorPane jp = new JEditorPane();
452 JScrollPane sp = new JScrollPane
453 (jp, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
454 JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
455 jp.setEditable(false);
457 jp.setPage(GUIGlobals.class.getResource("/help/About.html"));//GUIGlobals.aboutPage);
458 // We need a hyperlink listener to be able to switch to the license
460 jp.addHyperlinkListener(new javax.swing.event.HyperlinkListener() {
461 public void hyperlinkUpdate(javax.swing.event.HyperlinkEvent e) {
463 == javax.swing.event.HyperlinkEvent.EventType.ACTIVATED) {
465 ( (JEditorPane) e.getSource()).setPage(e.getURL());
467 catch (IOException ex) {}
471 about.getContentPane().add(sp);
472 about.setSize(GUIGlobals.aboutSize);
473 Util.placeDialog(about, ths);
474 about.setVisible(true);
476 catch (IOException ex) {
477 ex.printStackTrace();
478 JOptionPane.showMessageDialog(ths, "Could not load file 'About.html'",
479 "Error", JOptionPane.ERROR_MESSAGE);
484 // General preferences dialog. The OSXAdapter calls this method when "Preferences..."
485 // is selected from the application menu.
486 public void preferences() {
487 //PrefsDialog.showPrefsDialog(ths, prefs);
488 AbstractWorker worker = new AbstractWorker() {
490 output(Globals.lang("Opening preferences..."));
491 if (prefsDialog == null) {
492 prefsDialog = new PrefsDialog3(ths, prefs);
493 Util.placeDialog(prefsDialog, ths);
496 prefsDialog.setValues();
499 public void update() {
500 prefsDialog.setVisible(true);
504 worker.getWorker().run();
505 worker.getCallBack().update();
508 public JabRefPreferences prefs() {
512 // General info dialog. The OSXAdapter calls this method when "Quit OSXAdapter"
513 // is selected from the application menu, Cmd-Q is pressed, or "Quit" is selected from the Dock.
515 // Ask here if the user really wants to close, if the base
516 // has not been saved since last save.
517 boolean close = true;
518 Vector filenames = new Vector();
519 if (tabbedPane.getTabCount() > 0) {
520 loop: for (int i = 0; i < tabbedPane.getTabCount(); i++) {
521 if (baseAt(i).baseChanged) {
522 tabbedPane.setSelectedIndex(i);
523 int answer = JOptionPane.showConfirmDialog
525 ("Database has changed. Do you "
526 + "want to save before closing?"),
527 Globals.lang("Save before closing"),
528 JOptionPane.YES_NO_CANCEL_OPTION);
530 if ( (answer == JOptionPane.CANCEL_OPTION) ||
531 (answer == JOptionPane.CLOSED_OPTION)) {
532 close = false; // The user has cancelled.
535 if (answer == JOptionPane.YES_OPTION) {
536 // The user wants to save.
538 basePanel().runCommand("save");
540 catch (Throwable ex) {
541 // Something prevented the file
542 // from being saved. Break!!!
548 if (baseAt(i).getFile() != null) {
549 filenames.add(baseAt(i).getFile().getPath());
556 prefs.putInt("posX", ths.getLocation().x);
557 prefs.putInt("posY", ths.getLocation().y);
558 prefs.putInt("sizeX", ths.getSize().width);
559 prefs.putInt("sizeY", ths.getSize().height);
560 prefs.putBoolean("searchPanelVisible", sidePaneManager.isComponentVisible("search"));
562 if (prefs.getBoolean("openLastEdited")) {
563 // Here we store the names of allcurrent filea. If
564 // there is no current file, we remove any
565 // previously stored file name.
566 if (filenames.size() == 0) {
567 prefs.remove("lastEdited");
570 String[] names = new String[filenames.size()];
571 for (int i = 0; i < filenames.size(); i++) {
572 names[i] = (String) filenames.elementAt(i);
575 prefs.putStringArray("lastEdited", names);
580 fileHistory.storeHistory();
581 prefs.customExports.store();
582 prefs.customImports.store();
583 BibtexEntryType.saveCustomEntryTypes(prefs);
585 // Let the search interface store changes to prefs.
586 // But which one? Let's use the one that is visible.
587 if (basePanel() != null) {
588 ((SearchManager2)searchManager).updatePrefs();
591 System.exit(0); // End program.
597 private void macOSXRegistration() {
598 if (Globals.osName.equals(Globals.MAC)) {
600 Class osxAdapter = Class.forName("osxadapter.OSXAdapter");
604 Method registerMethod = osxAdapter.getDeclaredMethod(
605 "registerMacOSXApplication", defArgs);
606 if (registerMethod != null) {
609 registerMethod.invoke(osxAdapter, args);
611 // This is slightly gross. to reflectively access methods with boolean args,
612 // use "boolean.class", then pass a Boolean object in as the arg, which apparently
614 defArgs[0] = boolean.class;
615 Method prefsEnableMethod = osxAdapter.getDeclaredMethod("enablePrefs",
617 if (prefsEnableMethod != null) {
620 prefsEnableMethod.invoke(osxAdapter, args);
623 catch (NoClassDefFoundError e) {
624 // This will be thrown first if the OSXAdapter is loaded on a system without the EAWT
625 // because OSXAdapter extends ApplicationAdapter in its def
626 System.err.println("This version of Mac OS X does not support the Apple EAWT. Application Menu handling has been disabled (" +
629 catch (ClassNotFoundException e) {
630 // This shouldn't be reached; if there's a problem with the OSXAdapter we should get the
631 // above NoClassDefFoundError first.
632 System.err.println("This version of Mac OS X does not support the Apple EAWT. Application Menu handling has been disabled (" +
635 catch (Exception e) {
636 System.err.println("Exception while loading the OSXAdapter:");
642 private void initLayout() {
643 tabbedPane.putClientProperty(Options.NO_CONTENT_BORDER_KEY, Boolean.TRUE);
645 pushExternalButton = new PushToApplicationButton(this,
646 PushToApplicationButton.applications);
649 getContentPane().setLayout(gbl);
650 contentPane.setDividerSize(2);
651 contentPane.setBorder(null);
652 //getContentPane().setBackground(GUIGlobals.lightGray);
653 con.fill = GridBagConstraints.HORIZONTAL;
654 con.anchor = GridBagConstraints.WEST;
657 con.gridwidth = GridBagConstraints.REMAINDER;
659 //gbl.setConstraints(mb, con);
660 //getContentPane().add(mb);
662 con.anchor = GridBagConstraints.NORTH;
663 //con.gridwidth = 1;//GridBagConstraints.REMAINDER;;
664 gbl.setConstraints(tlb, con);
665 getContentPane().add(tlb);
667 Component lim = Box.createGlue();
668 gbl.setConstraints(lim, con);
669 //getContentPane().add(lim);
671 JPanel empt = new JPanel();
672 empt.setBackground(GUIGlobals.lightGray);
673 gbl.setConstraints(empt, con);
674 getContentPane().add(empt);
676 con.insets = new Insets(1,0,1,1);
677 con.anchor = GridBagConstraints.EAST;
679 gbl.setConstraints(searchManager, con);
680 getContentPane().add(searchManager);*/
681 con.gridwidth = GridBagConstraints.REMAINDER;
684 con.fill = GridBagConstraints.BOTH;
685 con.anchor = GridBagConstraints.WEST;
686 con.insets = new Insets(0, 0, 0, 0);
687 lim = Box.createGlue();
688 gbl.setConstraints(lim, con);
689 getContentPane().add(lim);
690 //tabbedPane.setVisible(false);
691 //tabbedPane.setForeground(GUIGlobals.lightGray);
693 gbl.setConstraints(contentPane, con);
694 getContentPane().add(contentPane);
695 contentPane.setRightComponent(tabbedPane);
696 contentPane.setLeftComponent(sidePaneManager.getPanel());
697 sidePaneManager.updateView();
699 JPanel status = new JPanel();
700 status.setLayout(gbl);
704 con.insets = new Insets(0, 2, 0, 0);
705 gbl.setConstraints(statusLabel, con);
706 status.add(statusLabel);
708 con.insets = new Insets(0, 4, 0, 0);
709 con.gridwidth = GridBagConstraints.REMAINDER;
710 gbl.setConstraints(statusLine, con);
711 status.add(statusLine);
712 con.gridwidth = GridBagConstraints.REMAINDER;
713 statusLabel.setForeground(GUIGlobals.validFieldColor.darker());
714 con.insets = new Insets(0, 0, 0, 0);
715 gbl.setConstraints(status, con);
716 getContentPane().add(status);
719 // Drag and drop for tabbedPane:
720 TransferHandler xfer = new EntryTableTransferHandler(null, this, null);
721 tabbedPane.setTransferHandler(xfer);
722 tlb.setTransferHandler(xfer);
723 mb.setTransferHandler(xfer);
724 sidePaneManager.getPanel().setTransferHandler(xfer);
727 private void initLabelMaker() {
728 // initialize the labelMaker
729 labelMaker = new LabelMaker();
730 labelMaker.addRule(new ArticleLabelRule(),
731 BibtexEntryType.ARTICLE);
732 labelMaker.addRule(new BookLabelRule(),
733 BibtexEntryType.BOOK);
734 labelMaker.addRule(new IncollectionLabelRule(),
735 BibtexEntryType.INCOLLECTION);
736 labelMaker.addRule(new InproceedingsLabelRule(),
737 BibtexEntryType.INPROCEEDINGS);
741 * Returns the indexed BasePanel.
742 * @param i Index of base
744 BasePanel baseAt(int i) {
745 return (BasePanel) tabbedPane.getComponentAt(i);
748 public void showBaseAt(int i) {
749 tabbedPane.setSelectedIndex(i);
753 * Returns the currently viewed BasePanel.
755 public BasePanel basePanel() {
756 return (BasePanel) tabbedPane.getSelectedComponent();
760 * handle the color of active and inactive JTabbedPane tabs
762 private void markActiveBasePanel()
764 int now = tabbedPane.getSelectedIndex() ;
765 int len = tabbedPane.getTabCount() ;
766 if ((lastTabbedPanelSelectionIndex > -1) && (lastTabbedPanelSelectionIndex < len))
767 tabbedPane.setForegroundAt(lastTabbedPanelSelectionIndex, GUIGlobals.inActiveTabbed);
768 if ( (now > -1) && (now < len))
769 tabbedPane.setForegroundAt(now, GUIGlobals.activeTabbed);
770 lastTabbedPanelSelectionIndex = now ;
773 private int getTabIndex(JComponent comp) {
774 for (int i = 0; i < tabbedPane.getTabCount(); i++) {
775 if (tabbedPane.getComponentAt(i) == comp) {
782 public JTabbedPane getTabbedPane() { return tabbedPane; }
784 public String getTabTitle(JComponent comp) {
785 return tabbedPane.getTitleAt(getTabIndex(comp));
788 public String getTabTooltip(JComponent comp) {
789 return tabbedPane.getToolTipTextAt(getTabIndex(comp));
792 public void setTabTitle(JComponent comp, String title, String toolTip) {
793 int index = getTabIndex(comp);
794 tabbedPane.setTitleAt(index, title);
795 tabbedPane.setToolTipTextAt(index, toolTip);
799 extends MnemonicAwareAction {
800 private String command;
801 public GeneralAction(String command, String text,
802 String description, URL icon) {
803 super(new ImageIcon(icon));
804 this.command = command;
805 putValue(NAME, text);
806 putValue(SHORT_DESCRIPTION, Globals.lang(description));
809 public GeneralAction(String command, String text,
810 String description, String imageName,
812 super(GUIGlobals.getImage(imageName));
813 this.command = command;
814 putValue(NAME, text);
815 putValue(ACCELERATOR_KEY, key);
816 putValue(SHORT_DESCRIPTION, Globals.lang(description));
819 public GeneralAction(String command, String text) {
820 putValue(NAME, text);
821 this.command = command;
824 public GeneralAction(String command, String text, KeyStroke key) {
825 this.command = command;
826 putValue(NAME, text);
827 putValue(ACCELERATOR_KEY, key);
830 public GeneralAction(String command, String text, String description) {
831 this.command = command;
832 ImageIcon icon = GUIGlobals.getImage(command);
834 putValue(SMALL_ICON, icon);
835 putValue(NAME, text);
836 putValue(SHORT_DESCRIPTION, Globals.lang(description));
839 public GeneralAction(String command, String text, String description, KeyStroke key) {
840 this.command = command;
841 ImageIcon icon = GUIGlobals.getImage(command);
843 putValue(SMALL_ICON, icon);
844 putValue(NAME, text);
845 putValue(SHORT_DESCRIPTION, Globals.lang(description));
846 putValue(ACCELERATOR_KEY, key);
849 /* public GeneralAction(String command, String text, String description,
850 URL imageUrl, KeyStroke key) {
851 this.command = command;
852 ImageIcon icon = GUIGlobals.getImage(command);
854 putValue(SMALL_ICON, icon);
855 putValue(NAME, text);
856 putValue(SHORT_DESCRIPTION, Globals.lang(description));
857 putValue(ACCELERATOR_KEY, key);
860 public void actionPerformed(ActionEvent e) {
861 if (tabbedPane.getTabCount() > 0) {
863 ( (BasePanel) (tabbedPane.getSelectedComponent ()))
864 .runCommand(command);
866 catch (Throwable ex) {
867 ex.printStackTrace();
871 Util.pr("Action '" + command + "' must be disabled when no "
872 + "database is open.");
877 /** This got removed when we introduced SearchManager2.
878 class IncrementalSearchAction extends AbstractAction {
879 public IncrementalSearchAction() {
880 super("Incremental search", new ImageIcon(GUIGlobals.searchIconFile));
881 putValue(SHORT_DESCRIPTION, Globals.lang("Start incremental search"));
882 putValue(ACCELERATOR_KEY, prefs.getKey("Incremental search"));
884 public void actionPerformed(ActionEvent e) {
885 if (tabbedPane.getTabCount() > 0)
886 searchManager.startIncrementalSearch();
890 class SearchAction extends AbstractAction {
891 public SearchAction() {
892 super("Search", new ImageIcon(GUIGlobals.searchIconFile));
893 putValue(SHORT_DESCRIPTION, Globals.lang("Start search"));
894 putValue(ACCELERATOR_KEY, prefs.getKey("Search"));
896 public void actionPerformed(ActionEvent e) {
897 if (tabbedPane.getTabCount() > 0)
898 searchManager.startSearch();
904 extends MnemonicAwareAction {
906 String type = null; // The type of item to create.
907 KeyStroke keyStroke = null; // Used for the specific instances.
909 public NewEntryAction(KeyStroke key) {
910 // This action leads to a dialog asking for entry type.
911 super(GUIGlobals.getImage("add"));
912 putValue(NAME, "New entry");
913 putValue(ACCELERATOR_KEY, key);
914 putValue(SHORT_DESCRIPTION, Globals.lang("New BibTeX entry"));
917 public NewEntryAction(String type_) {
918 // This action leads to the creation of a specific entry.
919 putValue(NAME, Util.nCase(type_));
923 public NewEntryAction(String type_, KeyStroke key) {
924 // This action leads to the creation of a specific entry.
925 putValue(NAME, Util.nCase(type_));
926 putValue(ACCELERATOR_KEY, key);
930 public void actionPerformed(ActionEvent e) {
931 String thisType = type;
932 if (thisType == null) {
933 EntryTypeDialog etd = new EntryTypeDialog(ths);
934 Util.placeDialog(etd, ths);
935 etd.setVisible(true);
936 BibtexEntryType tp = etd.getChoice();
940 thisType = tp.getName();
943 if (tabbedPane.getTabCount() > 0) {
944 ( (BasePanel) (tabbedPane.getSelectedComponent()))
945 .newEntry(BibtexEntryType.getType(thisType));
948 Util.pr("Action 'New entry' must be disabled when no "
949 + "database is open.");
955 private void setupDatabaseLayout() {
956 // This method is called whenever this frame has been provided
957 // with a database, and completes the layout.
961 setTitle(GUIGlobals.baseTitle+file.getName());
963 setTitle(GUIGlobals.untitledTitle);
965 //DragNDropManager dndm = new DragNDropManager(this);
967 //setNonEmptyState();
968 Util.pr("JabRefFrame: Must set non-empty state.");
972 * Refresh import menus.
974 public void setUpImportMenus() {
975 setUpImportMenu(importMenu, false);
976 setUpImportMenu(importNewMenu, true);
979 private void fillMenu() {
980 //mb.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
982 JMenu file = subMenu("File"),
983 sessions = subMenu("Sessions"),
984 edit = subMenu("Edit"),
985 bibtex = subMenu("BibTeX"),
986 view = subMenu("View"),
987 tools = subMenu("Tools"),
988 web = subMenu("Web search"),
989 options = subMenu("Options"),
990 newSpec = subMenu("New entry..."),
991 helpMenu = subMenu("Help");
995 newDatabaseMenu.add(newDatabaseAction);
996 newDatabaseMenu.add(newSubDatabaseAction);
998 file.add(newDatabaseAction);
999 file.add(open); //opendatabaseaction
1000 file.add(mergeDatabaseAction);
1003 file.add(saveSelectedAs);
1004 file.addSeparator();
1005 //file.add(importMenu);
1006 //file.add(importNewMenu);
1007 file.add(importNew);
1008 file.add(importCurrent);
1009 file.add(exportAll);
1010 file.add(exportSelected);
1012 file.addSeparator();
1013 file.add(databaseProperties);
1014 file.addSeparator();
1016 sessions.add(loadSessionAction);
1017 sessions.add(saveSessionAction);
1019 file.add(fileHistory);
1020 //file.addSeparator();
1022 file.addSeparator();
1024 //==============================
1025 // NB: I added this because my frame borders are so tiny that I cannot click
1026 // on the "x" close button. Anyways, I think it is good to have an "exit" button
1027 // I was too lazy to make a new ExitAction
1028 //JMenuItem exit_mItem = new JMenuItem(Globals.lang("Exit"));
1029 //exit_mItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, KeyEvent.CTRL_MASK)); //Ctrl-Q to exit
1030 // above keybinding should be from user define
1031 //exit_mItem.addActionListener(new CloseAction() );
1032 //file.add( exit_mItem);
1033 //=====================================
1039 edit.addSeparator();
1047 edit.add(copyCiteKey);
1048 //edit.add(exportToClipboard);
1049 edit.addSeparator();
1052 edit.add(unmarkAll);
1053 edit.addSeparator();
1054 edit.add(selectAll);
1059 view.addSeparator();
1060 view.add(toggleGroups);
1061 view.add(togglePreview);
1062 view.add(switchPreview);
1063 view.addSeparator();
1064 view.add(toggleHighlightAny);
1065 view.add(toggleHighlightAll);
1068 bibtex.add(newEntryAction);
1069 for (int i = 0; i < newSpecificEntryAction.length; i++) {
1070 newSpec.add(newSpecificEntryAction[i]);
1072 bibtex.add(newSpec);
1073 bibtex.add(plainTextImport);
1074 bibtex.addSeparator();
1075 bibtex.add(editEntry);
1076 bibtex.add(importCiteSeer);
1077 bibtex.add(editPreamble);
1078 bibtex.add(editStrings);
1081 tools.add(normalSearch);
1082 tools.add(incrementalSearch);
1083 tools.add(replaceAll);
1084 tools.add(new MassSetFieldAction(this));
1085 tools.add(makeKeyAction);
1087 // [kiar] I think we should group these festures
1088 tools.add(checkAndFix);
1089 checkAndFix.add(dupliCheck);
1090 checkAndFix.add(strictDupliCheck);
1091 checkAndFix.add(autoSetPdf);
1092 checkAndFix.add(autoSetPs);
1093 checkAndFix.add(integrityCheckAction);
1096 tools.addSeparator();
1097 tools.add(manageSelectors);
1099 tools.add(pushExternalButton.getMenuAction());
1100 tools.add(writeXmpAction);
1102 //tools.add(emacsPushAction);
1103 //tools.add(lyxPushAction);
1104 //tools.add(winEdtPushAction);
1105 //tools.add(latexEditorPushAction);
1106 //tools.add(fetchAuthorMedline);
1107 tools.addSeparator();
1108 tools.add(openFile);
1110 tools.addSeparator();
1111 tools.add(newSubDatabaseAction);
1113 tools.addSeparator();
1114 tools.add(abbreviateIso);
1115 tools.add(abbreviateMedline);
1116 tools.add(unabbreviate);
1120 web.add(fetchMedline);
1121 web.add(citeSeerPanelAction);
1122 web.add(fetchCiteSeer);
1123 ieex = new GeneralFetcher(sidePaneManager, this, ieeexplorerFetcher);
1124 arxiv = new GeneralFetcher(sidePaneManager, this, arxivFetcher);
1125 web.add(ieex.getAction());
1126 web.add(arxiv.getAction());
1130 options.add(showPrefs);
1131 AbstractAction customizeAction = new CustomizeEntryTypeAction();
1132 AbstractAction genFieldsCustomization = new GenFieldsCustomizationAction();
1133 options.add(customizeAction);
1134 options.add(genFieldsCustomization);
1135 options.add(customExpAction);
1136 options.add(customImpAction);
1137 options.add(manageJournals);
1139 /*options.add(new AbstractAction("Font") {
1140 public void actionPerformed(ActionEvent e) {
1141 // JDialog dl = new EntryCustomizationDialog(ths);
1142 Font f=new FontSelectorDialog
1143 (ths, GUIGlobals.CURRENTFONT).getSelectedFont();
1147 GUIGlobals.CURRENTFONT=f;
1149 prefs.put("fontFamily", GUIGlobals.CURRENTFONT.getFamily());
1150 prefs.putInt("fontStyle", GUIGlobals.CURRENTFONT.getStyle());
1151 prefs.putInt("fontSize", GUIGlobals.CURRENTFONT.getSize());
1152 if (tabbedPane.getTabCount() > 0) {
1153 for (int i=0; i<tabbedPane.getTabCount(); i++) {
1154 baseAt(i).entryTable.updateFont();
1155 baseAt(i).refreshTable();
1161 //options.add(selectKeys);
1165 helpMenu.add(contents);
1166 helpMenu.addSeparator();
1167 //old about helpMenu.add(about);
1168 helpMenu.add(about);
1170 helpMenu.addSeparator();
1171 helpMenu.add(errorConsole);
1174 private JMenu subMenu(String name) {
1175 name = Globals.menuTitle(name);
1176 int i = name.indexOf('&');
1179 res = new JMenu(name.substring(0, i)+name.substring(i+1));
1180 char mnemonic = Character.toUpperCase(name.charAt(i+1));
1181 res.setMnemonic((int)mnemonic);
1183 else res = new JMenu(name);
1188 private void createToolBar() {
1189 tlb.putClientProperty(Options.HEADER_STYLE_KEY, HeaderStyle.BOTH);
1190 tlb.setBorder(null);
1191 tlb.setRollover(true);
1193 //tlb.setBorderPainted(true);
1194 //tlb.setBackground(GUIGlobals.lightGray);
1195 //tlb.setForeground(GUIGlobals.lightGray);
1196 tlb.setFloatable(false);
1197 tlb.addAction(newDatabaseAction);
1198 tlb.addAction(open);
1199 tlb.addAction(save);
1203 tlb.addAction(copy);
1204 tlb.addAction(paste);
1205 tlb.addAction(undo);
1206 tlb.addAction(redo);
1209 tlb.addAction(newEntryAction);
1210 tlb.addAction(editEntry);
1211 tlb.addAction(editPreamble);
1212 tlb.addAction(editStrings);
1213 tlb.addAction(makeKeyAction);
1217 tlb.addAction(mark);
1218 tlb.addAction(unmark);
1221 searchToggle = new JToggleButton(toggleSearch);
1222 searchToggle.setText(null);
1223 if (!Globals.ON_MAC)
1224 searchToggle.setMargin(marg);
1225 tlb.add(searchToggle);
1227 previewToggle = new JToggleButton(togglePreview);
1228 previewToggle.setText(null);
1229 if (!Globals.ON_MAC)
1230 previewToggle.setMargin(marg);
1231 tlb.add(previewToggle);
1234 groupToggle = new JToggleButton(toggleGroups);
1235 groupToggle.setText(null);
1236 if (!Globals.ON_MAC)
1237 groupToggle.setMargin(marg);
1238 tlb.add(groupToggle);
1241 highlightAny = new JToggleButton(toggleHighlightAny);
1242 highlightAny.setText(null);
1243 if (!Globals.ON_MAC)
1244 highlightAny.setMargin(marg);
1245 tlb.add(highlightAny);
1246 highlightAll = new JToggleButton(toggleHighlightAll);
1247 highlightAll.setText(null);
1248 if (!Globals.ON_MAC)
1249 highlightAll.setMargin(marg);
1250 tlb.add(highlightAll);
1254 // Removing the separate push-to buttons, replacing them by the
1255 // multipurpose button:
1256 //tlb.addAction(emacsPushAction);
1257 //tlb.addAction(lyxPushAction);
1258 //tlb.addAction(winEdtPushAction);
1259 tlb.add(pushExternalButton.getComponent());
1261 tlb.addAction(openFile);
1262 tlb.addAction(openUrl);
1265 //tlb.addSeparator();
1266 //tlb.addAction(showPrefs);
1267 tlb.add(Box.createHorizontalGlue());
1268 //tlb.add(new JabRefLabel(GUIGlobals.frameTitle+" "+GUIGlobals.version));
1270 tlb.addAction(closeDatabaseAction);
1271 //Insets margin = new Insets(0, 0, 0, 0);
1272 //for (int i=0; i<tlb.getComponentCount(); i++)
1273 // ((JButton)tlb.getComponentAtIndex(i)).setMargin(margin);
1277 private class JabRefLabel
1279 private String label;
1280 public JabRefLabel(String name) {
1284 public void paint(Graphics g) {
1285 Graphics2D g2 = (Graphics2D) g;
1286 g2.setColor(GUIGlobals.nullFieldColor);
1287 g2.setFont(GUIGlobals.jabRefFont);
1288 FontMetrics fm = g2.getFontMetrics();
1289 int width = fm.stringWidth(label);
1290 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
1291 RenderingHints.VALUE_ANTIALIAS_ON);
1292 g2.drawString(label, getWidth() - width - 7, getHeight() - 10);
1298 private JMenuItem mItem(AbstractAction a, KeyStroke ks) {
1299 // Set up a menu item with action and accelerator key.
1300 JMenuItem mi = new JMenuItem();
1303 mi.setAccelerator(ks);
1308 //private void setupMainPanel() {
1311 /*public Completer getAutoCompleter(String field) {
1312 return (Completer)autoCompleters.get(field);
1316 public void assignAutoCompleters() {
1317 // Set up which fields should have autocompletion. This should
1318 // probably be made customizable. Existing Completer objects are
1319 // forgotten. The completers must be updated towards the database.
1320 byte[] fields = prefs.getByteArray("autoCompFields");
1321 autoCompleters = new Hashtable();
1322 for (int i=0; i<fields.length; i++) {
1323 autoCompleters.put(GUIGlobals.ALL_FIELDS[fields[i]], new Completer());
1328 public void updateAutoCompleters() {
1329 if (database != null)
1330 database.setCompleters(autoCompleters);
1333 public void output(final String s) {
1335 SwingUtilities.invokeLater(new Runnable() {
1337 statusLine.setText(s);
1338 statusLine.repaint();
1343 public void stopShowingSearchResults() {
1344 for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1345 baseAt(i).stopShowingSearchResults();
1349 protected List openDatabaseOnlyActions = new LinkedList();
1350 protected List severalDatabasesOnlyActions = new LinkedList();
1352 protected void initActions() {
1353 openDatabaseOnlyActions = new LinkedList();
1354 openDatabaseOnlyActions.addAll(Arrays.asList(new Object[] { manageSelectors,
1355 mergeDatabaseAction, newSubDatabaseAction, close, save, saveAs, saveSelectedAs, undo,
1356 redo, cut, delete, copy, paste, mark, unmark, unmarkAll, editEntry, importCiteSeer,
1357 selectAll, copyKey, copyCiteKey, editPreamble, editStrings, toggleGroups, toggleSearch,
1358 makeKeyAction, emacsPushAction, lyxPushAction, winEdtPushAction, normalSearch,
1359 incrementalSearch, replaceAll, importMenu, exportMenu, fetchMedline, fetchCiteSeer,
1360 openFile, openUrl, togglePreview, dupliCheck, strictDupliCheck, highlightAll,
1361 highlightAny, citeSeerPanelAction, newEntryAction, plainTextImport,
1362 closeDatabaseAction, switchPreview, integrityCheckAction, autoSetPdf, autoSetPs,
1363 toggleHighlightAny, toggleHighlightAll, databaseProperties, abbreviateIso,
1364 abbreviateMedline, unabbreviate, ieex.getAction(), arxiv.getAction(), exportAll, exportSelected,
1367 openDatabaseOnlyActions.addAll(Arrays.asList(newSpecificEntryAction));
1369 severalDatabasesOnlyActions = new LinkedList();
1370 severalDatabasesOnlyActions.addAll(Arrays
1371 .asList(new Object[] { nextTab, prevTab, sortTabs }));
1373 tabbedPane.addChangeListener(new ChangeListener() {
1374 public void stateChanged(ChangeEvent event) {
1375 updateEnabledState();
1383 public static void setEnabled(List l, boolean enabled) {
1384 Iterator i = l.iterator();
1385 while (i.hasNext()) {
1386 Object o = i.next();
1387 if (o instanceof Action)
1388 ((Action)o).setEnabled(enabled);
1389 if (o instanceof Component)
1390 ((Component)o).setEnabled(enabled);
1394 protected int previousTabCount = -1;
1397 * Enable or Disable all actions based on the number of open tabs.
1399 * The action that are affected are set in initActions.
1401 protected void updateEnabledState() {
1402 int tabCount = tabbedPane.getTabCount();
1403 if (tabCount != previousTabCount){
1404 previousTabCount = tabCount;
1405 setEnabled(openDatabaseOnlyActions, tabCount > 0);
1406 setEnabled(severalDatabasesOnlyActions, tabCount > 1);
1411 * This method causes all open BasePanels to set up their tables
1412 * anew. When called from PrefsDialog2, this updates to the new
1415 public void setupAllTables() {
1416 // This action can be invoked without an open database, so
1417 // we have to check if we have one before trying to invoke
1418 // methods to execute changes in the preferences.
1420 // We want to notify all tabs about the changes to
1421 // avoid problems when changing the column set.
1422 for (int i = 0; i < tabbedPane.getTabCount(); i++) {
1423 BasePanel bf = baseAt(i);
1426 if (bf.database != null) {
1427 bf.setupMainPanel();
1434 public BasePanel addTab(BibtexDatabase db, File file, HashMap meta, String encoding, boolean raisePanel) {
1435 BasePanel bp = new BasePanel(ths, db, file, meta, encoding);
1436 addTab(bp, file, raisePanel);
1440 public void addTab(BasePanel bp, File file, boolean raisePanel) {
1441 tabbedPane.add((file != null ? file.getName(): Globals.lang(GUIGlobals.untitledTitle)),
1443 tabbedPane.setToolTipTextAt(tabbedPane.getTabCount()-1,
1444 file != null ? file.getAbsolutePath() : null);
1446 tabbedPane.setSelectedComponent(bp);
1450 class SelectKeysAction
1451 extends AbstractAction {
1452 public SelectKeysAction() {
1453 super(Globals.lang("Customize key bindings"));
1456 public void actionPerformed(ActionEvent e) {
1457 KeyBindingsDialog d = new KeyBindingsDialog
1458 ( (HashMap) prefs.getKeyBindings().clone(),
1459 prefs.getDefaultKeys());
1460 d.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
1461 d.pack(); //setSize(300,500);
1462 Util.placeDialog(d, ths);
1464 if (d.getAction()) {
1465 prefs.setNewKeyBindings(d.getNewKeyBindings());
1466 JOptionPane.showMessageDialog
1468 Globals.lang("Your new key bindings have been stored.") + "\n"
1469 + Globals.lang("You must restart JabRef for the new key "
1470 + "bindings to work properly."),
1471 Globals.lang("Key bindings changed"),
1472 JOptionPane.INFORMATION_MESSAGE);
1478 * The action concerned with closing the window.
1481 extends MnemonicAwareAction {
1482 public CloseAction() {
1483 putValue(NAME, "Quit");
1484 putValue(SHORT_DESCRIPTION, Globals.lang("Quit JabRef"));
1485 putValue(ACCELERATOR_KEY, prefs.getKey("Quit JabRef"));
1486 //putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_Q,
1487 // Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
1491 public void actionPerformed(ActionEvent e) {
1496 // The action for closing the current database and leaving the window open.
1497 CloseDatabaseAction closeDatabaseAction = new CloseDatabaseAction();
1499 class CloseDatabaseAction extends MnemonicAwareAction {
1500 public CloseDatabaseAction() {
1501 super(GUIGlobals.getImage("close"));
1502 putValue(NAME, "Close database");
1503 putValue(SHORT_DESCRIPTION, Globals.lang("Close the current database"));
1504 putValue(ACCELERATOR_KEY, prefs.getKey("Close database"));
1507 public void actionPerformed(ActionEvent e) {
1508 // Ask here if the user really wants to close, if the base
1509 // has not been saved since last save.
1510 boolean close = true;
1511 if (basePanel() == null) { // when it is initially empty
1512 return; // nbatada nov 7
1515 if (basePanel().baseChanged) {
1516 int answer = JOptionPane.showConfirmDialog(ths, Globals
1517 .lang("Database has changed. Do you want to save " + "before closing?"),
1518 Globals.lang("Save before closing"), JOptionPane.YES_NO_CANCEL_OPTION);
1519 if ((answer == JOptionPane.CANCEL_OPTION) || (answer == JOptionPane.CLOSED_OPTION)) {
1520 close = false; // The user has cancelled.
1522 if (answer == JOptionPane.YES_OPTION) {
1523 // The user wants to save.
1525 basePanel().runCommand("save");
1526 } catch (Throwable ex) {
1527 // Something prevented the file
1528 // from being saved. Break!!!
1536 basePanel().cleanUp();
1537 tabbedPane.remove(basePanel());
1538 if (tabbedPane.getTabCount() > 0) {
1539 markActiveBasePanel();
1541 updateEnabledState(); // Man, this is what I call a bug that this is not called.
1542 output(Globals.lang("Closed database") + ".");
1543 System.gc(); // Test
1549 // The action concerned with opening a new database.
1550 class NewDatabaseAction
1551 extends MnemonicAwareAction {
1552 public NewDatabaseAction() {
1553 super(GUIGlobals.getImage("new"));
1554 putValue(NAME, "New database");
1555 putValue(SHORT_DESCRIPTION, Globals.lang("New BibTeX database"));
1556 //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1559 public void actionPerformed(ActionEvent e) {
1560 // Create a new, empty, database.
1561 BibtexDatabase database = new BibtexDatabase();
1562 addTab(database, null, null, Globals.prefs.get("defaultEncoding"), true);
1563 output(Globals.lang("New database created."));
1567 class ImportCiteSeerAction
1568 extends MnemonicAwareAction {
1570 public ImportCiteSeerAction() {
1571 super(GUIGlobals.getImage("citeseer"));
1572 putValue(NAME, "Import Fields from CiteSeer");
1573 putValue(SHORT_DESCRIPTION, Globals.lang("Import Fields from CiteSeer Database"));
1574 putValue(ACCELERATOR_KEY, prefs.getKey("Import Fields from CiteSeer")); // Key defined in MenuTitles!
1577 public void actionPerformed(ActionEvent e) {
1579 if(citeSeerFetcher.activateImportFetcher()) {
1584 BasePanel currentBp;
1587 int[] clickedOn = null;
1589 class UpdateComponent implements Runnable {
1590 boolean changesMade;
1592 UpdateComponent(boolean changesMade) {
1593 this.changesMade = changesMade;
1597 citeSeerFetcher.endImportCiteSeerProgress();
1599 currentBp.markBaseChanged();
1600 //for(int i=0; i < clickedOn.length; i++)
1601 // currentBp.entryTable.addRowSelectionInterval(i,i);
1602 //currentBp.showEntry(toShow);
1603 output(Globals.lang("Completed Import Fields from CiteSeer."));
1608 currentBp = (BasePanel) tabbedPane.getSelectedComponent();
1609 // We demand that at least one row is selected.
1611 int rowCount = currentBp.mainTable.getSelectedRowCount();
1612 if (rowCount >= 1) {
1613 clickedOn = currentBp.mainTable.getSelectedRows();
1615 JOptionPane.showMessageDialog(currentBp.frame(),
1616 Globals.lang("You must select at least one row to perform this operation."),
1617 Globals.lang("CiteSeer Import Error"),
1618 JOptionPane.WARNING_MESSAGE);
1620 toShow = (BibtexEntry)currentBp.mainTable.getSelected().get(0);
1621 if (clickedOn != null) {
1622 citeSeerFetcher.beginImportCiteSeerProgress();
1623 NamedCompound citeseerNamedCompound =
1624 new NamedCompound(Globals.lang("CiteSeer Import Fields"));
1625 boolean newValues = citeSeerFetcher.importCiteSeerEntries(clickedOn, citeseerNamedCompound);
1627 citeseerNamedCompound.end();
1628 currentBp.undoManager.addEdit(citeseerNamedCompound);
1630 UpdateComponent updateComponent = new UpdateComponent(newValues);
1631 SwingUtilities.invokeLater(updateComponent);
1633 citeSeerFetcher.deactivateImportFetcher();
1637 JOptionPane.showMessageDialog(tabbedPane.getSelectedComponent(),
1638 Globals.lang("A CiteSeer import operation is currently in progress.") + " " +
1639 Globals.lang("Please wait until it has finished."),
1640 Globals.lang("CiteSeer Import Error"),
1641 JOptionPane.WARNING_MESSAGE);
1646 class FetchCiteSeerAction
1647 extends MnemonicAwareAction {
1649 public FetchCiteSeerAction() {
1650 super(GUIGlobals.getImage("citeseer"));
1651 putValue(NAME, "Fetch citations from CiteSeer");
1653 putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Articles Citing your Database"));
1654 putValue(ACCELERATOR_KEY, prefs.getKey("Fetch citations from CiteSeer"));
1657 public void actionPerformed(ActionEvent e) {
1659 if(citeSeerFetcher.activateCitationFetcher()) {
1660 sidePaneManager.show("CiteSeerProgress");
1664 BibtexDatabase newDatabase;
1665 BibtexDatabase targetDatabase;
1667 Runnable updateComponent = new Runnable() {
1669 /* TODO: This should probably be selectable on/off
1670 * in the preferences window, but for now all
1671 * Citation fetcher operations will sort by citation count.
1673 private void setSortingByCitationCount() {
1674 newBp.sortingByCiteSeerResults = true;
1678 setSortingByCitationCount();
1679 tabbedPane.add(Globals.lang(GUIGlobals.untitledTitle), newBp);
1680 tabbedPane.setSelectedComponent(newBp);
1681 output(Globals.lang("Fetched all citations from target database."));
1682 citeSeerFetcher.deactivateCitationFetcher();
1688 newBp = new BasePanel(ths);
1690 targetBp = (BasePanel) tabbedPane.getSelectedComponent();
1691 newDatabase = newBp.getDatabase();
1692 targetDatabase = targetBp.getDatabase();
1693 errorCode = citeSeerFetcher.populate(newDatabase, targetDatabase);
1694 if (newDatabase.getEntryCount() > 0) {
1695 SwingUtilities.invokeLater(updateComponent);
1696 } else if(errorCode == 0) {
1697 SwingUtilities.invokeLater(citeSeerFetcher.getEmptyFetchSetDialog());
1699 citeSeerFetcher.deactivateCitationFetcher();
1702 catch (Exception ex) {
1703 ex.printStackTrace();
1708 JOptionPane.showMessageDialog(tabbedPane.getSelectedComponent(),
1709 Globals.lang("A CiteSeer fetch operation is currently in progress.") + " " +
1710 Globals.lang("Please wait until it has finished."),
1711 Globals.lang("CiteSeer Fetch Error"),
1712 JOptionPane.WARNING_MESSAGE);
1719 // The action concerned with generate a new (sub-)database from latex aux file.
1720 class NewSubDatabaseAction extends MnemonicAwareAction
1722 public NewSubDatabaseAction()
1724 super(GUIGlobals.getImage("new"));
1725 putValue(NAME, "New subdatabase based on AUX file" );
1726 putValue( SHORT_DESCRIPTION, Globals.lang( "New BibTeX subdatabase" ) ) ;
1727 //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1730 public void actionPerformed( ActionEvent e )
1732 // Create a new, empty, database.
1734 FromAuxDialog dialog = new FromAuxDialog(ths, "", true, ths.tabbedPane) ;
1736 Util.placeDialog(dialog, ths);
1737 dialog.setVisible(true) ;
1739 if (dialog.okPressed())
1741 BasePanel bp = new BasePanel( ths,
1742 dialog.getGenerateDB(), // database
1744 null, Globals.prefs.get("defaultEncoding")); // meta data
1745 tabbedPane.add( Globals.lang( GUIGlobals.untitledTitle ), bp ) ;
1746 tabbedPane.setSelectedComponent( bp ) ;
1747 output( Globals.lang( "New database created." ) ) ;
1753 // The action should test the database and report errors/warnings
1754 class IntegrityCheckAction extends AbstractAction
1756 public IntegrityCheckAction()
1758 super(Globals.menuTitle("Integrity check"),
1759 GUIGlobals.getImage("integrityCheck")) ;
1760 //putValue( SHORT_DESCRIPTION, "integrity" ) ; //Globals.lang( "integrity" ) ) ;
1761 //putValue(MNEMONIC_KEY, GUIGlobals.newKeyCode);
1764 public void actionPerformed( ActionEvent e )
1766 Object selComp = tabbedPane.getSelectedComponent() ;
1767 if (selComp != null)
1769 BasePanel bp = ( BasePanel ) selComp ;
1770 BibtexDatabase refBase = bp.getDatabase() ;
1771 if (refBase != null)
1773 IntegrityWizard wizard = new IntegrityWizard(ths, basePanel()) ;
1774 Util.placeDialog(wizard, ths);
1775 wizard.setVisible(true) ;
1782 class FetchMedlineAction extends MnemonicAwareAction {
1783 public FetchMedlineAction() {
1784 super(GUIGlobals.getImage("medline"));
1785 putValue(NAME, "Fetch Medline");
1786 putValue(ACCELERATOR_KEY, prefs.getKey("Fetch Medline"));
1787 putValue(SHORT_DESCRIPTION, Globals.lang("Fetch Medline by ID"));
1790 public void actionPerformed(ActionEvent e) {
1791 if (tabbedPane.getTabCount() > 0) {
1792 sidePaneManager.toggle("fetchMedline");
1793 if (sidePaneManager.isComponentVisible("fetchMedline")) {
1794 new FocusRequester(medlineFetcher.getTextField());
1800 class CiteSeerPanelAction extends MnemonicAwareAction {
1801 public CiteSeerPanelAction() {
1802 super(GUIGlobals.getImage("medline"));
1803 putValue(NAME, "Fetch CiteSeer");
1804 putValue(ACCELERATOR_KEY, prefs.getKey("Fetch CiteSeer"));
1805 putValue(SHORT_DESCRIPTION, Globals.lang("Fetch CiteSeer by ID"));
1808 public void actionPerformed(ActionEvent e) {
1809 if (tabbedPane.getTabCount() > 0) {
1810 sidePaneManager.toggle("CiteSeerPanel");
1811 if (sidePaneManager.isComponentVisible("CiteSeerPanel")) {
1812 new FocusRequester(citeSeerFetcherPanel.getTextField());
1818 // The action for opening the preferences dialog.
1819 AbstractAction showPrefs = new ShowPrefsAction();
1821 class ShowPrefsAction
1822 extends MnemonicAwareAction {
1823 public ShowPrefsAction() {
1824 super(GUIGlobals.getImage("preferences"));
1825 putValue(NAME, "Preferences");
1826 putValue(SHORT_DESCRIPTION, Globals.lang("Preferences"));
1829 public void actionPerformed(ActionEvent e) {
1835 * This method does the job of adding imported entries into the active database, or into a new one.
1836 * It shows the ImportInspectionDialog if preferences indicate it should be used. Otherwise it imports
1838 * @param panel The BasePanel to add to.
1839 * @param entries The entries to add.
1840 * @param filename Name of the file where the import came from.
1841 * @param openInNew Should the entries be imported into a new database?
1842 * @param callBack The callback for the ImportInspectionDialog to use.
1844 public void addImportedEntries(final BasePanel panel, final List entries, String filename, boolean openInNew,
1845 ImportInspectionDialog.CallBack callBack) {
1846 // Use the import inspection dialog if it is enabled in preferences, and (there are more than
1847 // one entry or the inspection dialog is also enabled for single entries):
1848 if (Globals.prefs.getBoolean("useImportInspectionDialog") &&
1849 (Globals.prefs.getBoolean("useImportInspectionDialogForSingle") || (entries.size() > 1))) {
1850 ImportInspectionDialog diag = new ImportInspectionDialog(ths, panel,
1851 BibtexFields.DEFAULT_INSPECTION_FIELDS,
1852 Globals.lang("Import"), openInNew);
1853 diag.addEntries(entries);
1854 diag.addCallBack(callBack);
1855 diag.entryListComplete();
1856 Util.placeDialog(diag, ths);
1857 diag.setVisible(true);
1860 ths.addBibEntries(entries, filename, openInNew);
1861 if ((panel != null) && (entries.size() == 1)) {
1862 SwingUtilities.invokeLater(new Runnable() {
1864 panel.highlightEntry((BibtexEntry)entries.get(0));
1874 * Adds the entries to the database, possibly checking for duplicates first.
1875 * @param filename If non-null, a message is printed to the status line describing
1876 * how many entries were imported, and from which file. If null, the message will not
1878 * @param intoNew Determines if the entries will be put in a new database or in the current
1881 public int addBibEntries(java.util.List bibentries, String filename,
1883 if (bibentries == null || bibentries.size() == 0) {
1885 // No entries found. We need a message for this.
1886 JOptionPane.showMessageDialog(ths, Globals.lang("No entries found. Please make sure you are "
1887 +"using the correct import filter."), Globals.lang("Import failed"),
1888 JOptionPane.ERROR_MESSAGE);
1892 int addedEntries = 0;
1894 // Set owner and timestamp fields:
1895 Util.setAutomaticFields(bibentries);
1897 if (intoNew || (tabbedPane.getTabCount() == 0)) {
1898 // Import into new database.
1899 BibtexDatabase database = new BibtexDatabase();
1900 Iterator it = bibentries.iterator();
1901 while (it.hasNext()) {
1902 BibtexEntry entry = (BibtexEntry) it.next();
1905 entry.setId(Util.createNeutralId());
1906 database.insertEntry(entry);
1908 catch (KeyCollisionException ex) {
1910 System.err.println("KeyCollisionException [ addBibEntries(...) ]");
1913 HashMap meta = new HashMap();
1914 // Metadata are only put in bibtex files, so we will not find it
1915 // in imported files. Instead we pass an empty HashMap.
1916 BasePanel bp = new BasePanel(ths, database, null, meta, Globals.prefs.get("defaultEncoding"));
1918 if (prefs.getBoolean("autoComplete")) {
1919 db.setCompleters(autoCompleters);
1922 addedEntries = database.getEntryCount();
1923 tabbedPane.add(GUIGlobals.untitledTitle, bp);
1924 bp.markBaseChanged();
1925 tabbedPane.setSelectedComponent(bp);
1926 if (filename != null)
1927 output(Globals.lang("Imported database") + " '" + filename + "' " +
1928 Globals.lang("with") + " " +
1929 database.getEntryCount() + " " +
1930 Globals.lang("entries into new database") + ".");
1933 // Import into current database.
1934 boolean checkForDuplicates = true;
1935 BasePanel basePanel = basePanel();
1936 BibtexDatabase database = basePanel.database;
1937 int oldCount = database.getEntryCount();
1938 NamedCompound ce = new NamedCompound(Globals.lang("Import entries"));
1939 Iterator it = bibentries.iterator();
1941 mainLoop: while (it.hasNext()) {
1942 BibtexEntry entry = (BibtexEntry) it.next();
1943 boolean dupli = false;
1944 // Check for duplicates among the current entries:
1945 if (checkForDuplicates) {
1946 loop: for (Iterator i2=database.getKeySet().iterator();
1948 BibtexEntry existingEntry = database.getEntryById((String)i2.next());
1949 if (Util.isDuplicate(entry, existingEntry,
1950 Globals.duplicateThreshold)) {
1951 DuplicateResolverDialog drd = new DuplicateResolverDialog
1952 (ths, existingEntry, entry, DuplicateResolverDialog.IMPORT_CHECK);
1953 drd.setVisible(true);
1954 int res = drd.getSelected();
1955 if (res == DuplicateResolverDialog.KEEP_LOWER) {
1958 else if (res == DuplicateResolverDialog.KEEP_UPPER) {
1959 database.removeEntry(existingEntry.getId());
1960 ce.addEdit(new UndoableRemoveEntry
1961 (database, existingEntry, basePanel));
1962 } else if (res == DuplicateResolverDialog.BREAK) {
1972 entry.setId(Util.createNeutralId());
1973 database.insertEntry(entry);
1974 ce.addEdit(new UndoableInsertEntry
1975 (database, entry, basePanel));
1978 catch (KeyCollisionException ex) {
1980 System.err.println("KeyCollisionException [ addBibEntries(...) ]");
1984 if (addedEntries > 0) {
1986 basePanel.undoManager.addEdit(ce);
1987 basePanel.markBaseChanged();
1988 if (filename != null)
1989 output(Globals.lang("Imported database") + " '" + filename + "' " +
1990 Globals.lang("with") + " " +
1991 (database.getEntryCount() - oldCount) + " " +
1992 Globals.lang("entries into new database") + ".");
1997 return addedEntries;
2000 private void setUpImportMenu(JMenu importMenu, boolean intoNew_) {
2001 final boolean intoNew = intoNew_;
2002 importMenu.removeAll();
2004 // Add a menu item for autodetecting import format:
2005 importMenu.add(new ImportMenuItem(ths, intoNew));
2007 // Add custom importers
2008 importMenu.addSeparator();
2010 SortedSet customImporters = Globals.importFormatReader.getCustomImportFormats();
2011 JMenu submenu = new JMenu(Globals.lang("Custom importers"));
2012 submenu.setMnemonic(KeyEvent.VK_S);
2013 /*if (customImporters.size() == 0) {
2014 submenu.setEnabled(false);
2015 submenu.setToolTipText(Globals.lang("No custom imports registered yet."));
2017 // Put in all formatters registered in ImportFormatReader:
2018 for (Iterator i=customImporters.iterator(); i.hasNext();) {
2019 ImportFormat imFo = (ImportFormat)i.next();
2020 submenu.add(new ImportMenuItem(ths, intoNew, imFo));
2023 if (customImporters.size() > 0)
2024 submenu.addSeparator();
2025 submenu.add(customImpAction);
2027 importMenu.add(submenu);
2028 importMenu.addSeparator();
2030 // Put in all formatters registered in ImportFormatReader:
2031 for (Iterator i=Globals.importFormatReader.getBuiltInInputFormats().iterator(); i.hasNext();) {
2032 ImportFormat imFo = (ImportFormat)i.next();
2033 importMenu.add(new ImportMenuItem(ths, intoNew, imFo));
2038 public FileHistory getFileHistory() {
2044 * Set the preview active state for all BasePanel instances.
2047 public void setPreviewActive(boolean enabled) {
2048 for (int i=0; i<tabbedPane.getTabCount(); i++) {
2049 baseAt(i).setPreviewActive(enabled);
2054 public void removeCachedEntryEditors() {
2055 for (int j=0; j<tabbedPane.getTabCount(); j++) {
2056 BasePanel bp = (BasePanel)tabbedPane.getComponentAt(j);
2057 bp.entryEditors.clear();
2062 * This method shows a wait cursor and blocks all input to the JFrame's contents.
2064 public void block() {
2065 getGlassPane().setVisible(true);
2066 //getGlassPane().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2070 * This method reverts the cursor to normal, and stops blocking input to the JFrame's contents.
2072 public void unblock() {
2073 getGlassPane().setVisible(false);
2074 // getGlassPane().setCursor(Cursor.WAIT_CURSOR);
2079 class SaveSessionAction
2080 extends MnemonicAwareAction {
2081 public SaveSessionAction() {
2082 super(GUIGlobals.getImage("save"));
2083 putValue(NAME, "Save session");
2084 putValue(ACCELERATOR_KEY, prefs.getKey("Save session"));
2087 public void actionPerformed(ActionEvent e) {
2088 // Here we store the names of allcurrent filea. If
2089 // there is no current file, we remove any
2090 // previously stored file name.
2091 Vector filenames = new Vector();
2092 if (tabbedPane.getTabCount() > 0) {
2093 for (int i = 0; i < tabbedPane.getTabCount(); i++) {
2094 if (tabbedPane.getTitleAt(i).equals(GUIGlobals.untitledTitle)) {
2095 tabbedPane.setSelectedIndex(i);
2096 int answer = JOptionPane.showConfirmDialog
2098 ("This untitled database must be saved first to be "
2099 + "included in the saved session. Save now?"),
2100 Globals.lang("Save database"),
2101 JOptionPane.YES_NO_OPTION);
2102 if (answer == JOptionPane.YES_OPTION) {
2103 // The user wants to save.
2105 basePanel().runCommand("save");
2107 catch (Throwable ex) {}
2110 if (baseAt(i).getFile() != null) {
2111 filenames.add(baseAt(i).getFile().getPath());
2116 if (filenames.size() == 0) {
2117 output(Globals.lang("Not saved (empty session)") + ".");
2121 String[] names = new String[filenames.size()];
2122 for (int i = 0; i < filenames.size(); i++) {
2123 names[i] = (String) filenames.elementAt(i);
2125 prefs.putStringArray("savedSession", names);
2126 output(Globals.lang("Saved session") + ".");
2132 class LoadSessionAction
2133 extends MnemonicAwareAction {
2134 boolean running = false;
2135 public LoadSessionAction() {
2136 super(GUIGlobals.getImage("loadSession"));
2137 putValue(NAME, "Load session");
2138 putValue(ACCELERATOR_KEY, prefs.getKey("Load session"));
2141 public void actionPerformed(ActionEvent e) {
2142 if (prefs.get("savedSession") == null) {
2143 output(Globals.lang("No saved session found."));
2148 else running = true;
2149 output(Globals.lang("Loading session..."));
2152 HashSet currentFiles = new HashSet();
2153 if (tabbedPane.getTabCount() > 0) {
2154 for (int i = 0; i < tabbedPane.getTabCount(); i++) {
2155 if (baseAt(i).getFile() != null)
2156 currentFiles.add(baseAt(i).getFile().getPath());
2159 int i0 = tabbedPane.getTabCount();
2160 String[] names = prefs.getStringArray("savedSession");
2161 for (int i = 0; i < names.length; i++) {
2162 if (!currentFiles.contains(names[i])) {
2163 File file = new File(names[i]);
2164 if (file.exists()) {
2165 //Util.pr("Opening last edited file:"
2166 //+fileToOpen.getName());
2167 open.openIt(file, i == 0);
2171 output(Globals.lang("Files opened") + ": " +
2172 (tabbedPane.getTabCount() - i0));
2180 class ChangeTabAction
2181 extends MnemonicAwareAction {
2182 private boolean next;
2183 public ChangeTabAction(boolean next) {
2184 putValue(NAME, next ? "Next tab" : "Previous tab");
2186 //Util.pr(""+prefs.getKey("Next tab"));
2187 putValue(ACCELERATOR_KEY,
2188 (next ? prefs.getKey("Next tab") : prefs.getKey("Previous tab")));
2191 public void actionPerformed(ActionEvent e) {
2192 int i = tabbedPane.getSelectedIndex();
2193 int newI = (next ? i + 1 : i - 1);
2195 newI = tabbedPane.getTabCount() - 1;
2197 if (newI == tabbedPane.getTabCount()) {
2200 tabbedPane.setSelectedIndex(newI);
2205 * Class for handling general actions; cut, copy and paste. The focused component is
2206 * kept track of by Globals.focusListener, and we call the action stored under the
2207 * relevant name in its action map.
2210 extends MnemonicAwareAction {
2211 private String command;
2212 public EditAction(String command, URL icon) {
2213 super(new ImageIcon(icon));
2214 this.command = command;
2215 String nName = Util.nCase(command);
2216 putValue(NAME, nName);
2217 putValue(ACCELERATOR_KEY, prefs.getKey(nName));
2218 putValue(SHORT_DESCRIPTION, Globals.lang(nName));
2219 //putValue(ACCELERATOR_KEY,
2220 // (next?prefs.getKey("Next tab"):prefs.getKey("Previous tab")));
2223 public void actionPerformed(ActionEvent e) {
2225 //Util.pr(Globals.focusListener.getFocused().toString());
2226 JComponent source = Globals.focusListener.getFocused();
2228 source.getActionMap().get(command).actionPerformed
2229 (new ActionEvent(source, 0, command));
2230 } catch (NullPointerException ex) {
2231 // No component is focused, so we do nothing.
2236 class CustomizeExportsAction extends MnemonicAwareAction {
2237 public CustomizeExportsAction() {
2238 putValue(NAME, "Manage custom exports");
2241 public void actionPerformed(ActionEvent e) {
2242 ExportCustomizationDialog ecd = new ExportCustomizationDialog(ths);
2243 ecd.setVisible(true);
2247 class CustomizeImportsAction extends MnemonicAwareAction {
2248 public CustomizeImportsAction() {
2249 putValue(NAME, "Manage custom imports");
2252 public void actionPerformed(ActionEvent e) {
2253 ImportCustomizationDialog ecd = new ImportCustomizationDialog(ths);
2254 ecd.setVisible(true);
2258 class ExportCSV extends MnemonicAwareAction {
2259 public ExportCSV() {
2260 putValue(NAME, "Tab-separated file");
2262 public void actionPerformed(ActionEvent e) {
2263 String chosenFile = Globals.getNewFile(ths, new File(prefs.get("workingDirectory")), ".csv",
2264 JFileChooser.SAVE_DIALOG, true);
2265 if (chosenFile == null)
2268 FileActions.exportToCSV(basePanel().database(), new File(chosenFile),
2270 } catch (Exception ex) {
2271 ex.printStackTrace();
2277 class CustomizeEntryTypeAction extends MnemonicAwareAction {
2278 public CustomizeEntryTypeAction() {
2279 putValue(NAME, "Customize entry types");
2281 public void actionPerformed(ActionEvent e) {
2282 JDialog dl = new EntryCustomizationDialog2(ths);
2283 Util.placeDialog(dl, ths);
2284 dl.setVisible(true);
2288 class GenFieldsCustomizationAction extends MnemonicAwareAction {
2289 public GenFieldsCustomizationAction() {
2290 putValue(NAME, "Set up general fields");
2292 public void actionPerformed(ActionEvent e) {
2293 GenFieldsCustomizer gf = new GenFieldsCustomizer(ths);
2294 Util.placeDialog(gf, ths);
2295 gf.setVisible(true);
2300 class DatabasePropertiesAction extends MnemonicAwareAction {
2301 DatabasePropertiesDialog propertiesDialog = null;
2302 public DatabasePropertiesAction() {
2303 putValue(NAME, "Database properties");
2306 public void actionPerformed(ActionEvent e) {
2307 if (propertiesDialog == null)
2308 propertiesDialog = new DatabasePropertiesDialog(JabRefFrame.this);
2309 propertiesDialog.setPanel(basePanel());
2310 Util.placeDialog(propertiesDialog, JabRefFrame.this);
2311 propertiesDialog.setVisible(true);
2315 /*private class ForegroundLabel extends JLabel {
2316 public ForegroundLabel(String s) {
2318 setFont(new Font("plain", Font.BOLD, 70));
2319 setHorizontalAlignment(JLabel.CENTER);
2322 public void paint(Graphics g) {
2323 Graphics2D g2 = (Graphics2D)g;
2324 g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
2325 super.paint(g2); //To change body of overridden methods use File | Settings | File Templates.
2329 private class MyGlassPane extends JPanel {
2330 //ForegroundLabel infoLabel = new ForegroundLabel("Showing search");
2331 public MyGlassPane() {
2332 addKeyListener(new KeyAdapter() { });
2333 addMouseListener(new MouseAdapter() { });
2334 /* infoLabel.setForeground(new Color(255, 100, 100, 124));
2336 setLayout(new BorderLayout());
2337 add(infoLabel, BorderLayout.CENTER);*/
2339 Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
2341 // Override isOpaque() to prevent the glasspane from hiding the window contents:
2342 public boolean isOpaque() { return false; }