summaryrefslogtreecommitdiffstats
path: root/src/mainwindow.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mainwindow.cpp')
-rw-r--r--src/mainwindow.cpp2391
1 files changed, 2391 insertions, 0 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
new file mode 100644
index 0000000..bb5db7a
--- /dev/null
+++ b/src/mainwindow.cpp
@@ -0,0 +1,2391 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "mainwindow.h"
+#include "tellico_kernel.h"
+#include "document.h"
+#include "detailedlistview.h"
+#include "entryeditdialog.h"
+#include "groupview.h"
+#include "viewstack.h"
+#include "collection.h"
+#include "entry.h"
+#include "configdialog.h"
+#include "entryitem.h"
+#include "filter.h"
+#include "filterdialog.h"
+#include "collectionfieldsdialog.h"
+#include "controller.h"
+#include "importdialog.h"
+#include "exportdialog.h"
+#include "filehandler.h" // needed so static mainWindow variable can be set
+#include "gui/stringmapdialog.h"
+#include "translators/htmlexporter.h" // for printing
+#include "entryview.h"
+#include "entryiconview.h"
+#include "imagefactory.h" // needed so tmp files can get cleaned
+#include "collections/bibtexcollection.h" // needed for bibtex string macro dialog
+#include "translators/bibtexhandler.h" // needed for bibtex options
+#include "fetchdialog.h"
+#include "reportdialog.h"
+#include "tellico_strings.h"
+#include "filterview.h"
+#include "loanview.h"
+#include "gui/tabcontrol.h"
+#include "gui/lineedit.h"
+#include "tellico_utils.h"
+#include "tellico_debug.h"
+#include "entryiconfactory.h"
+#include "statusbar.h"
+#include "fetch/fetchmanager.h"
+#include "cite/actionmanager.h"
+#include "core/tellico_config.h"
+#include "core/drophandler.h"
+#include "latin1literal.h"
+
+#include <kapplication.h>
+#include <kcombobox.h>
+#include <kiconloader.h>
+#include <kfiledialog.h>
+#include <kmenubar.h>
+#include <ktoolbar.h>
+#include <klocale.h>
+#include <kconfig.h>
+#include <kstdaction.h>
+#include <kwin.h>
+#include <kprogress.h>
+#include <kprinter.h>
+#include <khtmlview.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kmessagebox.h>
+#include <ktip.h>
+#include <krecentdocument.h>
+#include <kedittoolbar.h>
+#include <kkeydialog.h>
+#include <kio/netaccess.h>
+#include <dcopclient.h>
+#include <kaction.h>
+
+#include <qsplitter.h>
+//#include <qpainter.h>
+#include <qsignalmapper.h>
+#include <qtimer.h>
+#include <qmetaobject.h> // needed for copy, cut, paste slots
+#include <qwhatsthis.h>
+#include <qvbox.h>
+
+// the null string and bool are dummy arguments
+#define MIME_ICON(s) \
+ KMimeType::mimeType(QString::fromLatin1(s))->icon(QString::null, false)
+
+namespace {
+ static const int MAIN_WINDOW_MIN_WIDTH = 600;
+ //static const int PRINTED_PAGE_OVERLAP = 0;
+ static const int MAX_IMAGES_WARN_PERFORMANCE = 200;
+}
+
+using Tellico::MainWindow;
+
+MainWindow::MainWindow(QWidget* parent_/*=0*/, const char* name_/*=0*/) : KMainWindow(parent_, name_),
+ ApplicationInterface(),
+ m_updateAll(0),
+ m_statusBar(0),
+ m_editDialog(0),
+ m_groupView(0),
+ m_filterView(0),
+ m_loanView(0),
+ m_configDlg(0),
+ m_filterDlg(0),
+ m_collFieldsDlg(0),
+ m_stringMacroDlg(0),
+ m_fetchDlg(0),
+ m_reportDlg(0),
+ m_queuedFilters(0),
+ m_initialized(false),
+ m_newDocument(true) {
+
+ if(!kapp->dcopClient()->isRegistered()) {
+ kapp->dcopClient()->registerAs("tellico");
+ kapp->dcopClient()->setDefaultObject(objId());
+ }
+
+ m_fetchActions.setAutoDelete(true); // these are the fetcher actions
+
+ Controller::init(this); // the only time this is ever called!
+ // has to be after controller init
+ Kernel::init(this); // the only time this is ever called!
+
+ setIcon(DesktopIcon(QString::fromLatin1("tellico")));
+
+ // initialize the status bar and progress bar
+ initStatusBar();
+
+ // create a document, which also creates an empty book collection
+ // must be done before the different widgets are created
+ initDocument();
+
+ // set up all the actions, some connect to the document, so this must be after initDocument()
+ initActions();
+
+ // create the different widgets in the view, some widgets connect to actions, so must be after initActions()
+ initView();
+
+ // The edit dialog is not created until after the main window is initialized, so it can be a child.
+ // So don't make any connections, don't read options for it until initFileOpen
+ readOptions();
+
+ setAcceptDrops(true);
+ DropHandler* drophandler = new DropHandler(this);
+ installEventFilter(drophandler);
+
+ MARK_LINE;
+ QTimer::singleShot(0, this, SLOT(slotInit()));
+}
+
+void MainWindow::slotInit() {
+ MARK;
+ if(m_editDialog) {
+ return;
+ }
+ m_editDialog = new EntryEditDialog(this, "editdialog");
+ Controller::self()->addObserver(m_editDialog);
+
+ m_toggleEntryEditor->setChecked(Config::showEditWidget());
+ slotToggleEntryEditor();
+
+ initConnections();
+ ImageFactory::init();
+
+ // disable OOO menu item if library is not available
+ action("cite_openoffice")->setEnabled(Cite::ActionManager::isEnabled(Cite::CiteOpenOffice));
+}
+
+void MainWindow::initStatusBar() {
+ MARK;
+ m_statusBar = new Tellico::StatusBar(this);
+}
+
+void MainWindow::initActions() {
+ MARK;
+ /*************************************************
+ * File->New menu
+ *************************************************/
+ QSignalMapper* collectionMapper = new QSignalMapper(this);
+ connect(collectionMapper, SIGNAL(mapped(int)),
+ this, SLOT(slotFileNew(int)));
+
+ KActionMenu* fileNewMenu = new KActionMenu(actionCollection(), "file_new_collection");
+ fileNewMenu->setText(i18n("New"));
+// fileNewMenu->setIconSet(BarIconSet(QString::fromLatin1("filenew"))); // doesn't work
+ fileNewMenu->setIconSet(BarIcon(QString::fromLatin1("filenew")));
+ fileNewMenu->setToolTip(i18n("Create a new collection"));
+ fileNewMenu->setDelayed(false);
+
+ KAction* action = new KAction(actionCollection(), "new_book_collection");
+ action->setText(i18n("New &Book Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("book")));
+ action->setToolTip(i18n("Create a new book collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Book);
+
+ action = new KAction(actionCollection(), "new_bibtex_collection");
+ action->setText(i18n("New B&ibliography"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("bibtex")));
+ action->setToolTip(i18n("Create a new bibtex bibliography"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Bibtex);
+
+ action = new KAction(actionCollection(), "new_comic_book_collection");
+ action->setText(i18n("New &Comic Book Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("comic")));
+ action->setToolTip(i18n("Create a new comic book collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::ComicBook);
+
+ action = new KAction(actionCollection(), "new_video_collection");
+ action->setText(i18n("New &Video Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("video")));
+ action->setToolTip(i18n("Create a new video collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Video);
+
+ action = new KAction(actionCollection(), "new_music_collection");
+ action->setText(i18n("New &Music Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("album")));
+ action->setToolTip(i18n("Create a new music collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Album);
+
+ action = new KAction(actionCollection(), "new_coin_collection");
+ action->setText(i18n("New C&oin Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("coin")));
+ action->setToolTip(i18n("Create a new coin collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Coin);
+
+ action = new KAction(actionCollection(), "new_stamp_collection");
+ action->setText(i18n("New &Stamp Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("stamp")));
+ action->setToolTip(i18n("Create a new stamp collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Stamp);
+
+ action = new KAction(actionCollection(), "new_card_collection");
+ action->setText(i18n("New C&ard Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("card")));
+ action->setToolTip(i18n("Create a new trading card collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Card);
+
+ action = new KAction(actionCollection(), "new_wine_collection");
+ action->setText(i18n("New &Wine Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("wine")));
+ action->setToolTip(i18n("Create a new wine collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Wine);
+
+ action = new KAction(actionCollection(), "new_game_collection");
+ action->setText(i18n("New &Game Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("game")));
+ action->setToolTip(i18n("Create a new game collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+
+ collectionMapper->setMapping(action, Data::Collection::Game);
+ action = new KAction(actionCollection(), "new_boardgame_collection");
+ action->setText(i18n("New Boa&rd Game Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("boardgame")));
+ action->setToolTip(i18n("Create a new board game collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::BoardGame);
+
+ action = new KAction(actionCollection(), "new_file_catalog");
+ action->setText(i18n("New &File Catalog"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("file")));
+ action->setToolTip(i18n("Create a new file catalog"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::File);
+
+ action = new KAction(actionCollection(), "new_custom_collection");
+ action->setText(i18n("New C&ustom Collection"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("filenew")));
+ action->setToolTip(i18n("Create a new custom collection"));
+ fileNewMenu->insert(action);
+ connect(action, SIGNAL(activated()), collectionMapper, SLOT(map()));
+ collectionMapper->setMapping(action, Data::Collection::Base);
+
+ /*************************************************
+ * File menu
+ *************************************************/
+ action = KStdAction::open(this, SLOT(slotFileOpen()), actionCollection());
+ action->setToolTip(i18n("Open an existing document"));
+ m_fileOpenRecent = KStdAction::openRecent(this, SLOT(slotFileOpenRecent(const KURL&)), actionCollection());
+ m_fileOpenRecent->setToolTip(i18n("Open a recently used file"));
+ m_fileSave = KStdAction::save(this, SLOT(slotFileSave()), actionCollection());
+ m_fileSave->setToolTip(i18n("Save the document"));
+ action = KStdAction::saveAs(this, SLOT(slotFileSaveAs()), actionCollection());
+ action->setToolTip(i18n("Save the document as a different file..."));
+ action = KStdAction::print(this, SLOT(slotFilePrint()), actionCollection());
+ action->setToolTip(i18n("Print the contents of the document..."));
+ action = KStdAction::quit(this, SLOT(slotFileQuit()), actionCollection());
+ action->setToolTip(i18n("Quit the application"));
+
+/**************** Import Menu ***************************/
+
+ QSignalMapper* importMapper = new QSignalMapper(this);
+ connect(importMapper, SIGNAL(mapped(int)),
+ this, SLOT(slotFileImport(int)));
+
+ KActionMenu* importMenu = new KActionMenu(actionCollection(), "file_import");
+ importMenu->setText(i18n("&Import"));
+ importMenu->setIconSet(BarIconSet(QString::fromLatin1("fileimport")));
+ importMenu->setToolTip(i18n("Import collection data from other formats"));
+ importMenu->setDelayed(false);
+
+ action = new KAction(actionCollection(), "file_import_tellico");
+ action->setText(i18n("Import Tellico Data..."));
+ action->setToolTip(i18n("Import another Tellico data file"));
+ action->setIcon(QString::fromLatin1("tellico"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::TellicoXML);
+
+ action = new KAction(actionCollection(), "file_import_csv");
+ action->setText(i18n("Import CSV Data..."));
+ action->setToolTip(i18n("Import a CSV file"));
+ action->setIcon(MIME_ICON("text/x-csv"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::CSV);
+
+ action = new KAction(actionCollection(), "file_import_mods");
+ action->setText(i18n("Import MODS Data..."));
+ action->setToolTip(i18n("Import a MODS data file"));
+ action->setIcon(MIME_ICON("text/xml"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::MODS);
+
+ action = new KAction(actionCollection(), "file_import_alexandria");
+ action->setText(i18n("Import Alexandria Data..."));
+ action->setToolTip(i18n("Import data from the Alexandria book collection manager"));
+ action->setIcon(QString::fromLatin1("alexandria"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::Alexandria);
+
+ action = new KAction(actionCollection(), "file_import_delicious");
+ action->setText(i18n("Import Delicious Library Data..."));
+ action->setToolTip(i18n("Import data from Delicious Library"));
+ action->setIcon(MIME_ICON("text/xml"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::Delicious);
+
+ action = new KAction(actionCollection(), "file_import_referencer");
+ action->setText(i18n("Import Referencer Data..."));
+ action->setToolTip(i18n("Import data from Referencer"));
+ action->setIcon(QString::fromLatin1("referencer"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::Referencer);
+
+ action = new KAction(actionCollection(), "file_import_bibtex");
+ action->setText(i18n("Import Bibtex Data..."));
+ action->setToolTip(i18n("Import a bibtex bibliography file"));
+ action->setIcon(MIME_ICON("text/x-bibtex"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::Bibtex);
+
+ action = new KAction(actionCollection(), "file_import_bibtexml");
+ action->setText(i18n("Import Bibtexml Data..."));
+ action->setToolTip(i18n("Import a Bibtexml bibliography file"));
+ action->setIcon(MIME_ICON("text/xml"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::Bibtexml);
+
+ action = new KAction(actionCollection(), "file_import_ris");
+ action->setText(i18n("Import RIS Data..."));
+ action->setToolTip(i18n("Import an RIS reference file"));
+ action->setIcon(MIME_ICON("application/x-research-info-systems"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::RIS);
+
+ action = new KAction(actionCollection(), "file_import_pdf");
+ action->setText(i18n("Import PDF File..."));
+ action->setToolTip(i18n("Import a PDF file"));
+ action->setIcon(MIME_ICON("application/pdf"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::PDF);
+
+ action = new KAction(actionCollection(), "file_import_audiofile");
+ action->setText(i18n("Import Audio File Metadata..."));
+ action->setToolTip(i18n("Import meta-data from audio files"));
+ action->setIcon(MIME_ICON("audio/x-mp3"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::AudioFile);
+#ifndef HAVE_TAGLIB
+ action->setEnabled(false);
+#endif
+
+ action = new KAction(actionCollection(), "file_import_freedb");
+ action->setText(i18n("Import Audio CD Data..."));
+ action->setToolTip(i18n("Import audio CD information"));
+ action->setIcon(MIME_ICON("media/audiocd"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::FreeDB);
+#ifndef HAVE_KCDDB
+ action->setEnabled(false);
+#endif
+
+ action = new KAction(actionCollection(), "file_import_gcfilms");
+ action->setText(i18n("Import GCstar Data..."));
+ action->setToolTip(i18n("Import a GCstar data file"));
+ action->setIcon(QString::fromLatin1("gcstar"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::GCfilms);
+
+ action = new KAction(actionCollection(), "file_import_griffith");
+ action->setText(i18n("Import Griffith Data..."));
+ action->setToolTip(i18n("Import a Griffith database"));
+ action->setIcon(QString::fromLatin1("griffith"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::Griffith);
+
+ action = new KAction(actionCollection(), "file_import_amc");
+ action->setText(i18n("Import Ant Movie Catalog Data..."));
+ action->setToolTip(i18n("Import an Ant Movie Catalog data file"));
+ action->setIcon(MIME_ICON("application/x-crossover-amc"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::AMC);
+
+ action = new KAction(actionCollection(), "file_import_filelisting");
+ action->setText(i18n("Import File Listing..."));
+ action->setToolTip(i18n("Import information about files in a folder"));
+ action->setIcon(MIME_ICON("inode/directory"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::FileListing);
+
+ action = new KAction(actionCollection(), "file_import_xslt");
+ action->setText(i18n("Import XSL Transform..."));
+ action->setToolTip(i18n("Import using an XSL Transform"));
+ action->setIcon(MIME_ICON("text/x-xslt"));
+ importMenu->insert(action);
+ connect(action, SIGNAL(activated()), importMapper, SLOT(map()));
+ importMapper->setMapping(action, Import::XSLT);
+
+/**************** Export Menu ***************************/
+
+ QSignalMapper* exportMapper = new QSignalMapper(this);
+ connect(exportMapper, SIGNAL(mapped(int)),
+ this, SLOT(slotFileExport(int)));
+
+ KActionMenu* exportMenu = new KActionMenu(actionCollection(), "file_export");
+ exportMenu->setText(i18n("&Export"));
+ exportMenu->setIconSet(BarIconSet(QString::fromLatin1("fileexport")));
+ exportMenu->setToolTip(i18n("Export the collection data to other formats"));
+ exportMenu->setDelayed(false);
+
+ action = new KAction(actionCollection(), "file_export_xml");
+ action->setText(i18n("Export to XML..."));
+ action->setToolTip(i18n("Export to a Tellico XML file"));
+ action->setIcon(QString::fromLatin1("tellico"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::TellicoXML);
+
+ action = new KAction(actionCollection(), "file_export_zip");
+ action->setText(i18n("Export to Zip..."));
+ action->setToolTip(i18n("Export to a Tellico Zip file"));
+ action->setIcon(QString::fromLatin1("tellico"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::TellicoZip);
+
+ action = new KAction(actionCollection(), "file_export_html");
+ action->setText(i18n("Export to HTML..."));
+ action->setToolTip(i18n("Export to an HTML file"));
+ action->setIcon(MIME_ICON("text/html"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::HTML);
+
+ action = new KAction(actionCollection(), "file_export_csv");
+ action->setText(i18n("Export to CSV..."));
+ action->setToolTip(i18n("Export to a comma-separated values file"));
+ action->setIcon(MIME_ICON("text/x-csv"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::CSV);
+
+ action = new KAction(actionCollection(), "file_export_pilotdb");
+ action->setText(i18n("Export to PilotDB..."));
+ action->setToolTip(i18n("Export to a PilotDB database"));
+ action->setIcon(MIME_ICON("application/vnd.palm"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::PilotDB);
+
+ action = new KAction(actionCollection(), "file_export_alexandria");
+ action->setText(i18n("Export to Alexandria..."));
+ action->setToolTip(i18n("Export to an Alexandria library"));
+ action->setIcon(QString::fromLatin1("alexandria"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::Alexandria);
+
+ action = new KAction(actionCollection(), "file_export_bibtex");
+ action->setText(i18n("Export to Bibtex..."));
+ action->setToolTip(i18n("Export to a bibtex file"));
+ action->setIcon(MIME_ICON("text/x-bibtex"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::Bibtex);
+
+ action = new KAction(actionCollection(), "file_export_bibtexml");
+ action->setText(i18n("Export to Bibtexml..."));
+ action->setToolTip(i18n("Export to a Bibtexml file"));
+ action->setIcon(MIME_ICON("text/xml"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::Bibtexml);
+
+ action = new KAction(actionCollection(), "file_export_onix");
+ action->setText(i18n("Export to ONIX..."));
+ action->setToolTip(i18n("Export to an ONIX file"));
+ action->setIcon(MIME_ICON("text/xml"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::ONIX);
+
+ action = new KAction(actionCollection(), "file_export_gcfilms");
+ action->setText(i18n("Export to GCfilms..."));
+ action->setToolTip(i18n("Export to a GCfilms data file"));
+ action->setIcon(QString::fromLatin1("gcstar"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::GCfilms);
+
+#if 0
+ QString dummy1 = i18n("Export to GCstar...");
+ QString dummy2 = i18n("Export to a GCstar data file");
+#endif
+
+ action = new KAction(actionCollection(), "file_export_xslt");
+ action->setText(i18n("Export XSL Transform..."));
+ action->setToolTip(i18n("Export using an XSL Transform"));
+ action->setIcon(MIME_ICON("text/x-xslt"));
+ exportMenu->insert(action);
+ connect(action, SIGNAL(activated()), exportMapper, SLOT(map()));
+ exportMapper->setMapping(action, Export::XSLT);
+
+ /*************************************************
+ * Edit menu
+ *************************************************/
+ action = KStdAction::cut(this, SLOT(slotEditCut()), actionCollection());
+ action->setToolTip(i18n("Cut the selected text and puts it in the clipboard"));
+ action = KStdAction::copy(this, SLOT(slotEditCopy()), actionCollection());
+ action->setToolTip(i18n("Copy the selected text to the clipboard"));
+ action = KStdAction::paste(this, SLOT(slotEditPaste()), actionCollection());
+ action->setToolTip(i18n("Paste the clipboard contents"));
+ action = KStdAction::selectAll(this, SLOT(slotEditSelectAll()), actionCollection());
+ action->setToolTip(i18n("Select all the entries in the collection"));
+ action = KStdAction::deselect(this, SLOT(slotEditDeselect()), actionCollection());
+ action->setToolTip(i18n("Deselect all the entries in the collection"));
+
+ action = new KAction(i18n("Internet Search..."), QString::fromLatin1("wizard"), CTRL + Key_M,
+ this, SLOT(slotShowFetchDialog()),
+ actionCollection(), "edit_search_internet");
+ action->setToolTip(i18n("Search the internet..."));
+
+ action = new KAction(i18n("Advanced &Filter..."), QString::fromLatin1("filter"), CTRL + Key_J,
+ this, SLOT(slotShowFilterDialog()),
+ actionCollection(), "filter_dialog");
+ action->setToolTip(i18n("Filter the collection"));
+
+ /*************************************************
+ * Collection menu
+ *************************************************/
+ m_newEntry = new KAction(i18n("&New Entry..."), QString::fromLatin1("filenew"), CTRL + Key_N,
+ this, SLOT(slotNewEntry()),
+ actionCollection(), "coll_new_entry");
+ m_newEntry->setToolTip(i18n("Create a new entry"));
+ m_editEntry = new KAction(i18n("&Edit Entry..."), QString::fromLatin1("edit"), CTRL + Key_E,
+ this, SLOT(slotShowEntryEditor()),
+ actionCollection(), "coll_edit_entry");
+ m_editEntry->setToolTip(i18n("Edit the selected entries"));
+ m_copyEntry = new KAction(i18n("D&uplicate Entry"), QString::fromLatin1("editcopy"), CTRL + Key_Y,
+ Controller::self(), SLOT(slotCopySelectedEntries()),
+ actionCollection(), "coll_copy_entry");
+ m_copyEntry->setToolTip(i18n("Copy the selected entries"));
+ m_deleteEntry = new KAction(i18n("&Delete Entry"), QString::fromLatin1("editdelete"), CTRL + Key_D,
+ Controller::self(), SLOT(slotDeleteSelectedEntries()),
+ actionCollection(), "coll_delete_entry");
+ m_deleteEntry->setToolTip(i18n("Delete the selected entries"));
+ m_mergeEntry = new KAction(i18n("&Merge Entries"), QString::fromLatin1("editcopy"), CTRL + Key_G,
+ Controller::self(), SLOT(slotMergeSelectedEntries()),
+ actionCollection(), "coll_merge_entry");
+ m_mergeEntry->setToolTip(i18n("Merge the selected entries"));
+ m_mergeEntry->setEnabled(false); // gets enabled when more than 1 entry is selected
+
+ action = new KAction(i18n("&Generate Reports..."), QString::fromLatin1("document"), 0, this,
+ SLOT(slotShowReportDialog()),
+ actionCollection(), "coll_reports");
+ action->setToolTip(i18n("Generate collection reports"));
+ m_checkOutEntry = new KAction(i18n("Check-&out..."), QString::fromLatin1("2uparrow"), 0,
+ Controller::self(), SLOT(slotCheckOut()),
+ actionCollection(), "coll_checkout");
+ m_checkOutEntry->setToolTip(i18n("Check-out the selected items"));
+ m_checkInEntry = new KAction(i18n("Check-&in"), QString::fromLatin1("2downarrow"), 0,
+ Controller::self(), SLOT(slotCheckIn()),
+ actionCollection(), "coll_checkin");
+ m_checkInEntry->setToolTip(i18n("Check-in the selected items"));
+
+ action = new KAction(i18n("&Rename Collection..."), QString::fromLatin1("editclear"), CTRL + Key_R,
+ this, SLOT(slotRenameCollection()),
+ actionCollection(), "coll_rename_collection");
+ action->setToolTip(i18n("Rename the collection"));
+ action = new KAction(i18n("Collection &Fields..."), QString::fromLatin1("edit"), CTRL + Key_U,
+ this, SLOT(slotShowCollectionFieldsDialog()),
+ actionCollection(), "coll_fields");
+ action->setToolTip(i18n("Modify the collection fields"));
+ action = new KAction(i18n("Convert to &Bibliography"), 0,
+ this, SLOT(slotConvertToBibliography()),
+ actionCollection(), "coll_convert_bibliography");
+ action->setToolTip(i18n("Convert a book collection to a bibliography"));
+ action->setIconSet(UserIconSet(QString::fromLatin1("bibtex")));
+ action = new KAction(i18n("String &Macros..."), QString::fromLatin1("view_text"), 0,
+ this, SLOT(slotShowStringMacroDialog()),
+ actionCollection(), "coll_string_macros");
+ action->setToolTip(i18n("Edit the bibtex string macros"));
+
+ QSignalMapper* citeMapper = new QSignalMapper(this);
+ connect(citeMapper, SIGNAL(mapped(int)),
+ this, SLOT(slotCiteEntry(int)));
+
+ action = new KAction(actionCollection(), "cite_clipboard");
+ action->setText(i18n("Copy Bibtex to Cli&pboard"));
+ action->setToolTip(i18n("Copy bibtex citations to the clipboard"));
+ action->setIcon(QString::fromLatin1("editpaste"));
+ connect(action, SIGNAL(activated()), citeMapper, SLOT(map()));
+ citeMapper->setMapping(action, Cite::CiteClipboard);
+
+ action = new KAction(actionCollection(), "cite_lyxpipe");
+ action->setText(i18n("Cite Entry in &LyX"));
+ action->setToolTip(i18n("Cite the selected entries in LyX"));
+ action->setIcon(QString::fromLatin1("lyx"));
+ connect(action, SIGNAL(activated()), citeMapper, SLOT(map()));
+ citeMapper->setMapping(action, Cite::CiteLyxpipe);
+
+ action = new KAction(actionCollection(), "cite_openoffice");
+ action->setText(i18n("Ci&te Entry in OpenOffice.org"));
+ action->setToolTip(i18n("Cite the selected entries in OpenOffice.org"));
+ action->setIcon(QString::fromLatin1("ooo-writer"));
+ connect(action, SIGNAL(activated()), citeMapper, SLOT(map()));
+ citeMapper->setMapping(action, Cite::CiteOpenOffice);
+
+ QSignalMapper* updateMapper = new QSignalMapper(this, "update_mapper");
+ connect(updateMapper, SIGNAL(mapped(const QString&)),
+ Controller::self(), SLOT(slotUpdateSelectedEntries(const QString&)));
+
+ m_updateEntryMenu = new KActionMenu(i18n("&Update Entry"), actionCollection(), "coll_update_entry");
+// m_updateEntryMenu->setIconSet(BarIconSet(QString::fromLatin1("fileexport")));
+ m_updateEntryMenu->setDelayed(false);
+
+ m_updateAll = new KAction(actionCollection(), "update_entry_all");
+ m_updateAll->setText(i18n("All Sources"));
+ m_updateAll->setToolTip(i18n("Update entry data from all available sources"));
+// m_updateEntryMenu->insert(action);
+ connect(m_updateAll, SIGNAL(activated()), updateMapper, SLOT(map()));
+ updateMapper->setMapping(m_updateAll, QString::fromLatin1("_all"));
+
+ /*************************************************
+ * Settings menu
+ *************************************************/
+ setStandardToolBarMenuEnabled(true);
+ createStandardStatusBarAction();
+ KStdAction::configureToolbars(this, SLOT(slotConfigToolbar()), actionCollection());
+ KStdAction::keyBindings(this, SLOT(slotConfigKeys()), actionCollection());
+ m_toggleGroupWidget = new KToggleAction(i18n("Show Grou&p View"), 0,
+ this, SLOT(slotToggleGroupWidget()),
+ actionCollection(), "toggle_group_widget");
+ m_toggleGroupWidget->setToolTip(i18n("Enable/disable the group view"));
+ m_toggleGroupWidget->setCheckedState(i18n("Hide Grou&p View"));
+
+ m_toggleEntryEditor = new KToggleAction(i18n("Show Entry &Editor"), 0,
+ this, SLOT(slotToggleEntryEditor()),
+ actionCollection(), "toggle_edit_widget");
+ m_toggleEntryEditor->setToolTip(i18n("Enable/disable the editor"));
+ m_toggleEntryEditor->setCheckedState(i18n("Hide Entry &Editor"));
+
+ m_toggleEntryView = new KToggleAction(i18n("Show Entry &View"), 0,
+ this, SLOT(slotToggleEntryView()),
+ actionCollection(), "toggle_entry_view");
+ m_toggleEntryView->setToolTip(i18n("Enable/disable the entry view"));
+ m_toggleEntryView->setCheckedState(i18n("Hide Entry &View"));
+
+ KStdAction::preferences(this, SLOT(slotShowConfigDialog()), actionCollection());
+
+ /*************************************************
+ * Help menu
+ *************************************************/
+ KStdAction::tipOfDay(this, SLOT(slotShowTipOfDay()), actionCollection(), "tipOfDay");
+
+ /*************************************************
+ * Collection Toolbar
+ *************************************************/
+ (void) new KAction(i18n("Change Grouping"), CTRL + Key_G,
+ this, SLOT(slotGroupLabelActivated()),
+ actionCollection(), "change_entry_grouping_accel");
+
+ m_entryGrouping = new KSelectAction(i18n("&Group Selection"), 0, this,
+ SLOT(slotChangeGrouping()),
+ actionCollection(), "change_entry_grouping");
+ m_entryGrouping->setToolTip(i18n("Change the grouping of the collection"));
+
+ (void) new KAction(i18n("Filter"), CTRL + Key_F,
+ this, SLOT(slotFilterLabelActivated()),
+ actionCollection(), "quick_filter_accel");
+ (void) new KAction(i18n("Clear Filter"), QString::fromLatin1("locationbar_erase"), 0,
+ this, SLOT(slotClearFilter()),
+ actionCollection(), "quick_filter_clear");
+
+ m_quickFilter = new GUI::LineEdit();
+ m_quickFilter->setHint(i18n("Filter here...")); // same text as kdepim and amarok
+ // about 10 characters wide
+ m_quickFilter->setFixedWidth(m_quickFilter->fontMetrics().maxWidth()*10);
+ // want to update every time the filter text changes
+ connect(m_quickFilter, SIGNAL(textChanged(const QString&)),
+ this, SLOT(slotQueueFilter()));
+
+ KWidgetAction* wAction = new KWidgetAction(m_quickFilter, i18n("Filter"), 0, 0, 0,
+ actionCollection(), "quick_filter");
+ wAction->setToolTip(i18n("Filter the collection"));
+ wAction->setShortcutConfigurable(false);
+ wAction->setAutoSized(true);
+
+ // show tool tips in status bar
+ actionCollection()->setHighlightingEnabled(true);
+ connect(actionCollection(), SIGNAL(actionStatusText(const QString &)),
+ SLOT(slotStatusMsg(const QString &)));
+ connect(actionCollection(), SIGNAL(clearStatusText()),
+ SLOT(slotClearStatus()));
+
+#ifdef UIFILE
+ kdWarning() << "MainWindow::initActions() - change createGUI() call!" << endl;
+ createGUI(UIFILE, false);
+#else
+ createGUI(QString::null, false);
+#endif
+}
+
+void MainWindow::initDocument() {
+ MARK;
+ Data::Document* doc = Data::Document::self();
+
+ KConfigGroup config(KGlobal::config(), "General Options");
+ doc->setLoadAllImages(config.readBoolEntry("Load All Images", false));
+
+ // allow status messages from the document
+ connect(doc, SIGNAL(signalStatusMsg(const QString&)),
+ SLOT(slotStatusMsg(const QString&)));
+
+ // do stuff that changes when the doc is modified
+ connect(doc, SIGNAL(signalModified(bool)),
+ SLOT(slotEnableModifiedActions(bool)));
+
+ connect(Kernel::self()->commandHistory(), SIGNAL(commandExecuted()),
+ doc, SLOT(slotSetModified()));
+ connect(Kernel::self()->commandHistory(), SIGNAL(documentRestored()),
+ doc, SLOT(slotDocumentRestored()));
+}
+
+void MainWindow::initView() {
+ MARK;
+ m_split = new QSplitter(Qt::Horizontal, this);
+ setCentralWidget(m_split);
+
+ m_viewTabs = new GUI::TabControl(m_split);
+ m_viewTabs->setTabBarHidden(true);
+ m_groupView = new GroupView(m_viewTabs, "groupview");
+ Controller::self()->addObserver(m_groupView);
+ m_viewTabs->addTab(m_groupView, SmallIcon(QString::fromLatin1("folder")), i18n("Groups"));
+ QWhatsThis::add(m_groupView, i18n("<qt>The <i>Group View</i> sorts the entries into groupings "
+ "based on a selected field.</qt>"));
+
+ m_rightSplit = new QSplitter(Qt::Vertical, m_split);
+
+ m_detailedView = new DetailedListView(m_rightSplit, "detailedlistview");
+ Controller::self()->addObserver(m_detailedView);
+ QWhatsThis::add(m_detailedView, i18n("<qt>The <i>Column View</i> shows the value of multiple fields "
+ "for each entry.</qt>"));
+ connect(Data::Document::self(), SIGNAL(signalCollectionImagesLoaded(Tellico::Data::CollPtr)),
+ m_detailedView, SLOT(slotRefreshImages()));
+
+ m_viewStack = new ViewStack(m_rightSplit, "viewstack");
+ Controller::self()->addObserver(m_viewStack->iconView());
+ connect(m_viewStack->entryView(), SIGNAL(signalAction(const KURL&)),
+ SLOT(slotURLAction(const KURL&)));
+
+ setMinimumWidth(MAIN_WINDOW_MIN_WIDTH);
+}
+
+void MainWindow::initConnections() {
+ // have to toggle the menu item if the dialog gets closed
+ connect(m_editDialog, SIGNAL(finished()),
+ this, SLOT(slotEditDialogFinished()));
+
+ // let the group view call filters, too
+ connect(m_groupView, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)),
+ Controller::self(), SLOT(slotUpdateFilter(Tellico::FilterPtr)));
+}
+
+void MainWindow::initFileOpen(bool nofile_) {
+ MARK;
+ slotInit();
+ // check to see if most recent file should be opened
+ bool happyStart = false;
+ if(!nofile_ && Config::reopenLastFile()) {
+ // Config::lastOpenFile() is the full URL, protocol included
+ KURL lastFile(Config::lastOpenFile()); // empty string is actually ok, it gets handled
+ if(!lastFile.isEmpty() && lastFile.isValid()) {
+ slotFileOpen(lastFile);
+ happyStart = true;
+ }
+ }
+ if(!happyStart) {
+ // the document is created with an initial book collection, continue with that
+ Controller::self()->slotCollectionAdded(Data::Document::self()->collection());
+
+ m_fileSave->setEnabled(false);
+ slotEnableOpenedActions();
+ slotEnableModifiedActions(false);
+
+ slotEntryCount();
+
+ const int type = Kernel::self()->collectionType();
+ QString welcomeFile = locate("appdata", QString::fromLatin1("welcome.html"));
+ QString text = FileHandler::readTextFile(welcomeFile);
+ text.replace(QString::fromLatin1("$FGCOLOR$"), Config::templateTextColor(type).name());
+ text.replace(QString::fromLatin1("$BGCOLOR$"), Config::templateBaseColor(type).name());
+ text.replace(QString::fromLatin1("$COLOR1$"), Config::templateHighlightedTextColor(type).name());
+ text.replace(QString::fromLatin1("$COLOR2$"), Config::templateHighlightedBaseColor(type).name());
+ text.replace(QString::fromLatin1("$IMGDIR$"), QFile::encodeName(ImageFactory::tempDir()));
+ text.replace(QString::fromLatin1("$BANNER$"),
+ i18n("Welcome to the Tellico Collection Manager"));
+ text.replace(QString::fromLatin1("$WELCOMETEXT$"),
+ i18n("<h3>Tellico is a tool for managing collections of books, "
+ "videos, music, and whatever else you want to catalog.</h3>"
+ "<h3>New entries can be added to your collection by "
+ "<a href=\"tc:///coll_new_entry\">entering data manually</a> or by "
+ "<a href=\"tc:///edit_search_internet\">downloading data</a> from "
+ "various Internet sources.</h3>"));
+ m_viewStack->entryView()->showText(text);
+ }
+ m_initialized = true;
+}
+
+// These are general options.
+// The options that can be changed in the "Configuration..." dialog
+// are taken care of by the ConfigDialog object.
+void MainWindow::saveOptions() {
+// myDebug() << "MainWindow::saveOptions()" << endl;
+
+ saveMainWindowSettings(KGlobal::config(), QString::fromLatin1("Main Window Options"));
+
+ Config::setShowGroupWidget(m_toggleGroupWidget->isChecked());
+ Config::setShowEditWidget(m_toggleEntryEditor->isChecked());
+ Config::setShowEntryView(m_toggleEntryView->isChecked());
+
+ m_fileOpenRecent->saveEntries(KGlobal::config(), QString::fromLatin1("Recent Files"));
+ if(!isNewDocument()) {
+ Config::setLastOpenFile(Data::Document::self()->URL().url());
+ }
+
+ if(m_groupView->isShown()) {
+ Config::setMainSplitterSizes(m_split->sizes());
+ }
+ if(m_viewStack->isShown()) {
+ // badly named option, but no need to change
+ Config::setSecondarySplitterSizes(m_rightSplit->sizes());
+ }
+
+ Config::setGroupViewSortColumn(m_groupView->sortStyle()); // ok to use SortColumn key, save semantics
+ Config::setGroupViewSortAscending(m_groupView->ascendingSort());
+
+ if(m_loanView) {
+ Config::setLoanViewSortAscending(m_loanView->sortStyle()); // ok to use SortColumn key, save semantics
+ Config::setLoanViewSortAscending(m_loanView->ascendingSort());
+ }
+
+ if(m_filterView) {
+ Config::setFilterViewSortAscending(m_filterView->sortStyle()); // ok to use SortColumn key, save semantics
+ Config::setFilterViewSortAscending(m_filterView->ascendingSort());
+ }
+
+ // this is used in the EntryEditDialog constructor, too
+ m_editDialog->saveDialogSize(QString::fromLatin1("Edit Dialog Options"));
+
+ saveCollectionOptions(Data::Document::self()->collection());
+ Config::writeConfig();
+}
+
+void MainWindow::readCollectionOptions(Data::CollPtr coll_) {
+ KConfigGroup group(KGlobal::config(), QString::fromLatin1("Options - %1").arg(coll_->typeName()));
+
+ QString defaultGroup = coll_->defaultGroupField();
+ QString entryGroup;
+ if(coll_->type() != Data::Collection::Base) {
+ entryGroup = group.readEntry("Group By", defaultGroup);
+ } else {
+ KURL url = Kernel::self()->URL();
+ for(uint i = 0; i < Config::maxCustomURLSettings(); ++i) {
+ KURL u = group.readEntry(QString::fromLatin1("URL_%1").arg(i));
+ if(url == u) {
+ entryGroup = group.readEntry(QString::fromLatin1("Group By_%1").arg(i), defaultGroup);
+ break;
+ }
+ }
+ // fall back to old setting
+ if(entryGroup.isEmpty()) {
+ entryGroup = group.readEntry("Group By", defaultGroup);
+ }
+ }
+ if(entryGroup.isEmpty() || !coll_->entryGroups().contains(entryGroup)) {
+ entryGroup = defaultGroup;
+ }
+ m_groupView->setGroupField(entryGroup);
+
+ QString entryXSLTFile = Config::templateName(coll_->type());
+ if(entryXSLTFile.isEmpty()) {
+ entryXSLTFile = QString::fromLatin1("Fancy"); // should never happen, but just in case
+ }
+ m_viewStack->entryView()->setXSLTFile(entryXSLTFile + QString::fromLatin1(".xsl"));
+
+ // make sure the right combo element is selected
+ slotUpdateCollectionToolBar(coll_);
+}
+
+void MainWindow::saveCollectionOptions(Data::CollPtr coll_) {
+ // don't save initial collection options, or empty collections
+ if(!coll_ || coll_->entryCount() == 0 || isNewDocument()) {
+ return;
+ }
+
+ int configIndex = -1;
+ KConfigGroup config(KGlobal::config(), QString::fromLatin1("Options - %1").arg(coll_->typeName()));
+ QString groupName;
+ if(m_entryGrouping->currentItem() > -1 &&
+ static_cast<int>(coll_->entryGroups().count()) > m_entryGrouping->currentItem()) {
+ groupName = Kernel::self()->fieldNameByTitle(m_entryGrouping->currentText());
+ if(coll_->type() != Data::Collection::Base) {
+ config.writeEntry("Group By", groupName);
+ }
+ }
+
+ if(coll_->type() == Data::Collection::Base) {
+ // all of this is to have custom settings on a per file basis
+ KURL url = Kernel::self()->URL();
+ QValueList<KURL> urls = QValueList<KURL>() << url;
+ QStringList groupBys = QStringList() << groupName;
+ for(uint i = 0; i < Config::maxCustomURLSettings(); ++i) {
+ KURL u = config.readEntry(QString::fromLatin1("URL_%1").arg(i));
+ QString g = config.readEntry(QString::fromLatin1("Group By_%1").arg(i));
+ if(!u.isEmpty() && url != u) {
+ urls.append(u);
+ groupBys.append(g);
+ } else if(!u.isEmpty()) {
+ configIndex = i;
+ }
+ }
+ uint limit = QMIN(urls.count(), Config::maxCustomURLSettings());
+ for(uint i = 0; i < limit; ++i) {
+ config.writeEntry(QString::fromLatin1("URL_%1").arg(i), urls[i].url());
+ config.writeEntry(QString::fromLatin1("Group By_%1").arg(i), groupBys[i]);
+ }
+ }
+ m_detailedView->saveConfig(coll_, configIndex);
+}
+
+void MainWindow::readOptions() {
+// myDebug() << "MainWindow::readOptions()" << endl;
+
+ applyMainWindowSettings(KGlobal::config(), QString::fromLatin1("Main Window Options"));
+
+ QValueList<int> splitList = Config::mainSplitterSizes();
+ if(!splitList.empty()) {
+ m_split->setSizes(splitList);
+ }
+
+ splitList = Config::secondarySplitterSizes();
+ if(!splitList.empty()) {
+ m_rightSplit->setSizes(splitList);
+ }
+
+ m_viewStack->iconView()->setMaxAllowedIconWidth(Config::maxIconSize());
+
+ connect(toolBar("collectionToolBar"), SIGNAL(modechange()), SLOT(slotUpdateToolbarIcons()));
+
+ m_toggleGroupWidget->setChecked(Config::showGroupWidget());
+ slotToggleGroupWidget();
+
+ m_toggleEntryView->setChecked(Config::showEntryView());
+ slotToggleEntryView();
+
+ // initialize the recent file list
+ m_fileOpenRecent->loadEntries(KGlobal::config(), QString::fromLatin1("Recent Files"));
+
+ // sort by count if column = 1
+ int sortStyle = Config::groupViewSortColumn();
+ m_groupView->setSortStyle(static_cast<GUI::ListView::SortStyle>(sortStyle));
+ bool sortAscending = Config::groupViewSortAscending();
+ m_groupView->setSortOrder(sortAscending ? Qt::Ascending : Qt::Descending);
+
+ m_detailedView->setPixmapSize(Config::maxPixmapWidth(), Config::maxPixmapHeight());
+
+ bool useBraces = Config::useBraces();
+ if(useBraces) {
+ BibtexHandler::s_quoteStyle = BibtexHandler::BRACES;
+ } else {
+ BibtexHandler::s_quoteStyle = BibtexHandler::QUOTES;
+ }
+
+ // Don't read any options for the edit dialog here, since it's not yet initialized.
+ // Put them in init()
+}
+
+void MainWindow::saveProperties(KConfig* cfg_) {
+ if(!isNewDocument() && !Data::Document::self()->isModified()) {
+ // saving to tempfile not necessary
+ } else {
+ KURL url = Data::Document::self()->URL();
+ cfg_->writeEntry("filename", url.url());
+ cfg_->writeEntry("modified", Data::Document::self()->isModified());
+ QString tempname = KURL::encode_string(kapp->tempSaveName(url.url()));
+ KURL tempurl;
+ tempurl.setPath(tempname);
+ Data::Document::self()->saveDocument(tempurl);
+ }
+}
+
+void MainWindow::readProperties(KConfig* cfg_) {
+ QString filename = cfg_->readEntry(QString::fromLatin1("filename"));
+ bool modified = cfg_->readBoolEntry(QString::fromLatin1("modified"), false);
+ if(modified) {
+ bool canRecover;
+ QString tempname = kapp->checkRecoverFile(filename, canRecover);
+
+ if(canRecover) {
+ KURL tempurl;
+ tempurl.setPath(tempname);
+ Data::Document::self()->openDocument(tempurl);
+ Data::Document::self()->slotSetModified(true);
+ updateCaption(true);
+ QFile::remove(tempname);
+ }
+ } else {
+ if(!filename.isEmpty()) {
+ KURL url;
+ url.setPath(filename);
+ Data::Document::self()->openDocument(url);
+ updateCaption(false);
+ }
+ }
+}
+
+bool MainWindow::queryClose() {
+ // in case we're still loading the images, cancel that
+ Data::Document::self()->cancelImageWriting();
+ return m_editDialog->queryModified() && Data::Document::self()->saveModified();
+}
+
+bool MainWindow::queryExit() {
+ FileHandler::clean();
+ ImageFactory::clean(true);
+ saveOptions();
+ return true;
+}
+
+void MainWindow::slotFileNew(int type_) {
+ slotStatusMsg(i18n("Creating new document..."));
+
+ // close the fields dialog
+ slotHideCollectionFieldsDialog();
+
+ if(m_editDialog->queryModified() && Data::Document::self()->saveModified()) {
+ // remove filter and loan tabs, they'll get re-added if needed
+ if(m_filterView) {
+ m_viewTabs->removePage(m_filterView);
+ Controller::self()->removeObserver(m_filterView);
+ delete m_filterView;
+ m_filterView = 0;
+ }
+ if(m_loanView) {
+ m_viewTabs->removePage(m_loanView);
+ Controller::self()->removeObserver(m_loanView);
+ delete m_loanView;
+ m_loanView = 0;
+ }
+ m_viewTabs->setTabBarHidden(true);
+ Data::Document::self()->newDocument(type_);
+ m_fileOpenRecent->setCurrentItem(-1);
+ slotEnableOpenedActions();
+ slotEnableModifiedActions(false);
+ m_newDocument = true;
+ ImageFactory::clean(false);
+ }
+
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotFileOpen() {
+ slotStatusMsg(i18n("Opening file..."));
+
+ if(m_editDialog->queryModified() && Data::Document::self()->saveModified()) {
+ QString filter = i18n("*.tc *.bc|Tellico Files (*.tc)");
+ filter += QString::fromLatin1("\n");
+ filter += i18n("*.xml|XML Files (*.xml)");
+ filter += QString::fromLatin1("\n");
+ filter += i18n("*|All Files");
+ // keyword 'open'
+ KURL url = KFileDialog::getOpenURL(QString::fromLatin1(":open"), filter,
+ this, i18n("Open File"));
+ if(!url.isEmpty() && url.isValid()) {
+ slotFileOpen(url);
+ }
+ }
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotFileOpen(const KURL& url_) {
+ slotStatusMsg(i18n("Opening file..."));
+
+ // close the fields dialog
+ slotHideCollectionFieldsDialog();
+
+ // there seems to be a race condition at start between slotInit() and initFileOpen()
+ // which means the edit dialog might not have been created yet
+ if((!m_editDialog || m_editDialog->queryModified()) && Data::Document::self()->saveModified()) {
+ if(openURL(url_)) {
+ m_fileOpenRecent->addURL(url_);
+ m_fileOpenRecent->setCurrentItem(-1);
+ }
+ }
+
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotFileOpenRecent(const KURL& url_) {
+ slotStatusMsg(i18n("Opening file..."));
+
+ // close the fields dialog
+ slotHideCollectionFieldsDialog();
+
+ if(m_editDialog->queryModified() && Data::Document::self()->saveModified()) {
+ if(!openURL(url_)) {
+ m_fileOpenRecent->removeURL(url_);
+ m_fileOpenRecent->setCurrentItem(-1);
+ }
+ } else {
+ // the KAction shouldn't be checked now
+ m_fileOpenRecent->setCurrentItem(-1);
+ }
+
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::openFile(const QString& file_) {
+ KURL url = KURL::fromPathOrURL(file_);
+ if(!url.isEmpty() && url.isValid()) {
+ slotFileOpen(url);
+ }
+}
+
+bool MainWindow::openURL(const KURL& url_) {
+// myDebug() << "MainWindow::openURL() - " << url_.prettyURL() << endl;
+
+ // try to open document
+ GUI::CursorSaver cs(Qt::waitCursor);
+
+ bool success = Data::Document::self()->openDocument(url_);
+
+ if(success) {
+ m_quickFilter->clear();
+ slotEnableOpenedActions();
+ m_newDocument = false;
+ slotEnableModifiedActions(Data::Document::self()->isModified()); // doc might add some stuff
+ } else if(!m_initialized) {
+ // special case on startup when openURL() is called with a command line argument
+ // and that URL can't be opened. The window still needs to be initialized
+ // the doc object is created with an initial book collection, continue with that
+ Controller::self()->slotCollectionAdded(Data::Document::self()->collection());
+
+ m_fileSave->setEnabled(false);
+ slotEnableOpenedActions();
+ slotEnableModifiedActions(false);
+
+ slotEntryCount();
+ }
+ // slotFileOpen(URL) gets called when opening files on the command line
+ // so go ahead and make sure m_initialized is set.
+ m_initialized = true;
+
+ // remove filter and loan tabs, they'll get re-added if needed
+ if(m_filterView && m_filterView->childCount() == 0) {
+ m_viewTabs->removePage(m_filterView);
+ Controller::self()->removeObserver(m_filterView);
+ delete m_filterView;
+ m_filterView = 0;
+ }
+ if(m_loanView && m_loanView->childCount() == 0) {
+ m_viewTabs->removePage(m_loanView);
+ Controller::self()->removeObserver(m_loanView);
+ delete m_loanView;
+ m_loanView = 0;
+ }
+ Controller::self()->hideTabs(); // does conditional check
+
+ return success;
+}
+
+void MainWindow::slotFileSave() {
+ fileSave();
+}
+
+bool MainWindow::fileSave() {
+ if(!m_editDialog->queryModified()) {
+ return false;
+ }
+ slotStatusMsg(i18n("Saving file..."));
+
+ bool ret = true;
+ if(isNewDocument()) {
+ ret = fileSaveAs();
+ } else {
+ // special check: if there are more than 200 images AND the "Write Images In File" config key
+ // is not set, then warn user that performance may suffer, and write result
+ if(Config::imageLocation() == Config::ImagesInFile &&
+ Config::askWriteImagesInFile() &&
+ Data::Document::self()->imageCount() > MAX_IMAGES_WARN_PERFORMANCE) {
+ QString msg = i18n("<qt><p>You are saving a file with many images, which causes Tellico to "
+ "slow down significantly. Do you want to save the images separately in "
+ "Tellico's data directory to improve performance?</p><p>Your choice can "
+ "always be changed in the configuration dialog.</p></qt>");
+
+ KGuiItem yes(i18n("Save Images Separately"));
+ KGuiItem no(i18n("Save Images in File"));
+
+ int res = KMessageBox::warningYesNo(this, msg, QString::null /* caption */, yes, no);
+ if(res == KMessageBox::No) {
+ Config::setImageLocation(Config::ImagesInAppDir);
+ }
+ Config::setAskWriteImagesInFile(false);
+ }
+
+ GUI::CursorSaver cs(Qt::waitCursor);
+ if(Data::Document::self()->saveDocument(Data::Document::self()->URL())) {
+ m_newDocument = false;
+ updateCaption(false);
+ m_fileSave->setEnabled(false);
+ m_detailedView->resetEntryStatus();
+ } else {
+ ret = false;
+ }
+ }
+
+ StatusBar::self()->clearStatus();
+ return ret;
+}
+
+void MainWindow::slotFileSaveAs() {
+ fileSaveAs();
+}
+
+bool MainWindow::fileSaveAs() {
+ if(!m_editDialog->queryModified()) {
+ return false;
+ }
+
+ slotStatusMsg(i18n("Saving file with a new filename..."));
+
+ QString filter = i18n("*.tc *.bc|Tellico Files (*.tc)");
+ filter += QChar('\n');
+ filter += i18n("*|All Files");
+
+ // keyword 'open'
+ KFileDialog dlg(QString::fromLatin1(":open"), filter, this, "filedialog", true);
+ dlg.setCaption(i18n("Save As"));
+ dlg.setOperationMode(KFileDialog::Saving);
+
+ int result = dlg.exec();
+ if(result == QDialog::Rejected) {
+ StatusBar::self()->clearStatus();
+ return false;
+ }
+
+ bool ret = true;
+ KURL url = dlg.selectedURL();
+ if(!url.isEmpty() && url.isValid()) {
+ GUI::CursorSaver cs(Qt::waitCursor);
+ if(Data::Document::self()->saveDocument(url)) {
+ KRecentDocument::add(url);
+ m_fileOpenRecent->addURL(url);
+ updateCaption(false);
+ m_newDocument = false;
+ m_fileSave->setEnabled(false);
+ m_detailedView->resetEntryStatus();
+ } else {
+ ret = false;
+ }
+ }
+
+ StatusBar::self()->clearStatus();
+ return ret;
+}
+
+void MainWindow::slotFilePrint() {
+ slotStatusMsg(i18n("Printing..."));
+
+ bool printGrouped = Config::printGrouped();
+ bool printHeaders = Config::printFieldHeaders();
+ int imageWidth = Config::maxImageWidth();
+ int imageHeight = Config::maxImageHeight();
+
+ // If the collection is being filtered, warn the user
+ if(m_detailedView->filter() != 0) {
+ QString str = i18n("The collection is currently being filtered to show a limited subset of "
+ "the entries. Only the visible entries will be printed. Continue?");
+ int ret = KMessageBox::warningContinueCancel(this, str, QString::null, KStdGuiItem::print(),
+ QString::fromLatin1("WarnPrintVisible"));
+ if(ret == KMessageBox::Cancel) {
+ StatusBar::self()->clearStatus();
+ return;
+ }
+ }
+
+ GUI::CursorSaver cs(Qt::waitCursor);
+
+ Export::HTMLExporter exporter(Data::Document::self()->collection());
+ // only print visible entries
+ exporter.setEntries(m_detailedView->visibleEntries());
+ exporter.setXSLTFile(QString::fromLatin1("tellico-printing.xsl"));
+ exporter.setPrintHeaders(printHeaders);
+ exporter.setPrintGrouped(printGrouped);
+ exporter.setGroupBy(Controller::self()->expandedGroupBy());
+ if(!printGrouped) { // the sort titles are only used if the entries are not grouped
+ exporter.setSortTitles(Controller::self()->sortTitles());
+ }
+ exporter.setColumns(m_detailedView->visibleColumns());
+ exporter.setMaxImageSize(imageWidth, imageHeight);
+
+ slotStatusMsg(i18n("Processing document..."));
+ if(Config::printFormatted()) {
+ exporter.setOptions(Export::ExportUTF8 | Export::ExportFormatted);
+ } else {
+ exporter.setOptions(Export::ExportUTF8);
+ }
+ QString html = exporter.text();
+ if(html.isEmpty()) {
+ XSLTError();
+ StatusBar::self()->clearStatus();
+ return;
+ }
+
+ // don't have busy cursor when showing the print dialog
+ cs.restore();
+// myDebug() << html << endl;
+ slotStatusMsg(i18n("Printing..."));
+ doPrint(html);
+
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotFileQuit() {
+ slotStatusMsg(i18n("Exiting..."));
+
+ // this gets called in queryExit() anyway
+ //saveOptions();
+ close();
+
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotEditCut() {
+ activateEditSlot(SLOT(cut()));
+}
+
+void MainWindow::slotEditCopy() {
+ activateEditSlot(SLOT(copy()));
+}
+
+void MainWindow::slotEditPaste() {
+ activateEditSlot(SLOT(paste()));
+}
+
+void MainWindow::activateEditSlot(const char* slot_) {
+ // the edit widget is the only one that copies, cuts, and pastes
+ QWidget* w;
+ if(m_editDialog->isVisible()) {
+ w = m_editDialog->focusWidget();
+ } else {
+ w = kapp->focusWidget();
+ }
+
+ if(w && w->isVisible()) {
+ QMetaObject* meta = w->metaObject();
+
+ int idx = meta->findSlot(slot_ + 1, true);
+ if(idx > -1) {
+ w->qt_invoke(idx, 0);
+ }
+ }
+}
+
+void MainWindow::slotEditSelectAll() {
+ m_detailedView->selectAllVisible();
+}
+
+void MainWindow::slotEditDeselect() {
+ Controller::self()->slotUpdateSelection(0, Data::EntryVec());
+}
+
+void MainWindow::slotConfigToolbar() {
+ saveMainWindowSettings(KGlobal::config(), QString::fromLatin1("Main Window Options"));
+#ifdef UIFILE
+ KEditToolbar dlg(actionCollection(), UIFILE);
+#else
+ KEditToolbar dlg(actionCollection());
+#endif
+ connect(&dlg, SIGNAL(newToolbarConfig()), this, SLOT(slotNewToolbarConfig()));
+ dlg.exec();
+}
+
+void MainWindow::slotNewToolbarConfig() {
+ applyMainWindowSettings(KGlobal::config(), QString::fromLatin1("Main Window Options"));
+#ifdef UIFILE
+ createGUI(UIFILE, false);
+#else
+ createGUI(QString::null, false);
+#endif
+}
+
+void MainWindow::slotConfigKeys() {
+ KKeyDialog::configure(actionCollection());
+}
+
+void MainWindow::slotToggleGroupWidget() {
+ if(m_toggleGroupWidget->isChecked()) {
+ m_viewTabs->show();
+ } else {
+ m_viewTabs->hide();
+ }
+}
+
+void MainWindow::slotToggleEntryEditor() {
+ if(m_toggleEntryEditor->isChecked()) {
+ m_editDialog->show();
+ } else {
+ m_editDialog->hide();
+ }
+}
+
+void MainWindow::slotToggleEntryView() {
+ if(m_toggleEntryView->isChecked()) {
+ m_viewStack->show();
+ } else {
+ m_viewStack->hide();
+ }
+}
+
+void MainWindow::slotShowConfigDialog() {
+ if(!m_configDlg) {
+ m_configDlg = new ConfigDialog(this);
+ m_configDlg->show();
+ m_configDlg->readConfiguration();
+ connect(m_configDlg, SIGNAL(signalConfigChanged()),
+ SLOT(slotHandleConfigChange()));
+ connect(m_configDlg, SIGNAL(finished()),
+ SLOT(slotHideConfigDialog()));
+ } else {
+ KWin::activateWindow(m_configDlg->winId());
+ m_configDlg->show();
+ }
+}
+
+void MainWindow::slotHideConfigDialog() {
+ if(m_configDlg) {
+ m_configDlg->delayedDestruct();
+ m_configDlg = 0;
+ }
+}
+
+void MainWindow::slotShowTipOfDay(bool force_/*=true*/) {
+ QString tipfile = locate("appdata", QString::fromLatin1("tellico.tips"));
+ KTipDialog::showTip(this, tipfile, force_);
+}
+
+void MainWindow::slotStatusMsg(const QString& text_) {
+ m_statusBar->setStatus(text_);
+}
+
+void MainWindow::slotClearStatus() {
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotEntryCount() {
+ Data::CollPtr coll = Data::Document::self()->collection();
+ if(!coll) {
+ return;
+ }
+
+ int count = coll->entryCount();
+ QString text = i18n("Total entries: %1").arg(count);
+
+ int selectCount = Controller::self()->selectedEntries().count();
+ int filterCount = m_detailedView->visibleItems();
+ // if more than one book is selected, add the number of selected books
+ if(filterCount < count && selectCount > 1) {
+ text += QChar(' ');
+ text += i18n("(%1 filtered; %2 selected)").arg(filterCount).arg(selectCount);
+ } else if(filterCount < count) {
+ text += QChar(' ');
+ text += i18n("(%1 filtered)").arg(filterCount);
+ } else if(selectCount > 1) {
+ text += QChar(' ');
+ text += i18n("(%1 selected)").arg(selectCount);
+ }
+
+ m_statusBar->setCount(text);
+}
+
+void MainWindow::slotEnableOpenedActions() {
+ slotUpdateToolbarIcons();
+
+ // collapse all the groups (depth=1)
+ m_groupView->slotCollapseAll(1);
+
+ updateCollectionActions();
+
+ // close the filter dialog when a new collection is opened
+ slotHideFilterDialog();
+ slotHideStringMacroDialog();
+}
+
+void MainWindow::slotEnableModifiedActions(bool modified_ /*= true*/) {
+ updateCaption(modified_);
+ updateCollectionActions();
+ m_fileSave->setEnabled(modified_);
+}
+
+void MainWindow::slotHandleConfigChange() {
+ const int imageLocation = Config::imageLocation();
+ const bool autoCapitalize = Config::autoCapitalization();
+ const bool autoFormat = Config::autoFormat();
+ QStringList articles = Config::articleList();
+ QStringList nocaps = Config::noCapitalizationList();
+ QStringList suffixes = Config::nameSuffixList();
+ QStringList prefixes = Config::surnamePrefixList();
+
+ m_configDlg->saveConfiguration();
+
+ // only modified if there are entries and image location is changed
+ if(imageLocation != Config::imageLocation() && !Data::Document::self()->isEmpty()) {
+ Data::Document::self()->slotSetModified();
+ }
+
+ if(autoCapitalize != Config::autoCapitalization() ||
+ autoFormat != Config::autoFormat() ||
+ articles != Config::articleList() ||
+ nocaps != Config::noCapitalizationList() ||
+ suffixes != Config::nameSuffixList() ||
+ prefixes != Config::surnamePrefixList()) {
+ // invalidate all groups
+ Data::Document::self()->collection()->invalidateGroups();
+ // refreshing the title causes the group view to refresh
+ Controller::self()->slotRefreshField(Data::Document::self()->collection()->fieldByName(QString::fromLatin1("title")));
+ }
+
+ QString entryXSLTFile = Config::templateName(Kernel::self()->collectionType());
+ m_viewStack->entryView()->setXSLTFile(entryXSLTFile + QString::fromLatin1(".xsl"));
+}
+
+void MainWindow::slotUpdateCollectionToolBar(Data::CollPtr coll_) {
+// myDebug() << "MainWindow::updateCollectionToolBar()" << endl;
+
+ if(!coll_) {
+ kdWarning() << "MainWindow::slotUpdateCollectionToolBar() - no collection pointer!" << endl;
+ return;
+ }
+
+ QString current = m_groupView->groupBy();
+ if(current.isEmpty() || !coll_->entryGroups().contains(current)) {
+ current = coll_->defaultGroupField();
+ }
+
+ const QStringList groups = coll_->entryGroups();
+ if(groups.isEmpty()) {
+ m_entryGrouping->clear();
+ return;
+ }
+
+ QMap<QString, QString> groupMap; // use a map so they get sorted
+ for(QStringList::ConstIterator groupIt = groups.begin(); groupIt != groups.end(); ++groupIt) {
+ // special case for people "pseudo-group"
+ if(*groupIt == Data::Collection::s_peopleGroupName) {
+ groupMap.insert(*groupIt, QString::fromLatin1("<") + i18n("People") + QString::fromLatin1(">"));
+ } else {
+ groupMap.insert(*groupIt, coll_->fieldTitleByName(*groupIt));
+ }
+ }
+
+ QStringList names = groupMap.keys();
+ int index = names.findIndex(current);
+ if(index == -1) {
+ current = names[0];
+ index = 0;
+ }
+ QStringList titles = groupMap.values();
+ m_entryGrouping->setItems(titles);
+ m_entryGrouping->setCurrentItem(index);
+ // in case the current grouping field get modified to be non-grouping...
+ m_groupView->setGroupField(current); // don't call slotChangeGrouping() since it adds an undo item
+
+ // this isn't really proper, but works so the combo box width gets adjusted
+ const int len = m_entryGrouping->containerCount();
+ for(int i = 0; i < len; ++i) {
+ KToolBar* tb = dynamic_cast<KToolBar*>(m_entryGrouping->container(i));
+ if(tb) {
+ KComboBox* cb = tb->getCombo(m_entryGrouping->itemId(i));
+ if(cb) {
+ // qt caches the combobox size and never recalculates the sizeHint()
+ // the source code recommends calling setFont to invalidate the sizeHint
+ cb->setFont(cb->font());
+ cb->updateGeometry();
+ }
+ }
+ }
+}
+
+void MainWindow::slotChangeGrouping() {
+// myDebug() << "MainWindow::slotChangeGrouping()" << endl;
+ QString title = m_entryGrouping->currentText();
+
+ QString groupName = Kernel::self()->fieldNameByTitle(title);
+ if(groupName.isEmpty()) {
+ if(title == QString::fromLatin1("<") + i18n("People") + QString::fromLatin1(">")) {
+ groupName = Data::Collection::s_peopleGroupName;
+ } else {
+ groupName = Data::Document::self()->collection()->defaultGroupField();
+ }
+ }
+ m_groupView->setGroupField(groupName);
+ m_viewTabs->showPage(m_groupView);
+}
+
+void MainWindow::slotShowReportDialog() {
+// myDebug() << "MainWindow::slotShowReport()" << endl;
+ if(!m_reportDlg) {
+ m_reportDlg = new ReportDialog(this);
+ connect(m_reportDlg, SIGNAL(finished()),
+ SLOT(slotHideReportDialog()));
+ } else {
+ KWin::activateWindow(m_reportDlg->winId());
+ }
+ m_reportDlg->show();
+}
+
+void MainWindow::slotHideReportDialog() {
+ if(m_reportDlg) {
+ m_reportDlg->delayedDestruct();
+ m_reportDlg = 0;
+ }
+}
+
+void MainWindow::doPrint(const QString& html_) {
+ KHTMLPart w ;
+ w.setJScriptEnabled(false);
+ w.setJavaEnabled(false);
+ w.setMetaRefreshEnabled(false);
+ w.setPluginsEnabled(false);
+ w.begin(Data::Document::self()->URL());
+ w.write(html_);
+ w.end();
+
+// the problem with doing my own layout is that the text gets truncated, both at the
+// top and at the bottom. Even adding the overlap parameter, there were problems.
+// KHTMLView takes care of that with a truncatedAt() parameter, but that's hidden in
+// the khtml::render_root class. So for now, just use the KHTMLView::print() method.
+#if 1
+ w.view()->print();
+#else
+ KPrinter* printer = new KPrinter(QPrinter::PrinterResolution);
+
+ if(printer->setup(this, i18n("Print %1").arg(Data::Document::self()->URL().prettyURL()))) {
+ printer->setFullPage(false);
+ printer->setCreator(QString::fromLatin1("Tellico"));
+ printer->setDocName(Data::Document::self()->URL().prettyURL());
+
+ QPainter *p = new QPainter;
+ p->begin(printer);
+
+ // mostly taken from KHTMLView::print()
+ QString headerLeft = KGlobal::locale()->formatDate(QDate::currentDate(), false);
+ QString headerRight = Data::Document::self()->URL().prettyURL();
+ QString footerMid;
+
+ QFont headerFont(QString::fromLatin1("helvetica"), 8);
+ p->setFont(headerFont);
+ const int lspace = p->fontMetrics().lineSpacing();
+ const int headerHeight = (lspace * 3) / 2;
+
+ QPaintDeviceMetrics metrics(printer);
+ const int pageHeight = metrics.height() - 2*headerHeight;
+ const int pageWidth = metrics.width();
+
+// myDebug() << "MainWindow::doPrint() - pageHeight = " << pageHeight << ""
+// "; contentsHeight = " << w->view()->contentsHeight() << endl;
+
+ int top = 0;
+ int page = 1;
+
+ bool more = true;
+ while(more) {
+ p->setPen(Qt::black);
+ p->setFont(headerFont);
+
+ footerMid = i18n("Page %1").arg(page);
+
+ p->drawText(0, 0, pageWidth, lspace, Qt::AlignLeft, headerLeft);
+ p->drawText(0, 0, pageWidth, lspace, Qt::AlignRight, headerRight);
+ p->drawText(0, pageHeight+headerHeight, pageWidth, lspace, Qt::AlignHCenter, footerMid);
+
+ w->paint(p, QRect(0, -top + 2*headerHeight, pageWidth, pageHeight+top), top, &more);
+
+ top += pageHeight - PRINTED_PAGE_OVERLAP;
+
+ if(more) {
+ printer->newPage();
+ page++;
+ }
+// p->resetXForm();
+ }
+ // stop painting, this will automatically send the print data to the printer
+ p->end();
+ delete p;
+ }
+
+ delete printer;
+#endif
+}
+
+void MainWindow::XSLTError() {
+ QString str = i18n("Tellico encountered an error in XSLT processing.") + QChar('\n');
+ str += i18n("Please check your installation.");
+ Kernel::self()->sorry(str);
+}
+
+void MainWindow::slotShowFilterDialog() {
+ if(!m_filterDlg) {
+ m_filterDlg = new FilterDialog(FilterDialog::CreateFilter, this); // allow saving
+ m_filterDlg->setFilter(m_detailedView->filter());
+ m_quickFilter->setEnabled(false);
+ connect(m_filterDlg, SIGNAL(signalCollectionModified()),
+ Data::Document::self(), SLOT(slotSetModified()));
+ connect(m_filterDlg, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)),
+ m_quickFilter, SLOT(clear()));
+ connect(m_filterDlg, SIGNAL(signalUpdateFilter(Tellico::FilterPtr)),
+ Controller::self(), SLOT(slotUpdateFilter(Tellico::FilterPtr)));
+ connect(m_filterDlg, SIGNAL(finished()),
+ SLOT(slotHideFilterDialog()));
+ } else {
+ KWin::activateWindow(m_filterDlg->winId());
+ }
+ m_filterDlg->show();
+}
+
+void MainWindow::slotHideFilterDialog() {
+// m_quickFilter->blockSignals(false);
+ m_quickFilter->setEnabled(true);
+ if(m_filterDlg) {
+ m_filterDlg->delayedDestruct();
+ m_filterDlg = 0;
+ }
+}
+
+void MainWindow::slotQueueFilter() {
+ m_queuedFilters++;
+ QTimer::singleShot(200, this, SLOT(slotUpdateFilter()));
+}
+
+void MainWindow::slotUpdateFilter() {
+ m_queuedFilters--;
+ if(m_queuedFilters > 0) {
+ return;
+ }
+
+ setFilter(m_quickFilter->text());
+}
+
+void MainWindow::setFilter(const QString& text_) {
+ QString text = text_.stripWhiteSpace();
+ Filter::Ptr filter = 0;
+ if(!text.isEmpty()) {
+ filter = new Filter(Filter::MatchAll);
+ QString fieldName = QString::null;
+ // if the text contains '=' assume it's a field name or title
+ if(text.find('=') > -1) {
+ fieldName = text.section('=', 0, 0).stripWhiteSpace();
+ text = text.section('=', 1).stripWhiteSpace();
+ // check that the field name might be a title
+ if(!Data::Document::self()->collection()->hasField(fieldName)) {
+ fieldName = Data::Document::self()->collection()->fieldNameByTitle(fieldName);
+ }
+ }
+ // if the text contains any non-word characters, assume it's a regexp
+ // but \W in qt is letter, number, or '_', I want to be a bit less strict
+ QRegExp rx(QString::fromLatin1("[^\\w\\s-']"));
+ if(text.find(rx) == -1) {
+ // split by whitespace, and add rules for each word
+ QStringList tokens = QStringList::split(QRegExp(QString::fromLatin1("\\s")), text);
+ for(QStringList::Iterator it = tokens.begin(); it != tokens.end(); ++it) {
+ // an empty field string means check every field
+ filter->append(new FilterRule(fieldName, *it, FilterRule::FuncContains));
+ }
+ } else {
+ // if it isn't valid, hold off on applying the filter
+ QRegExp tx(text);
+ if(!tx.isValid()) {
+ myDebug() << "MainWindow::slotUpdateFilter() - invalid regexp: " << text << endl;
+ return;
+ }
+ filter->append(new FilterRule(fieldName, text, FilterRule::FuncRegExp));
+ }
+ // also want to update the line edit in case the filter was set by DCOP
+ if(m_quickFilter->text().isEmpty() && m_quickFilter->text() != text_) {
+ m_quickFilter->setText(text_);
+ }
+ }
+ // only update filter if one exists or did exist
+ if(filter || m_detailedView->filter()) {
+ Controller::self()->slotUpdateFilter(filter);
+ }
+}
+
+void MainWindow::slotShowCollectionFieldsDialog() {
+ if(!m_collFieldsDlg) {
+ m_collFieldsDlg = new CollectionFieldsDialog(Data::Document::self()->collection(), this);
+ connect(m_collFieldsDlg, SIGNAL(finished()),
+ SLOT(slotHideCollectionFieldsDialog()));
+ } else {
+ KWin::activateWindow(m_collFieldsDlg->winId());
+ }
+ m_collFieldsDlg->show();
+}
+
+void MainWindow::slotHideCollectionFieldsDialog() {
+ if(m_collFieldsDlg) {
+ m_collFieldsDlg->delayedDestruct();
+ m_collFieldsDlg = 0;
+ }
+}
+
+void MainWindow::slotFileImport(int format_) {
+ slotStatusMsg(i18n("Importing data..."));
+ m_quickFilter->clear();
+
+ Import::Format format = static_cast<Import::Format>(format_);
+ bool checkURL = true;
+ KURL url;
+ switch(ImportDialog::importTarget(format)) {
+ case Import::File:
+ url = KFileDialog::getOpenURL(ImportDialog::startDir(format), ImportDialog::fileFilter(format),
+ this, i18n("Import File"));
+ break;
+
+ case Import::Dir:
+ // TODO: allow remote audiofile importing
+ url.setPath(KFileDialog::getExistingDirectory(ImportDialog::startDir(format),
+ this, i18n("Import Directory")));
+ break;
+
+ case Import::None:
+ default:
+ checkURL = false;
+ break;
+ }
+
+ if(checkURL) {
+ bool ok = !url.isEmpty() && url.isValid() && KIO::NetAccess::exists(url, true, this);
+ if(!ok) {
+ StatusBar::self()->clearStatus();
+ return;
+ }
+ }
+ importFile(format, url);
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotFileExport(int format_) {
+ slotStatusMsg(i18n("Exporting data..."));
+
+ Export::Format format = static_cast<Export::Format>(format_);
+ ExportDialog dlg(format, Data::Document::self()->collection(), this, "exportdialog");
+
+ if(dlg.exec() == QDialog::Rejected) {
+ StatusBar::self()->clearStatus();
+ return;
+ }
+
+ switch(ExportDialog::exportTarget(format)) {
+ case Export::None:
+ dlg.exportURL();
+ break;
+
+ case Export::Dir:
+ myDebug() << "MainWindow::slotFileExport() - ExportDir not implemented!" << endl;
+ break;
+
+ case Export::File:
+ {
+ KFileDialog fileDlg(QString::fromLatin1(":export"), dlg.fileFilter(), this, "filedialog", true);
+ fileDlg.setCaption(i18n("Export As"));
+ fileDlg.setOperationMode(KFileDialog::Saving);
+
+ if(fileDlg.exec() == QDialog::Rejected) {
+ StatusBar::self()->clearStatus();
+ return;
+ }
+
+ KURL url = fileDlg.selectedURL();
+ if(!url.isEmpty() && url.isValid()) {
+ GUI::CursorSaver cs(Qt::waitCursor);
+ dlg.exportURL(url);
+ }
+ }
+ break;
+ }
+
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotShowStringMacroDialog() {
+ if(Data::Document::self()->collection()->type() != Data::Collection::Bibtex) {
+ return;
+ }
+
+ if(!m_stringMacroDlg) {
+ const Data::BibtexCollection* c = static_cast<Data::BibtexCollection*>(Data::Document::self()->collection().data());
+ m_stringMacroDlg = new StringMapDialog(c->macroList(), this, "StringMacroDialog", false);
+ m_stringMacroDlg->setCaption(i18n("String Macros"));
+ m_stringMacroDlg->setLabels(i18n("Macro"), i18n("String"));
+ connect(m_stringMacroDlg, SIGNAL(finished()), SLOT(slotHideStringMacroDialog()));
+ connect(m_stringMacroDlg, SIGNAL(okClicked()), SLOT(slotStringMacroDialogOk()));
+ } else {
+ KWin::activateWindow(m_stringMacroDlg->winId());
+ }
+ m_stringMacroDlg->show();
+}
+
+void MainWindow::slotHideStringMacroDialog() {
+ if(m_stringMacroDlg) {
+ m_stringMacroDlg->delayedDestruct();
+ m_stringMacroDlg = 0;
+ }
+}
+
+void MainWindow::slotStringMacroDialogOk() {
+ // no point in checking if collection is bibtex, as dialog would never have been created
+ if(m_stringMacroDlg) {
+ static_cast<Data::BibtexCollection*>(Data::Document::self()->collection().data())->setMacroList(m_stringMacroDlg->stringMap());
+ Data::Document::self()->slotSetModified(true);
+ }
+}
+
+void MainWindow::slotNewEntry() {
+ m_toggleEntryEditor->setChecked(true);
+ slotToggleEntryEditor();
+ m_editDialog->slotHandleNew();
+}
+
+void MainWindow::slotEditDialogFinished() {
+ m_toggleEntryEditor->setChecked(false);
+}
+
+void MainWindow::slotShowEntryEditor() {
+ m_toggleEntryEditor->setChecked(true);
+ m_editDialog->show();
+
+ KWin::activateWindow(m_editDialog->winId());
+}
+
+void MainWindow::slotConvertToBibliography() {
+ // only book collections can be converted to bibtex
+ Data::CollPtr coll = Data::Document::self()->collection();
+ if(!coll || coll->type() != Data::Collection::Book) {
+ return;
+ }
+
+ GUI::CursorSaver cs;
+
+ Data::CollPtr newColl = Data::BibtexCollection::convertBookCollection(coll);
+ if(newColl) {
+ m_newDocument = true;
+ Kernel::self()->replaceCollection(newColl);
+ m_fileOpenRecent->setCurrentItem(-1);
+ slotUpdateToolbarIcons();
+ updateCollectionActions();
+ } else {
+ kdWarning() << "MainWindow::slotConvertToBibliography() - ERROR: no bibliography created!" << endl;
+ }
+}
+
+void MainWindow::slotCiteEntry(int action_) {
+ StatusBar::self()->setStatus(i18n("Creating citations..."));
+ Cite::ActionManager::self()->cite(static_cast<Cite::CiteAction>(action_), Controller::self()->selectedEntries());
+ StatusBar::self()->clearStatus();
+}
+
+void MainWindow::slotShowFetchDialog() {
+ if(!m_fetchDlg) {
+ m_fetchDlg = new FetchDialog(this);
+ connect(m_fetchDlg, SIGNAL(finished()), SLOT(slotHideFetchDialog()));
+ connect(Controller::self(), SIGNAL(collectionAdded(int)), m_fetchDlg, SLOT(slotResetCollection()));
+ } else {
+ KWin::activateWindow(m_fetchDlg->winId());
+ }
+ m_fetchDlg->show();
+}
+
+void MainWindow::slotHideFetchDialog() {
+ if(m_fetchDlg) {
+ m_fetchDlg->delayedDestruct();
+ m_fetchDlg = 0;
+ }
+}
+
+bool MainWindow::importFile(Import::Format format_, const KURL& url_, Import::Action action_) {
+ // try to open document
+ GUI::CursorSaver cs(Qt::waitCursor);
+
+ bool failed = false;
+ Data::CollPtr coll;
+ if(!url_.isEmpty() && url_.isValid() && KIO::NetAccess::exists(url_, true, this)) {
+ coll = ImportDialog::importURL(format_, url_);
+ } else {
+ Kernel::self()->sorry(i18n(errorLoad).arg(url_.fileName()));
+ failed = true;
+ }
+
+ if(!coll && !m_initialized) {
+ // special case on startup when openURL() is called with a command line argument
+ // and that URL can't be opened. The window still needs to be initialized
+ // the doc object is created with an initial book collection, continue with that
+ Controller::self()->slotCollectionAdded(Data::Document::self()->collection());
+ m_fileSave->setEnabled(false);
+ slotEnableOpenedActions();
+ slotEnableModifiedActions(false);
+ slotEntryCount();
+ m_fileOpenRecent->setCurrentItem(-1);
+ m_initialized = true;
+ failed = true;
+ } else if(coll) {
+ // this is rather dumb, but I'm too lazy to find the bug
+ // if the document isn't initialized, then Tellico crashes
+ // since Document::replaceCollection() ends up calling lots of stuff that isn't initialized
+ if(!m_initialized) {
+ Controller::self()->slotCollectionAdded(Data::Document::self()->collection());
+ m_initialized = true;
+ }
+ failed = !importCollection(coll, action_);
+ }
+
+ StatusBar::self()->clearStatus();
+ return !failed; // return true means success
+}
+
+bool MainWindow::exportCollection(Export::Format format_, const KURL& url_) {
+ if(!url_.isValid()) {
+ myDebug() << "MainWindow::exportCollection() - invalid URL: " << url_.url() << endl;
+ return false;
+ }
+
+ GUI::CursorSaver cs;
+ const Data::CollPtr c = Data::Document::self()->collection();
+ if(!c) {
+ return false;
+ }
+
+ // only bibliographies can export to bibtex or bibtexml
+ bool isBibtex = (c->type() == Data::Collection::Bibtex);
+ if(!isBibtex && (format_ == Export::Bibtex || format_ == Export::Bibtexml)) {
+ return false;
+ }
+ // only books and bibliographies can export to alexandria
+ bool isBook = (c->type() == Data::Collection::Book);
+ if(!isBibtex && !isBook && format_ == Export::Alexandria) {
+ return false;
+ }
+
+ bool success = ExportDialog::exportCollection(format_, url_);
+ return success;
+}
+
+bool MainWindow::showEntry(long id) {
+ Data::EntryPtr entry = Data::Document::self()->collection()->entryById(id);
+ if(entry) {
+ m_viewStack->showEntry(entry);
+ }
+ return entry != 0;
+}
+
+void MainWindow::addFilterView() {
+ if(m_filterView) {
+ return;
+ }
+
+ m_filterView = new FilterView(m_viewTabs, "filterview");
+ Controller::self()->addObserver(m_filterView);
+ m_viewTabs->insertTab(m_filterView, SmallIcon(QString::fromLatin1("filter")), i18n("Filters"), 1);
+ QWhatsThis::add(m_filterView, i18n("<qt>The <i>Filter View</i> shows the entries which meet certain "
+ "filter rules.</qt>"));
+
+ int sortStyle = Config::filterViewSortColumn();
+ m_filterView->setSortStyle(static_cast<GUI::ListView::SortStyle>(sortStyle));
+ bool sortAscending = Config::filterViewSortAscending();
+ m_filterView->setSortOrder(sortAscending ? Qt::Ascending : Qt::Descending);
+}
+
+void MainWindow::addLoanView() {
+ if(m_loanView) {
+ return;
+ }
+
+ m_loanView = new LoanView(m_viewTabs, "loanview");
+ Controller::self()->addObserver(m_loanView);
+ m_viewTabs->insertTab(m_loanView, SmallIcon(QString::fromLatin1("kaddressbook")), i18n("Loans"), 2);
+ QWhatsThis::add(m_loanView, i18n("<qt>The <i>Loan View</i> shows a list of all the people who "
+ "have borrowed items from your collection.</qt>"));
+
+ int sortStyle = Config::loanViewSortColumn();
+ m_loanView->setSortStyle(static_cast<GUI::ListView::SortStyle>(sortStyle));
+ bool sortAscending = Config::loanViewSortAscending();
+ m_loanView->setSortOrder(sortAscending ? Qt::Ascending : Qt::Descending);
+}
+
+void MainWindow::updateCaption(bool modified_) {
+ QString caption;
+ if(Data::Document::self()->collection()) {
+ caption = Data::Document::self()->collection()->title();
+ }
+ if(!m_newDocument) {
+ if(!caption.isEmpty()) {
+ caption += QString::fromLatin1(" - ");
+ }
+ KURL u = Data::Document::self()->URL();
+ if(u.isLocalFile()) {
+ // for new files, the path is set to /Untitled in Data::Document
+ if(u.path() == '/' + i18n("Untitled")) {
+ caption += u.fileName();
+ } else {
+ caption += u.path();
+ }
+ } else {
+ caption += u.prettyURL();
+ }
+ }
+ setCaption(caption, modified_);
+}
+
+void MainWindow::slotUpdateToolbarIcons() {
+ // myDebug() << "MainWindow::slotUpdateToolbarIcons() " << endl;
+ // first change the icon for the menu item
+ m_newEntry->setIconSet(UserIconSet(Kernel::self()->collectionTypeName()));
+
+ // since the toolbar icon is probably a different size than the menu item icon
+ // superimpose it on the "mime_empty" icon
+ KToolBar* tb = toolBar("collectionToolBar");
+ if(!tb) {
+ return;
+ }
+
+ for(int i = 0; i < tb->count(); ++i) {
+ if(m_newEntry->isPlugged(tb, tb->idAt(i))) {
+ QIconSet icons;
+ icons.installIconFactory(new EntryIconFactory(tb->iconSize()));
+ tb->setButtonIconSet(tb->idAt(i), icons);
+ break;
+ }
+ }
+}
+
+void MainWindow::slotGroupLabelActivated() {
+ // need entry grouping combo id
+ KToolBar* tb = toolBar("collectionToolBar");
+ if(!tb) {
+ return;
+ }
+
+ for(int i = 0; i < tb->count(); ++i) {
+ if(m_entryGrouping->isPlugged(tb, tb->idAt(i))) {
+ KComboBox* combo = tb->getCombo(tb->idAt(i));
+ if(combo) {
+ combo->popup();
+ break;
+ }
+ }
+ }
+}
+
+void MainWindow::slotFilterLabelActivated() {
+ m_quickFilter->setFocus();
+ m_quickFilter->selectAll();
+}
+
+void MainWindow::slotClearFilter() {
+ m_quickFilter->clear();
+ slotQueueFilter();
+}
+
+void MainWindow::slotRenameCollection() {
+ Kernel::self()->renameCollection();
+}
+
+void MainWindow::updateCollectionActions() {
+ if(!Data::Document::self()->collection()) {
+ return;
+ }
+
+ stateChanged(QString::fromLatin1("collection_reset"));
+ Data::Collection::Type type = Data::Document::self()->collection()->type();
+ switch(type) {
+ case Data::Collection::Book:
+ stateChanged(QString::fromLatin1("is_book"));
+ break;
+ case Data::Collection::Bibtex:
+ stateChanged(QString::fromLatin1("is_bibliography"));
+ break;
+ case Data::Collection::Video:
+ stateChanged(QString::fromLatin1("is_video"));
+ break;
+ default:
+ break;
+ }
+ Controller::self()->updateActions();
+ // special case when there are no available data sources
+ if(m_fetchActions.isEmpty() && m_updateAll) {
+ m_updateAll->setEnabled(false);
+ }
+}
+
+void MainWindow::updateEntrySources() {
+ QSignalMapper* mapper = ::qt_cast<QSignalMapper*>(child("update_mapper"));
+ if(!mapper) {
+ kdWarning() << "MainWindow::updateEntrySources() - no update mapper!" << endl;
+ return;
+ }
+
+ unplugActionList(QString::fromLatin1("update_entry_actions"));
+ for(QPtrListIterator<KAction> it(m_fetchActions); it.current(); ++it) {
+ it.current()->unplugAll();
+ mapper->removeMappings(it.current());
+ }
+ // autoDelete() all actions, which removes them from the actionCollection()
+ m_fetchActions.clear();
+
+ Fetch::FetcherVec vec = Fetch::Manager::self()->fetchers(Kernel::self()->collectionType());
+ for(Fetch::FetcherVec::Iterator it = vec.begin(); it != vec.end(); ++it) {
+ KAction* action = new KAction(actionCollection());
+ action->setText(it->source());
+ action->setToolTip(i18n("Update entry data from %1").arg(it->source()));
+ action->setIconSet(Fetch::Manager::fetcherIcon(it.data()));
+ connect(action, SIGNAL(activated()), mapper, SLOT(map()));
+ mapper->setMapping(action, it->source());
+ m_fetchActions.append(action);
+ }
+
+ plugActionList(QString::fromLatin1("update_entry_actions"), m_fetchActions);
+}
+
+void MainWindow::importFile(Import::Format format_, const KURL::List& urls_) {
+ KURL::List urls = urls_;
+ // update as DropHandler and Importer classes are updated
+ if(urls_.count() > 1 &&
+ format_ != Import::Bibtex &&
+ format_ != Import::RIS &&
+ format_ != Import::PDF) {
+ KURL u = urls_.front();
+ QString url = u.isLocalFile() ? u.path() : u.prettyURL();
+ Kernel::self()->sorry(i18n("Tellico can only import one file of this type at a time. "
+ "Only %1 will be imported.").arg(url));
+ urls.clear();
+ urls = u;
+ }
+
+ ImportDialog dlg(format_, urls, this, "importdlg");
+ if(dlg.exec() != QDialog::Accepted) {
+ return;
+ }
+
+// if edit dialog is saved ok and if replacing, then the doc is saved ok
+ if(m_editDialog->queryModified() &&
+ (dlg.action() != Import::Replace || Data::Document::self()->saveModified())) {
+ GUI::CursorSaver cs(Qt::waitCursor);
+ Data::CollPtr coll = dlg.collection();
+ if(!coll) {
+ if(!dlg.statusMessage().isEmpty()) {
+ Kernel::self()->sorry(dlg.statusMessage());
+ }
+ return;
+ }
+ importCollection(coll, dlg.action());
+ }
+}
+
+bool MainWindow::importCollection(Data::CollPtr coll_, Import::Action action_) {
+ bool failed = false;
+ switch(action_) {
+ case Import::Append:
+ {
+ // only append if match, but special case importing books into bibliographies
+ Data::CollPtr c = Data::Document::self()->collection();
+ if(c->type() == coll_->type()
+ || (c->type() == Data::Collection::Bibtex && coll_->type() == Data::Collection::Book)) {
+ Kernel::self()->appendCollection(coll_);
+ slotEnableModifiedActions(true);
+ } else {
+ Kernel::self()->sorry(i18n(errorAppendType));
+ failed = true;
+ }
+ }
+ break;
+
+ case Import::Merge:
+ {
+ // only merge if match, but special case importing books into bibliographies
+ Data::CollPtr c = Data::Document::self()->collection();
+ if(c->type() == coll_->type()
+ || (c->type() == Data::Collection::Bibtex && coll_->type() == Data::Collection::Book)) {
+ Kernel::self()->mergeCollection(coll_);
+ slotEnableModifiedActions(true);
+ } else {
+ Kernel::self()->sorry(i18n(errorMergeType));
+ failed = true;
+ }
+ }
+ break;
+
+ default: // replace
+ Kernel::self()->replaceCollection(coll_);
+ m_fileOpenRecent->setCurrentItem(-1);
+ m_newDocument = true;
+ slotEnableOpenedActions();
+ slotEnableModifiedActions(false);
+ break;
+ }
+ return !failed;
+}
+
+void MainWindow::slotURLAction(const KURL& url_) {
+ Q_ASSERT(url_.protocol() == Latin1Literal("tc"));
+ QString actionName = url_.fileName();
+ KAction* action = this->action(actionName);
+ if(action) {
+ action->activate();
+ } else {
+ myWarning() << "MainWindow::slotURLAction() - unknown action: " << actionName << endl;
+ }
+}
+
+#include "mainwindow.moc"