/* Copyright 2012-2013 Adam Reichold Copyright 2014 Dorian Scholz Copyright 2012 MichaƂ Trybus Copyright 2013 Chris Young This file is part of qpdfview. qpdfview is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. qpdfview is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with qpdfview. If not, see . */ #include #include #include #include #include #include #include #include #include #ifdef WITH_DBUS #include #include #endif // WITH_DBUS #ifdef WITH_SYNCTEX #include #endif // WITH_SYNCTEX #include "renderparam.h" #include "documentview.h" #include "database.h" #include "mainwindow.h" #ifdef WITH_SIGNALS #include "signalhandler.h" #endif // WITH_SIGNALS #ifdef __amigaos4__ #include #include const char* __attribute__((used)) stack_cookie = "\0$STACK:500000\0"; #endif // __amigaos4__ namespace { using namespace qpdfview; struct File { QString filePath; int page; QString sourceName; int sourceLine; int sourceColumn; QRectF enclosingBox; File() : filePath(), page(-1), sourceName(), sourceLine(-1), sourceColumn(-1), enclosingBox() {} }; enum ExitStatus { ExitOk = 0, ExitUnknownArgument = 1, ExitIllegalArgument = 2, ExitInconsistentArguments = 3, ExitDBusError = 4 }; bool unique = false; bool quiet = false; QString instanceName; QString searchText; QList< File > files; MainWindow* mainWindow = 0; void loadTranslators() { QTranslator* toolkitTranslator = new QTranslator(qApp); QTranslator* applicationTranslator = new QTranslator(qApp); #if QT_VERSION >= QT_VERSION_CHECK(4,8,0) if(toolkitTranslator->load(QLocale::system(), "qt", "_", QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { qApp->installTranslator(toolkitTranslator); } if(applicationTranslator->load(QLocale::system(), "qpdfview", "_", QDir(QApplication::applicationDirPath()).filePath("data"))) { qApp->installTranslator(applicationTranslator); } else if(applicationTranslator->load(QLocale::system(), "qpdfview", "_", DATA_INSTALL_PATH)) { qApp->installTranslator(applicationTranslator); } //if(applicationTranslator->load(QLocale::system(), "TibisayPDFView", "_", QDir(QApplication::applicationDirPath()).filePath("data"))) { qApp->installTranslator(applicationTranslator); } //else if(applicationTranslator->load(QLocale::system(), "TibisayPDFView", "_", DATA_INSTALL_PATH)) { qApp->installTranslator(applicationTranslator); } #else if(toolkitTranslator->load("qt_" + QLocale::system().name(), QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { qApp->installTranslator(toolkitTranslator); } if(applicationTranslator->load("terepaima" + QLocale::system().name(), QDir(QApplication::applicationDirPath()).filePath("data"))) { qApp->installTranslator(applicationTranslator); } else if(applicationTranslator->load("terepaima" + QLocale::system().name(), DATA_INSTALL_PATH)) { qApp->installTranslator(applicationTranslator); } // if(applicationTranslator->load("TibisayPDFView_" + QLocale::system().name(), QDir(QApplication::applicationDirPath()).filePath("data"))) { qApp->installTranslator(applicationTranslator); } // else if(applicationTranslator->load("TibisayPDFView_" + QLocale::system().name(), DATA_INSTALL_PATH)) { qApp->installTranslator(applicationTranslator); } #endif // QT_VERSION } void parseCommandLineArguments() { bool instanceNameIsNext = false; bool searchTextIsNext = false; bool noMoreOptions = false; QRegExp fileAndPageRegExp("(.+)#(\\d+)"); QRegExp fileAndSourceRegExp("(.+)#src:(.+):(\\d+):(\\d+)"); QRegExp instanceNameRegExp("[A-Za-z_]+[A-Za-z0-9_]*"); QStringList arguments = QApplication::arguments(); if(!arguments.isEmpty()) { arguments.removeFirst(); } foreach(const QString& argument, arguments) { if(instanceNameIsNext) { if(argument.isEmpty()) { qCritical() << QObject::tr("An empty instance name is not allowed."); exit(ExitIllegalArgument); } instanceNameIsNext = false; instanceName = argument; } else if(searchTextIsNext) { if(argument.isEmpty()) { qCritical() << QObject::tr("An empty search text is not allowed."); exit(ExitIllegalArgument); } searchTextIsNext = false; searchText = argument; } else if(!noMoreOptions && argument.startsWith("--")) { if(argument == QLatin1String("--unique")) { unique = true; } else if(argument == QLatin1String("--quiet")) { quiet = true; } else if(argument == QLatin1String("--instance")) { instanceNameIsNext = true; } else if(argument == QLatin1String("--search")) { searchTextIsNext = true; } else if(argument == QLatin1String("--choose-instance")) { bool ok = false; const QString chosenInstanceName = QInputDialog::getItem(0, QObject::tr("Choose instance"), QObject::tr("Instance:"), Database::instance()->loadInstanceNames(), 0, true, &ok); if(ok) { instanceName = chosenInstanceName; } } else if(argument == QLatin1String("--help")) { std::cout << "Usage: qpdfview [options] [--] [file[#page]] [file[#src:name:line:column]] ..." << std::endl << std::endl << "Available options:" << std::endl << " --help Show this information" << std::endl << " --quiet Suppress warning messages when opening files" << std::endl << " --search text Search for text in the current tab" << std::endl << " --unique Open files as tabs in unique window" << std::endl << " --unique --instance name Open files as tabs in named instance" << std::endl << " --unique --choose-instance Open files as tabs after choosing an instance name" << std::endl << std::endl << "Please report bugs at \"https://launchpad.net/qpdfview\"." << std::endl; exit(ExitOk); } else if(argument == QLatin1String("--")) { noMoreOptions = true; } else { qCritical() << QObject::tr("Unknown command-line option '%1'.").arg(argument); exit(ExitUnknownArgument); } } else { File file; if(fileAndPageRegExp.exactMatch(argument)) { file.filePath = fileAndPageRegExp.cap(1); file.page = fileAndPageRegExp.cap(2).toInt(); } else if(fileAndSourceRegExp.exactMatch(argument)) { file.filePath = fileAndSourceRegExp.cap(1); file.sourceName = fileAndSourceRegExp.cap(2); file.sourceLine = fileAndSourceRegExp.cap(3).toInt(); file.sourceColumn = fileAndSourceRegExp.cap(4).toInt(); } else { file.filePath = argument; } files.append(file); } } if(instanceNameIsNext) { qCritical() << QObject::tr("Using '--instance' requires an instance name."); exit(ExitInconsistentArguments); } if(!unique && !instanceName.isEmpty()) { qCritical() << QObject::tr("Using '--instance' is not allowed without using '--unique'."); exit(ExitInconsistentArguments); } if(!instanceName.isEmpty() && !instanceNameRegExp.exactMatch(instanceName)) { qCritical() << QObject::tr("An instance name must only contain the characters \"[A-Z][a-z][0-9]_\" and must not begin with a digit."); exit(ExitIllegalArgument); } if(searchTextIsNext) { qCritical() << QObject::tr("Using '--search' requires a search text."); exit(ExitInconsistentArguments); } } void parseWorkbenchExtendedSelection(int argc, char** argv) { #ifdef __amigaos4__ if(argc == 0) { const int pathLength = 1024; const QScopedArrayPointer< char > filePath(new char[pathLength]); const struct WBStartup* wbStartup = reinterpret_cast< struct WBStartup* >(argv); for(int index = 1; index < wbStartup->sm_NumArgs; ++index) { const struct WBArg* wbArg = wbStartup->sm_ArgList + index; if((wbArg->wa_Lock) && (*wbArg->wa_Name)) { IDOS->DevNameFromLock(wbArg->wa_Lock, filePath.data(), pathLength, DN_FULLPATH); IDOS->AddPart(filePath.data(), wbArg->wa_Name, pathLength); File file; file.filePath = filePath.data(); files.append(file); } } } #else Q_UNUSED(argc); Q_UNUSED(argv); #endif // __amigaos4__ } void resolveSourceReferences() { #ifdef WITH_SYNCTEX for(int index = 0; index < files.count(); ++index) { File& file = files[index]; if(!file.sourceName.isNull()) { synctex_scanner_t scanner = synctex_scanner_new_with_output_file(file.filePath.toLocal8Bit(), 0, 1); if(scanner != 0) { if(synctex_display_query(scanner, file.sourceName.toLocal8Bit(), file.sourceLine, file.sourceColumn) > 0) { for(synctex_node_t node = synctex_next_result(scanner); node != 0; node = synctex_next_result(scanner)) { int page = synctex_node_page(node); QRectF enclosingBox(synctex_node_box_visible_h(node), synctex_node_box_visible_v(node), synctex_node_box_visible_width(node), synctex_node_box_visible_height(node)); if(file.page != page) { file.page = page; file.enclosingBox = enclosingBox; } else { file.enclosingBox = file.enclosingBox.united(enclosingBox); } } } synctex_scanner_free(scanner); } else { qWarning() << QObject::tr("SyncTeX data for '%1' could not be found.").arg(file.filePath); } } } #endif // WITH_SYNCTEX } void activateUniqueInstance() { qApp->setObjectName(instanceName); #ifdef WITH_DBUS if(unique) { QString serviceName = QApplication::organizationDomain(); if(!instanceName.isEmpty()) { serviceName.append('.'); serviceName.append(instanceName); } QScopedPointer< QDBusInterface > interface(new QDBusInterface(serviceName, "/MainWindow", "local.qpdfview.MainWindow", QDBusConnection::sessionBus())); if(interface->isValid()) { interface->call("raiseAndActivate"); foreach(const File& file, files) { QDBusReply< bool > reply = interface->call("jumpToPageOrOpenInNewTab", QFileInfo(file.filePath).absoluteFilePath(), file.page, true, file.enclosingBox, quiet); if(!reply.isValid()) { qCritical() << QDBusConnection::sessionBus().lastError().message(); exit(ExitDBusError); } } if(!searchText.isEmpty()) { interface->call("startSearch", searchText); } exit(ExitOk); } else { mainWindow = new MainWindow(); new MainWindowAdaptor(mainWindow); if(!QDBusConnection::sessionBus().registerService(serviceName)) { qCritical() << QDBusConnection::sessionBus().lastError().message(); delete mainWindow; exit(ExitDBusError); } if(!QDBusConnection::sessionBus().registerObject("/MainWindow", mainWindow)) { qCritical() << QDBusConnection::sessionBus().lastError().message(); delete mainWindow; exit(ExitDBusError); } } return; } else { mainWindow = new MainWindow(); } #else mainWindow = new MainWindow(); #endif // WITH_DBUS } void prepareSignalHandler() { #ifdef WITH_SIGNALS if(SignalHandler::prepareSignals()) { SignalHandler* signalHandler = new SignalHandler(mainWindow); QObject::connect(signalHandler, SIGNAL(sigIntReceived()), mainWindow, SLOT(close())); QObject::connect(signalHandler, SIGNAL(sigTermReceived()), mainWindow, SLOT(close())); } else { qWarning() << QObject::tr("Could not prepare signal handler."); } #endif // WITH_SIGNALS } } // anonymous int main(int argc, char** argv) { qRegisterMetaType< QList< QRectF > >("QList"); qRegisterMetaType< Rotation >("Rotation"); qRegisterMetaType< RenderParam >("RenderParam"); parseWorkbenchExtendedSelection(argc, argv); QApplication application(argc, argv); QApplication::setOrganizationDomain("local.terepaima"); // QApplication::setOrganizationDomain("local.qpdfview"); // QApplication::setOrganizationName("qpdfview"); // QApplication::setApplicationName("qpdfview"); QApplication::setOrganizationName("terepaima"); QApplication::setApplicationName("terepaima"); QApplication::setApplicationVersion(APPLICATION_VERSION); QApplication::setWindowIcon(QIcon(":icons/qpdfview.svg")); loadTranslators(); parseCommandLineArguments(); resolveSourceReferences(); activateUniqueInstance(); prepareSignalHandler(); mainWindow->show(); mainWindow->setAttribute(Qt::WA_DeleteOnClose); foreach(const File& file, files) { mainWindow->jumpToPageOrOpenInNewTab(file.filePath, file.page, true, file.enclosingBox, quiet); } if(!searchText.isEmpty()) { mainWindow->startSearch(searchText); } return application.exec(); }