File indexing completed on 2024-04-28 05:08:24

0001 /***************************************************************************
0002     Copyright (C) 2001-2018 Robby Stephenson <robby@periapsis.org>
0003  ***************************************************************************/
0004 
0005 /***************************************************************************
0006  *                                                                         *
0007  *   This program is free software; you can redistribute it and/or         *
0008  *   modify it under the terms of the GNU General Public License as        *
0009  *   published by the Free Software Foundation; either version 2 of        *
0010  *   the License or (at your option) version 3 or any later version        *
0011  *   accepted by the membership of KDE e.V. (or its successor approved     *
0012  *   by the membership of KDE e.V.), which shall act as a proxy            *
0013  *   defined in Section 14 of version 3 of the license.                    *
0014  *                                                                         *
0015  *   This program is distributed in the hope that it will be useful,       *
0016  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0017  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0018  *   GNU General Public License for more details.                          *
0019  *                                                                         *
0020  *   You should have received a copy of the GNU General Public License     *
0021  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
0022  *                                                                         *
0023  ***************************************************************************/
0024 
0025 #include <config.h>
0026 
0027 #include "mainwindow.h"
0028 #include "core/logger.h"
0029 #include "translators/translators.h" // needed for file type enum
0030 #include "tellico_debug.h"
0031 
0032 #include <KAboutData>
0033 #include <KLocalizedString>
0034 #include <KCrash>
0035 #include <KSharedConfig>
0036 #include <Kdelibs4ConfigMigrator>
0037 #include <Kdelibs4Migration>
0038 
0039 #include <QApplication>
0040 #include <QCommandLineParser>
0041 #include <QCommandLineOption>
0042 #include <QDir>
0043 #include <QFile>
0044 #include <QStack>
0045 #include <QDebug>
0046 
0047 int main(int argc, char* argv[]) {
0048   QApplication app(argc, argv);
0049   QGuiApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
0050   KLocalizedString::setApplicationDomain("tellico");
0051   app.setApplicationVersion(QStringLiteral(TELLICO_VERSION));
0052 
0053   Q_INIT_RESOURCE(icons);
0054 
0055   // Migrate KDE4 configuration and data files
0056   Kdelibs4ConfigMigrator migrator(QStringLiteral("tellico"));
0057   migrator.setConfigFiles(QStringList() << QStringLiteral("tellicorc"));
0058   migrator.setUiFiles(QStringList() << QStringLiteral("tellicoui.rc"));
0059 
0060   if(migrator.migrate()) {
0061     // migrate old data
0062     typedef QPair<QString, QString> StringPair;
0063     QList<StringPair> filesToCopy;
0064     QList<QString> dirsToCreate;
0065 
0066     Kdelibs4Migration dataMigrator;
0067     const QString sourceBasePath = dataMigrator.saveLocation("data", QStringLiteral("tellico"));
0068     const QString targetBasePath = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + QLatin1Char('/');
0069     QString sourceFilePath, targetFilePath;
0070 
0071     // first copy tellico-common.xsl if exists
0072     QString fileName = QStringLiteral("tellico-common.xsl");
0073     sourceFilePath = sourceBasePath + QLatin1Char('/') + fileName;
0074     targetFilePath = targetBasePath + QLatin1Char('/') + fileName;
0075     if(QFile::exists(sourceFilePath) && !QFile::exists(targetFilePath)) {
0076       filesToCopy << qMakePair(sourceFilePath, targetFilePath);
0077     }
0078 
0079     // then migrate data directories
0080     QStack<QString> dirsToCheck;
0081     dirsToCheck.push(QStringLiteral("report-templates"));
0082     dirsToCheck.push(QStringLiteral("entry-templates"));
0083     dirsToCheck.push(QStringLiteral("data-sources"));
0084     // this will copy all the images shared between collections
0085     dirsToCheck.push(QStringLiteral("data"));
0086     while(!dirsToCheck.isEmpty()) {
0087       QString dataDir = dirsToCheck.pop();
0088       QDir sourceDir(sourceBasePath + dataDir);
0089       if(sourceDir.exists()) {
0090         if(!QDir().exists(targetBasePath + dataDir)) {
0091           dirsToCreate << (targetBasePath + dataDir);
0092         }
0093         // grab the internal directories, so we can be recursive
0094         QStringList moreDirs = sourceDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
0095         foreach(const QString& moreDir, moreDirs) {
0096           dirsToCheck.push(dataDir + QLatin1Char('/') + moreDir);
0097         }
0098         QStringList fileNames = sourceDir.entryList(QDir::Files | QDir::NoDotAndDotDot | QDir::NoSymLinks);
0099         foreach(const QString& fileName, fileNames) {
0100           sourceFilePath = sourceBasePath + dataDir + QLatin1Char('/') + fileName;
0101           targetFilePath = targetBasePath + dataDir + QLatin1Char('/') + fileName;
0102           if(!QFile::exists(targetFilePath)) {
0103             filesToCopy << qMakePair(sourceFilePath, targetFilePath);
0104           }
0105         }
0106       }
0107     }
0108 
0109     foreach(const QString& dir, dirsToCreate) {
0110       QDir().mkpath(dir);
0111     }
0112     foreach(const StringPair& pair, filesToCopy) {
0113       QFile::copy(pair.first, pair.second);
0114     }
0115 
0116     // update the configuration cache
0117     KSharedConfig::openConfig()->reparseConfiguration();
0118   }
0119 
0120   KCrash::initialize();
0121 
0122   // component name = "tellico" is same as bugs.kde.org product name
0123   KAboutData aboutData(QStringLiteral("tellico"), QStringLiteral("Tellico"),
0124                        QStringLiteral(TELLICO_VERSION), i18n("Tellico - collection management software, free and simple"),
0125                        KAboutLicense::GPL_V2,
0126                        i18n("(c) 2001-2023, Robby Stephenson"),
0127                        QString(),
0128                        QStringLiteral("https://tellico-project.org"));
0129   aboutData.addAuthor(QStringLiteral("Robby Stephenson"), QString(), QStringLiteral("robby@periapsis.org"));
0130   aboutData.addAuthor(QStringLiteral("Mathias Monnerville"), i18n("Data source scripts"));
0131   aboutData.addAuthor(QStringLiteral("Regis Boudin"), QString(), QStringLiteral("regis@boudin.name"));
0132   aboutData.addAuthor(QStringLiteral("Petri Damstén"), QString(), QStringLiteral("damu@iki.fi"));
0133   aboutData.addAuthor(QStringLiteral("Sebastian Held"), QString());
0134 
0135   aboutData.addCredit(QStringLiteral("Virginie Quesnay"), i18n("Icons"));
0136   aboutData.addCredit(QStringLiteral("Amarok"), i18n("Code examples and general inspiration"),
0137                       QString(), QStringLiteral("https://amarok.kde.org"));
0138   aboutData.addCredit(QStringLiteral("Greg Ward"), i18n("Author of btparse library"));
0139   aboutData.addCredit(QStringLiteral("Robert Gamble"), i18n("Author of libcsv library"));
0140   aboutData.addCredit(QStringLiteral("Valentin Lavrinenko"), i18n("Author of rtf2html library"));
0141 
0142   aboutData.addLicense(KAboutLicense::GPL_V3);
0143   aboutData.setOrganizationDomain("kde.org");
0144   aboutData.setDesktopFileName(QStringLiteral("org.kde.tellico.desktop"));
0145 
0146   QCommandLineParser parser;
0147   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("nofile"), i18n("Do not reopen the last open file")));
0148   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("bibtex"), i18n("Import <filename> as a bibtex file")));
0149   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("mods"), i18n("Import <filename> as a MODS file")));
0150   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("ris"), i18n("Import <filename> as a RIS file")));
0151   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("pdf"), i18n("Import <filename> as a PDF file")));
0152   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("log"), i18n("Log diagnostic output")));
0153   parser.addOption(QCommandLineOption(QStringList() << QStringLiteral("logfile"), i18n("Write log output to <filename>"), QStringLiteral("logfile")));
0154   parser.addPositionalArgument(QStringLiteral("[filename]"), i18n("File to open"));
0155 
0156   aboutData.setupCommandLine(&parser);
0157 
0158   parser.process(app);
0159   aboutData.processCommandLine(&parser);
0160   KAboutData::setApplicationData(aboutData);
0161 
0162 #ifndef NDEBUG
0163   QLoggingCategory::setFilterRules(QStringLiteral("tellico.debug = true"));
0164 #endif
0165   // initialize logger
0166   Tellico::Logger::self();
0167   QString logFile = qEnvironmentVariable("TELLICO_LOGFILE");
0168   if(parser.isSet(QStringLiteral("logfile"))) {
0169     logFile = parser.value(QStringLiteral("logfile"));
0170   }
0171   if(logFile.isEmpty() && parser.isSet(QStringLiteral("log"))) {
0172     // use default log file location
0173     logFile = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/tellico_log.txt");
0174   }
0175   if(!logFile.isEmpty()) {
0176     Tellico::Logger::self()->setLogFile(logFile);
0177     myLog() << "Starting Tellico" << QStringLiteral(TELLICO_VERSION) << "at" << QDateTime::currentDateTime().toString(Qt::ISODate);
0178     myLog() << "Opening log file" << logFile;
0179   }
0180 
0181   if(app.isSessionRestored()) {
0182     myLog() << "Restoring previous session";
0183     RESTORE(Tellico::MainWindow);
0184   } else {
0185     Tellico::MainWindow* tellico = new Tellico::MainWindow();
0186     tellico->show();
0187     // slotInit gets called out of a QTimer signal
0188     // but it wasn't always completing in-time
0189     // so call it manually to ensure it has finished
0190     tellico->slotInit();
0191 
0192     QStringList args = parser.positionalArguments();
0193     if(args.count() > 0) {
0194       QLatin1String formatStr;
0195       Tellico::Import::Format format = Tellico::Import::TellicoXML;
0196       if(parser.isSet(QStringLiteral("bibtex"))) {
0197         format = Tellico::Import::Bibtex;
0198         formatStr = QLatin1String("bibtex");
0199       } else if(parser.isSet(QStringLiteral("mods"))) {
0200         format = Tellico::Import::MODS;
0201         formatStr = QLatin1String("mods");
0202       } else if(parser.isSet(QStringLiteral("ris"))) {
0203         format = Tellico::Import::RIS;
0204         formatStr = QLatin1String("ris");
0205       } else if(parser.isSet(QStringLiteral("pdf"))) {
0206         format = Tellico::Import::PDF;
0207         formatStr = QLatin1String("pdf");
0208       };
0209       const QUrl fileToLoad = QUrl::fromUserInput(args.at(0), QDir::currentPath());
0210       if(format == Tellico::Import::TellicoXML) {
0211         myLog() << "Opening" << fileToLoad.toDisplayString(QUrl::PreferLocalFile);
0212         tellico->slotFileOpen(fileToLoad);
0213       } else {
0214         myLog() << "Importing" << formatStr << "-" << fileToLoad.toDisplayString(QUrl::PreferLocalFile);
0215         tellico->importFile(format, fileToLoad, Tellico::Import::Replace);
0216         for(int i = 1; i < args.count(); ++i) {
0217           myLog() << "Appending" << fileToLoad.toDisplayString(QUrl::PreferLocalFile);
0218           tellico->importFile(format, fileToLoad, Tellico::Import::Append);
0219         }
0220       }
0221     } else {
0222       // bit of a hack, I just want the --nofile option
0223       // if --nofile is NOT passed, then the file option is set
0224       // is it's set, then go ahead and check for opening previous file
0225       tellico->initFileOpen(parser.isSet(QStringLiteral("nofile")));
0226     }
0227   }
0228 
0229   return app.exec();
0230 }