diff --git a/app/main.cpp b/app/main.cpp index e4765f3c89..e02c2c4875 100644 --- a/app/main.cpp +++ b/app/main.cpp @@ -1,849 +1,852 @@ /*************************************************************************** * Copyright 2003-2009 Alexander Dymo * * Copyright 2007 Ralf Habacker * * Copyright 2006-2007 Matt Rogers * * Copyright 2006-2007 Hamish Rodda * * Copyright 2005-2007 Adam Treat * * Copyright 2003-2007 Jens Dagerbo * * Copyright 2001-2002 Bernd Gehrmann * * Copyright 2001-2002 Matthias Hoelzer-Kluepfel * * Copyright 2003 Roberto Raggi * * Copyright 2010 Niko Sams * * Copyright 2015 Kevin Funk * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU Library General Public License as * * published by the Free Software Foundation; either version 2 of the * * License, or (at your option) any later version. * * * * This program 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 Library General Public * * License along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include "config-kdevelop.h" #include "kdevelop_version.h" #include "urlinfo.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kdevideextension.h" #if KDEVELOP_SINGLE_APP #include "qtsingleapplication.h" #endif #include #ifdef Q_OS_MAC #include #endif using namespace KDevelop; namespace { #if KDEVELOP_SINGLE_APP QString serializeOpenFilesMessage(const QVector &infos) { QByteArray message; QDataStream stream(&message, QIODevice::WriteOnly); stream << QByteArrayLiteral("open"); stream << infos; return QString::fromLatin1(message.toHex()); } #endif void openFiles(const QVector& infos) { for (const UrlInfo& info : infos) { if (!ICore::self()->documentController()->openDocument(info.url, info.cursor)) { qWarning(APP) << i18n("Could not open %1", info.url.toDisplayString(QUrl::PreferLocalFile)); } } } } class KDevelopApplication: #if KDEVELOP_SINGLE_APP public SharedTools::QtSingleApplication #else public QApplication #endif { + Q_OBJECT public: explicit KDevelopApplication(int &argc, char **argv, bool GUIenabled = true) #if KDEVELOP_SINGLE_APP : SharedTools::QtSingleApplication(QStringLiteral("KDevelop"), argc, argv) #else : QApplication(argc, argv, GUIenabled) #endif { Q_UNUSED(GUIenabled); connect(this, &QGuiApplication::saveStateRequest, this, &KDevelopApplication::saveState); } #if KDEVELOP_SINGLE_APP public Q_SLOTS: void remoteArguments(const QString &message, QObject *socket) { Q_UNUSED(socket); QByteArray ba = QByteArray::fromHex(message.toLatin1()); QDataStream stream(ba); QByteArray command; stream >> command; qCDebug(APP) << "Received remote command: " << command; if (command == "open") { QVector infos; stream >> infos; QVector files, directories; for (const auto& info : infos) if (info.isDirectory()) directories << info; else files << info; openFiles(files); for(const auto &urlinfo : directories) ICore::self()->projectController()->openProjectForUrl(urlinfo.url); } else { qCWarning(APP) << "Unknown remote command: " << command; } } void fileOpenRequested(const QString &file) { openFiles({UrlInfo(file)}); } #endif private Q_SLOTS: void saveState( QSessionManager& sm ) { if (KDevelop::Core::self() && KDevelop::Core::self()->sessionController()) { const auto activeSession = KDevelop::Core::self()->sessionController()->activeSession(); if (!activeSession) { qWarning(APP) << "No active session, can't save state"; return; } const QString x11SessionId = sm.sessionId() + QLatin1Char('_') + sm.sessionKey(); QString kdevelopSessionId = activeSession->id().toString(); sm.setRestartCommand({ QCoreApplication::applicationFilePath(), QStringLiteral("-session"), x11SessionId, QStringLiteral("-s"), kdevelopSessionId }); } } }; /// Tries to find a session identified by @p data in @p sessions. /// The @p data may be either a session's name or a string-representation of its UUID. /// @return pointer to the session or NULL if nothing appropriate has been found static const KDevelop::SessionInfo* findSessionInList( const SessionInfos& sessions, const QString& data ) { // We won't search a session without input data, since that could lead to false-positives // with unnamed sessions if( data.isEmpty() ) return nullptr; for( auto it = sessions.constBegin(); it != sessions.constEnd(); ++it ) { if ( ( it->name == data ) || ( it->uuid.toString() == data ) ) { const KDevelop::SessionInfo& sessionRef = *it; return &sessionRef; } } return nullptr; } /// Tries to find sessions containing project @p projectUrl in @p sessions. static const KDevelop::SessionInfos findSessionsWithProject(const SessionInfos& sessions, const QUrl& projectUrl) { if (!projectUrl.isValid()) return {}; KDevelop::SessionInfos infos; for (auto it = sessions.constBegin(); it != sessions.constEnd(); ++it) { if (it->projects.contains(projectUrl)) { infos << *it; } } return infos; } /// Performs a DBus call to open the given @p files in the running kdev instance identified by @p pid /// Returns the exit status static int openFilesInRunningInstance(const QVector& files, qint64 pid) { const QString service = QStringLiteral("org.kdevelop.kdevelop-%1").arg(pid); QDBusInterface iface(service, QStringLiteral("/org/kdevelop/DocumentController"), QStringLiteral("org.kdevelop.DocumentController")); QStringList urls; bool errors_occured = false; for (const UrlInfo& file : files) { QDBusReply result = iface.call(QStringLiteral("openDocumentSimple"), file.url.toString(), file.cursor.line(), file.cursor.column()); if ( ! result.value() ) { QTextStream err(stderr); err << i18n("Could not open file '%1'.", file.url.toDisplayString(QUrl::PreferLocalFile)) << "\n"; errors_occured = true; } } // make the window visible QDBusMessage makeVisible = QDBusMessage::createMethodCall( service, QStringLiteral("/kdevelop/MainWindow"), QStringLiteral("org.kdevelop.MainWindow"), QStringLiteral("ensureVisible") ); QDBusConnection::sessionBus().asyncCall( makeVisible ); return errors_occured; } /// Performs a DBus call to open the given @p files in the running kdev instance identified by @p pid /// Returns the exit status static int openProjectInRunningInstance(const QVector& paths, qint64 pid) { const QString service = QStringLiteral("org.kdevelop.kdevelop-%1").arg(pid); QDBusInterface iface(service, QStringLiteral("/org/kdevelop/ProjectController"), QStringLiteral("org.kdevelop.ProjectController")); int errors = 0; for (const UrlInfo& path : paths) { QDBusReply result = iface.call(QStringLiteral("openProjectForUrl"), path.url.toString()); if ( !result.isValid() ) { QTextStream err(stderr); err << i18n("Could not open project '%1': %2", path.url.toDisplayString(QUrl::PreferLocalFile), result.error().message()) << "\n"; ++errors; } } // make the window visible QDBusMessage makeVisible = QDBusMessage::createMethodCall( service, QStringLiteral("/kdevelop/MainWindow"), QStringLiteral("org.kdevelop.MainWindow"), QStringLiteral("ensureVisible") ); QDBusConnection::sessionBus().asyncCall( makeVisible ); return errors; } /// Gets the PID of a running KDevelop instance, eventually asking the user if there is more than one. /// Returns -1 in case there are no running sessions. static qint64 getRunningSessionPid() { SessionInfos candidates; foreach( const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos() ) { if( KDevelop::SessionController::isSessionRunning(si.uuid.toString()) ) { candidates << si; } } if ( candidates.isEmpty() ) { return -1; } QString sessionUuid; if ( candidates.size() == 1 ) { sessionUuid = candidates.first().uuid.toString(); } else { const QString title = i18n("Select the session to open the document in"); sessionUuid = KDevelop::SessionController::showSessionChooserDialog(title, true); } return KDevelop::SessionController::sessionRunInfo(sessionUuid).holderPid; } static QString findSessionId(const SessionInfos& availableSessionInfos, const QString& session) { //If there is a session and a project with the same name, always open the session //regardless of the order encountered QString projectAsSession; for (const KDevelop::SessionInfo& si : availableSessionInfos) { if ( session == si.name || session == si.uuid.toString() ) { return si.uuid.toString(); } else if (projectAsSession.isEmpty()) { foreach(const QUrl& k, si.projects) { QString fn(k.fileName()); fn = fn.left(fn.indexOf(QLatin1Char('.'))); if ( session == fn ) { projectAsSession = si.uuid.toString(); } } } } if (projectAsSession.isEmpty()) { QTextStream qerr(stderr); qerr << endl << i18n("Cannot open unknown session %1. See `--list-sessions` switch for available sessions or use `-n` to create a new one.", session) << endl; } return projectAsSession; } static qint64 findSessionPid(const QString &sessionId) { KDevelop::SessionRunInfo sessionInfo = KDevelop::SessionController::sessionRunInfo( sessionId ); return sessionInfo.holderPid; } int main( int argc, char *argv[] ) { QElapsedTimer timer; timer.start(); #if QT_VERSION >= QT_VERSION_CHECK(5, 8, 0) // If possible, use the Software backend for QQuickWidget (currently used in the // welcome page plugin). This means we don't need OpenGL at all, avoiding issues // like https://bugs.kde.org/show_bug.cgi?id=386527. QQuickWindow::setSceneGraphBackend(QSGRendererInterface::Software); #endif // TODO: Maybe generalize, add KDEVELOP_STANDALONE build option #if defined(Q_OS_WIN) || defined(Q_OS_MAC) qputenv("KDE_FORK_SLAVES", "1"); // KIO slaves will be forked off instead of being started via DBus #endif // Useful for valgrind runs, just `export KDEV_DISABLE_JIT=1` if (qEnvironmentVariableIsSet("KDEV_DISABLE_JIT")) { qputenv("KDEV_DISABLE_WELCOMEPAGE", "1"); qputenv("QT_ENABLE_REGEXP_JIT", "0"); } #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QCoreApplication::setAttribute(Qt::AA_DontCreateNativeWidgetSiblings); #ifdef Q_OS_MAC CFBundleRef mainBundle = CFBundleGetMainBundle(); if (mainBundle) { // get the application's Info Dictionary. For app bundles this would live in the bundle's Info.plist, // for regular executables it is obtained in another way. CFMutableDictionaryRef infoDict = (CFMutableDictionaryRef) CFBundleGetInfoDictionary(mainBundle); if (infoDict) { // Try to prevent App Nap on OS X. This can be tricky in practice, at least in 10.9 . CFDictionarySetValue(infoDict, CFSTR("NSAppSleepDisabled"), kCFBooleanTrue); CFDictionarySetValue(infoDict, CFSTR("NSSupportsAutomaticTermination"), kCFBooleanFalse); } } #endif //we can't use KCmdLineArgs as it doesn't allow arguments for the debugee //so lookup the --debug switch and eat everything behind by decrementing argc //debugArgs is filled with args after --debug QStringList debugArgs; QString debugeeName; { bool debugFound = false; int c = argc; for (int i=0; i < c; ++i) { if (debugFound) { debugArgs << QString::fromUtf8(argv[i]); } else if ((qstrcmp(argv[i], "--debug") == 0) || (qstrcmp(argv[i], "-d") == 0)) { if (argc > (i + 1)) { i++; } argc = i + 1; debugFound = true; } else if (QByteArray(argv[i]).startsWith("--debug=")) { argc = i + 1; debugFound = true; } } } KDevelopApplication app(argc, argv); KLocalizedString::setApplicationDomain("kdevelop"); KAboutData aboutData( QStringLiteral("kdevelop"), i18n("KDevelop"), QStringLiteral(KDEVELOP_VERSION_STRING), i18n("The KDevelop Integrated Development Environment"), KAboutLicense::GPL, i18n("Copyright 1999-2018, The KDevelop developers"), QString(), QStringLiteral("https://www.kdevelop.org/")); aboutData.setDesktopFileName(QStringLiteral("org.kde.kdevelop")); aboutData.addAuthor( i18n("Kevin Funk"), i18n( "Co-maintainer, C++/Clang, QA, Windows Support" ), QStringLiteral("kfunk@kde.org") ); aboutData.addAuthor( i18n("Sven Brauch"), i18n( "Co-maintainer, AppImage, Python Support, User Interface improvements" ), QStringLiteral("svenbrauch@gmail.com") ); aboutData.addAuthor( i18n("Aleix Pol Gonzalez"), i18n( "CMake Support, Run Support, Kross Support" ), QStringLiteral("aleixpol@gmail.com") ); aboutData.addAuthor( i18n("Milian Wolff"), i18n( "C++/Clang, Generic manager, Webdevelopment Plugins, Snippets, Performance" ), QStringLiteral("mail@milianw.de") ); aboutData.addAuthor( i18n("Olivier JG"), i18n( "C++/Clang, DUChain, Bug Fixes" ), QStringLiteral("olivier.jg@gmail.com") ); aboutData.addAuthor( i18n("Andreas Pakulat"), i18n( "Architecture, VCS Support, Project Management Support, QMake Projectmanager" ), QStringLiteral("apaku@gmx.de") ); aboutData.addAuthor( i18n("Alexander Dymo"), i18n( "Architecture, Sublime UI, Ruby support" ), QStringLiteral("adymo@kdevelop.org") ); aboutData.addAuthor( i18n("David Nolden"), i18n( "Definition-Use Chain, C++ Support, Code Navigation, Code Completion, Coding Assistance, Refactoring" ), QStringLiteral("david.nolden.kdevelop@art-master.de") ); aboutData.addAuthor( i18n("Vladimir Prus"), i18n( "GDB integration" ), QStringLiteral("ghost@cs.msu.su") ); aboutData.addAuthor( i18n("Hamish Rodda"), i18n( "Text editor integration, definition-use chain" ), QStringLiteral("rodda@kde.org") ); aboutData.addAuthor( i18n("Amilcar do Carmo Lucas"), i18n( "Website admin, API documentation, Doxygen and autoproject patches" ), QStringLiteral("amilcar@kdevelop.org") ); aboutData.addAuthor( i18n("Niko Sams"), i18n( "GDB integration, Webdevelopment Plugins" ), QStringLiteral("niko.sams@gmail.com") ); aboutData.addAuthor( i18n("Friedrich W. H. Kossebau"), QString(), QStringLiteral("kossebau@kde.org") ); aboutData.addCredit( i18n("Matt Rogers"), QString(), QStringLiteral("mattr@kde.org")); aboutData.addCredit( i18n("Cédric Pasteur"), i18n("astyle and indent support"), QStringLiteral("cedric.pasteur@free.fr") ); aboutData.addCredit( i18n("Evgeniy Ivanov"), i18n("Distributed VCS, Git, Mercurial"), QStringLiteral("powerfox@kde.ru") ); // QTest integration is separate in playground currently. //aboutData.addCredit( i18n("Manuel Breugelmanns"), i18n( "Veritas, QTest integration"), "mbr.nxi@gmail.com" ); aboutData.addCredit( i18n("Robert Gruber") , i18n( "SnippetPart, debugger and usability patches" ), QStringLiteral("rgruber@users.sourceforge.net") ); aboutData.addCredit( i18n("Dukju Ahn"), i18n( "Subversion plugin, Custom Make Manager, Overall improvements" ), QStringLiteral("dukjuahn@gmail.com") ); aboutData.addCredit( i18n("Harald Fernengel"), i18n( "Ported to Qt 3, patches, valgrind, diff and perforce support" ), QStringLiteral("harry@kdevelop.org") ); aboutData.addCredit( i18n("Roberto Raggi"), i18n( "C++ parser" ), QStringLiteral("roberto@kdevelop.org") ); aboutData.addCredit( i18n("The KWrite authors"), i18n( "Kate editor component" ), QStringLiteral("kwrite-devel@kde.org") ); aboutData.addCredit( i18n("Nokia Corporation/Qt Software"), i18n( "Designer code" ), QStringLiteral("qt-info@nokia.com") ); aboutData.addCredit( i18n("Contributors to older versions:"), QString(), QString() ); aboutData.addCredit( i18n("Bernd Gehrmann"), i18n( "Initial idea, basic architecture, much initial source code" ), QStringLiteral("bernd@kdevelop.org") ); aboutData.addCredit( i18n("Caleb Tennis"), i18n( "KTabBar, bugfixes" ), QStringLiteral("caleb@aei-tech.com") ); aboutData.addCredit( i18n("Richard Dale"), i18n( "Java & Objective C support" ), QStringLiteral("Richard_Dale@tipitina.demon.co.uk") ); aboutData.addCredit( i18n("John Birch"), i18n( "Debugger frontend" ), QStringLiteral("jbb@kdevelop.org") ); aboutData.addCredit( i18n("Sandy Meier"), i18n( "PHP support, context menu stuff" ), QStringLiteral("smeier@kdevelop.org") ); aboutData.addCredit( i18n("Kurt Granroth"), i18n( "KDE application templates" ), QStringLiteral("kurth@granroth.org") ); aboutData.addCredit( i18n("Ian Reinhart Geiser"), i18n( "Dist part, bash support, application templates" ), QStringLiteral("geiseri@yahoo.com") ); aboutData.addCredit( i18n("Matthias Hoelzer-Kluepfel"), i18n( "Several components, htdig indexing" ), QStringLiteral("hoelzer@kde.org") ); aboutData.addCredit( i18n("Victor Roeder"), i18n( "Help with Automake manager and persistent class store" ), QStringLiteral("victor_roeder@gmx.de") ); aboutData.addCredit( i18n("Simon Hausmann"), i18n( "Help with KParts infrastructure" ), QStringLiteral("hausmann@kde.org") ); aboutData.addCredit( i18n("Oliver Kellogg"), i18n( "Ada support" ), QStringLiteral("okellogg@users.sourceforge.net") ); aboutData.addCredit( i18n("Jakob Simon-Gaarde"), i18n( "QMake projectmanager" ), QStringLiteral("jsgaarde@tdcspace.dk") ); aboutData.addCredit( i18n("Falk Brettschneider"), i18n( "MDI modes, QEditor, bugfixes" ), QStringLiteral("falkbr@kdevelop.org") ); aboutData.addCredit( i18n("Mario Scalas"), i18n( "PartExplorer, redesign of CvsPart, patches, bugs(fixes)" ), QStringLiteral("mario.scalas@libero.it") ); aboutData.addCredit( i18n("Jens Dagerbo"), i18n( "Replace, Bookmarks, FileList and CTags2 plugins. Overall improvements and patches" ), QStringLiteral("jens.dagerbo@swipnet.se") ); aboutData.addCredit( i18n("Julian Rockey"), i18n( "Filecreate part and other bits and patches" ), QStringLiteral("linux@jrockey.com") ); aboutData.addCredit( i18n("Ajay Guleria"), i18n( "ClearCase support" ), QStringLiteral("ajay_guleria@yahoo.com") ); aboutData.addCredit( i18n("Marek Janukowicz"), i18n( "Ruby support" ), QStringLiteral("child@t17.ds.pwr.wroc.pl") ); aboutData.addCredit( i18n("Robert Moniot"), i18n( "Fortran documentation" ), QStringLiteral("moniot@fordham.edu") ); aboutData.addCredit( i18n("Ka-Ping Yee"), i18n( "Python documentation utility" ), QStringLiteral("ping@lfw.org") ); aboutData.addCredit( i18n("Dimitri van Heesch"), i18n( "Doxygen wizard" ), QStringLiteral("dimitri@stack.nl") ); aboutData.addCredit( i18n("Hugo Varotto"), i18n( "Fileselector component" ), QStringLiteral("hugo@varotto-usa.com") ); aboutData.addCredit( i18n("Matt Newell"), i18n( "Fileselector component" ), QStringLiteral("newellm@proaxis.com") ); aboutData.addCredit( i18n("Daniel Engelschalt"), i18n( "C++ code completion, persistent class store" ), QStringLiteral("daniel.engelschalt@gmx.net") ); aboutData.addCredit( i18n("Stephane Ancelot"), i18n( "Patches" ), QStringLiteral("sancelot@free.fr") ); aboutData.addCredit( i18n("Jens Zurheide"), i18n( "Patches" ), QStringLiteral("jens.zurheide@gmx.de") ); aboutData.addCredit( i18n("Luc Willems"), i18n( "Help with Perl support" ), QStringLiteral("Willems.luc@pandora.be") ); aboutData.addCredit( i18n("Marcel Turino"), i18n( "Documentation index view" ), QStringLiteral("M.Turino@gmx.de") ); aboutData.addCredit( i18n("Yann Hodique"), i18n( "Patches" ), QStringLiteral("Yann.Hodique@lifl.fr") ); aboutData.addCredit( i18n("Tobias Gl\303\244\303\237er") , i18n( "Documentation Finder, qmake projectmanager patches, usability improvements, bugfixes ... " ), QStringLiteral("tobi.web@gmx.de") ); aboutData.addCredit( i18n("Andreas Koepfle") , i18n( "QMake project manager patches" ), QStringLiteral("koepfle@ti.uni-mannheim.de") ); aboutData.addCredit( i18n("Sascha Cunz") , i18n( "Cleanup and bugfixes for qEditor, AutoMake and much other stuff" ), QStringLiteral("mail@sacu.de") ); aboutData.addCredit( i18n("Zoran Karavla"), i18n( "Artwork for the ruby language" ), QStringLiteral("webmaster@the-error.net"), QStringLiteral("http://the-error.net") ); KAboutData::setApplicationData(aboutData); // set icon for shells which do not use desktop file metadata // but without setting replacing an existing icon with an empty one! QApplication::setWindowIcon(QIcon::fromTheme(QStringLiteral("kdevelop"), QApplication::windowIcon())); KCrash::initialize(); Kdelibs4ConfigMigrator migrator(QStringLiteral("kdevelop")); migrator.setConfigFiles({QStringLiteral("kdeveloprc")}); migrator.setUiFiles({QStringLiteral("kdevelopui.rc")}); migrator.migrate(); // High DPI support app.setAttribute(Qt::AA_UseHighDpiPixmaps, true); qCDebug(APP) << "Startup"; QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("n"), QStringLiteral("new-session")}, i18n("Open KDevelop with a new session using the given name."), QStringLiteral("name")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("s"), QStringLiteral("open-session")}, i18n("Open KDevelop with the given session.\n" "You can pass either hash or the name of the session."), QStringLiteral("session")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("rm"), QStringLiteral("remove-session")}, i18n("Delete the given session.\n" "You can pass either hash or the name of the session." ), QStringLiteral("session")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("ps"), QStringLiteral("pick-session")}, i18n("Shows all available sessions and lets you select one to open.")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("pss"), QStringLiteral("pick-session-shell")}, i18n("List all available sessions on shell and lets you select one to open.")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("l"), QStringLiteral("list-sessions")}, i18n("List available sessions and quit.")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("f"), QStringLiteral("fetch")}, i18n("Open KDevelop and fetch the project from the given ."), QStringLiteral("repo url")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("p"), QStringLiteral("project")}, i18n("Open KDevelop and load the given project. can be either a .kdev4 file or a directory path."), QStringLiteral("project")}); parser.addOption(QCommandLineOption{QStringList{QStringLiteral("d"), QStringLiteral("debug")}, i18n("Start debugging an application in KDevelop with the given debugger.\n" "The executable that should be debugged must follow - including arguments.\n" "Example: kdevelop --debug gdb myapp --foo bar"), QStringLiteral("debugger")}); // this is used by the 'kdevelop!' script to retrieve the pid of a KDEVELOP // instance. When this is called, then we should just print the PID on the // standard-output. If a session is specified through open-session, then // we should return the PID of that session. Otherwise, if only a single // session is running, then we should just return the PID of that session. // Otherwise, we should print a command-line session-chooser dialog ("--pss"), // which only shows the running sessions, and the user can pick one. parser.addOption(QCommandLineOption{QStringList{QStringLiteral("pid")}}); parser.addPositionalArgument(QStringLiteral("files"), i18n( "Files to load, or directories to load as projects" ), QStringLiteral("[FILE[:line[:column]] | DIRECTORY]...")); // The session-controller needs to arguments to eventually pass them to newly opened sessions KDevelop::SessionController::setArguments(argc, argv); parser.process(app); aboutData.processCommandLine(&parser); if(parser.isSet(QStringLiteral("list-sessions"))) { QTextStream qout(stdout); qout << endl << ki18n("Available sessions (use '-s HASH' or '-s NAME' to open a specific one):").toString() << endl << endl; qout << QStringLiteral("%1").arg(ki18n("Hash").toString(), -38) << '\t' << ki18n("Name: Opened Projects").toString() << endl; foreach(const KDevelop::SessionInfo& si, KDevelop::SessionController::availableSessionInfos()) { if ( si.name.isEmpty() && si.projects.isEmpty() ) { continue; } qout << si.uuid.toString() << '\t' << si.description; if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) qout << " " << i18n("[running]"); qout << endl; } return 0; } // Handle extra arguments, which stand for files to open QVector initialFiles; QVector initialDirectories; foreach (const QString &file, parser.positionalArguments()) { const UrlInfo info(file); if (info.isDirectory()) { initialDirectories.append(info); } else { initialFiles.append(info); } } const auto availableSessionInfos = KDevelop::SessionController::availableSessionInfos(); if ((!initialFiles.isEmpty() || !initialDirectories.isEmpty()) && !parser.isSet(QStringLiteral("new-session"))) { #if KDEVELOP_SINGLE_APP if (app.isRunning()) { bool success = app.sendMessage(serializeOpenFilesMessage(initialFiles << initialDirectories)); if (success) { return 0; } } #else qint64 pid = -1; if (parser.isSet(QStringLiteral("open-session"))) { const QString session = findSessionId(availableSessionInfos, parser.value(QStringLiteral("open-session"))); if (session.isEmpty()) { return 1; } else if (KDevelop::SessionController::isSessionRunning(session)) { pid = findSessionPid(session); } } else { pid = getRunningSessionPid(); } if ( pid > 0 ) { return openFilesInRunningInstance(initialFiles, pid) + openProjectInRunningInstance(initialDirectories, pid); } // else there are no running sessions, and the generated list of files will be opened below. #endif } // if empty, restart kdevelop with last active session, see SessionController::defaultSessionId QString session; uint nRunningSessions = 0; for (const KDevelop::SessionInfo& si : availableSessionInfos) { if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) ++nRunningSessions; } // also show the picker dialog when a pid shall be retrieved and multiple // sessions are running. if(parser.isSet(QStringLiteral("pss")) || (parser.isSet(QStringLiteral("pid")) && !parser.isSet(QStringLiteral("open-session")) && !parser.isSet(QStringLiteral("ps")) && nRunningSessions > 1)) { QTextStream qerr(stderr); SessionInfos candidates; for (const KDevelop::SessionInfo& si : availableSessionInfos) { if( (!si.name.isEmpty() || !si.projects.isEmpty() || parser.isSet(QStringLiteral("pid"))) && (!parser.isSet(QStringLiteral("pid")) || KDevelop::SessionController::isSessionRunning(si.uuid.toString()))) candidates << si; } if(candidates.size() == 0) { qerr << "no session available" << endl; return 1; } if(candidates.size() == 1 && parser.isSet(QStringLiteral("pid"))) { session = candidates[0].uuid.toString(); }else{ for(int i = 0; i < candidates.size(); ++i) qerr << "[" << i << "]: " << candidates[i].description << endl; int chosen; std::cin >> chosen; if(std::cin.good() && (chosen >= 0 && chosen < candidates.size())) { session = candidates[chosen].uuid.toString(); }else{ qerr << "invalid selection" << endl; return 1; } } } if(parser.isSet(QStringLiteral("ps"))) { bool onlyRunning = parser.isSet(QStringLiteral("pid")); session = KDevelop::SessionController::showSessionChooserDialog(i18n("Select the session you would like to use"), onlyRunning); if(session.isEmpty()) return 1; } if ( parser.isSet(QStringLiteral("debug")) ) { if ( debugArgs.isEmpty() ) { QTextStream qerr(stderr); qerr << endl << i18nc("@info:shell", "Specify the executable you want to debug.") << endl; return 1; } QFileInfo executableFileInfo(debugArgs.first()); if (!executableFileInfo.exists()) { executableFileInfo = QStandardPaths::findExecutable(debugArgs.first()); if (!executableFileInfo.exists()) { QTextStream qerr(stderr); qerr << endl << i18nc("@info:shell", "Specified executable does not exist.") << endl; return 1; } } debugArgs.first() = executableFileInfo.absoluteFilePath(); debugeeName = i18n("Debug %1", executableFileInfo.fileName()); session = debugeeName; } else if ( parser.isSet(QStringLiteral("new-session")) ) { session = parser.value(QStringLiteral("new-session")); for (const KDevelop::SessionInfo& si : availableSessionInfos) { if ( session == si.name ) { QTextStream qerr(stderr); qerr << endl << i18n("A session with the name %1 exists already. Use the -s switch to open it.", session) << endl; return 1; } } // session doesn't exist, we can create it } else if ( parser.isSet(QStringLiteral("open-session")) ) { session = findSessionId(availableSessionInfos, parser.value(QStringLiteral("open-session"))); if (session.isEmpty()) { return 1; } } else if ( parser.isSet(QStringLiteral("remove-session")) ) { session = parser.value(QStringLiteral("remove-session")); auto si = findSessionInList(availableSessionInfos, session); if (!si) { QTextStream qerr(stderr); qerr << endl << i18n("No session with the name %1 exists.", session) << endl; return 1; } auto sessionLock = KDevelop::SessionController::tryLockSession(si->uuid.toString()); if (!sessionLock.lock) { QTextStream qerr(stderr); qerr << endl << i18n("Could not lock session %1 for deletion.", session) << endl; return 1; } KDevelop::SessionController::deleteSessionFromDisk(sessionLock.lock); QTextStream qout(stdout); qout << endl << i18n("Session with name %1 was successfully removed.", session) << endl; return 0; } if(parser.isSet(QStringLiteral("pid"))) { if (session.isEmpty()) { // just pick the first running session for (const KDevelop::SessionInfo& si : availableSessionInfos) { if(KDevelop::SessionController::isSessionRunning(si.uuid.toString())) session = si.uuid.toString(); } } const KDevelop::SessionInfo* sessionData = findSessionInList(availableSessionInfos, session); if( !sessionData ) { qCritical(APP) << "session not given or does not exist"; return 5; } const auto pid = findSessionPid(sessionData->uuid.toString()); if (pid > 0) { // Print the PID and we're ready std::cout << pid << std::endl; return 0; } else { qCritical(APP) << sessionData->uuid.toString() << sessionData->name << "is not running"; return 5; } } if (parser.isSet(QStringLiteral("project"))) { const auto project = parser.value(QStringLiteral("project")); QFileInfo info(project); QUrl projectUrl; if (info.suffix() == QLatin1String("kdev4")) { projectUrl = QUrl::fromLocalFile(info.absoluteFilePath()); } else if (info.isDir()) { QDir dir(info.absoluteFilePath()); const auto potentialProjectFiles = dir.entryList({QStringLiteral("*.kdev4")}, QDir::Files, QDir::Name); qDebug(APP) << "Found these potential project files:" << potentialProjectFiles; if (!potentialProjectFiles.isEmpty()) { projectUrl = QUrl::fromLocalFile(dir.absoluteFilePath(potentialProjectFiles.value(0))); } } else { QTextStream qerr(stderr); qerr << "Invalid project: " << project << " - should be either a path to a .kdev4 file or a directory containing a .kdev4 file"; return 1; } qDebug(APP) << "Attempting to find a suitable session for project" << projectUrl; const auto sessionInfos = findSessionsWithProject(availableSessionInfos, projectUrl); qDebug(APP) << "Found matching sessions:" << sessionInfos.size(); if (!sessionInfos.isEmpty()) { // TODO: If there's more than one match: Allow the user to select which session to open? qDebug(APP) << "Attempting to open session:" << sessionInfos.at(0).name; session = sessionInfos.at(0).uuid.toString(); } } KDevIDEExtension::init(); qDebug(APP) << "Attempting to initialize session:" << session; if(!Core::initialize(Core::Default, session)) return 5; // register a DBUS service for this process, so that we can open files in it from other invocations QDBusConnection::sessionBus().registerService(QStringLiteral("org.kdevelop.kdevelop-%1").arg(app.applicationPid())); Core* core = Core::self(); if (!QProcessEnvironment::systemEnvironment().contains(QStringLiteral("KDEV_DISABLE_WELCOMEPAGE"))) { core->pluginController()->loadPlugin(QStringLiteral("KDevWelcomePage")); } const auto fetchUrlStrings = parser.values(QStringLiteral("fetch")); for (const auto& fetchUrlString : fetchUrlStrings) { core->projectControllerInternal()->fetchProjectFromUrl(QUrl::fromUserInput(fetchUrlString)); } const QString debugStr = QStringLiteral("debug"); if ( parser.isSet(debugStr) ) { Q_ASSERT( !debugeeName.isEmpty() ); QString launchName = debugeeName; KDevelop::LaunchConfiguration* launch = nullptr; qCDebug(APP) << launchName; foreach (KDevelop::LaunchConfiguration *l, core->runControllerInternal()->launchConfigurationsInternal()) { qCDebug(APP) << l->name(); if (l->name() == launchName) { launch = l; } } KDevelop::LaunchConfigurationType *type = nullptr; foreach (KDevelop::LaunchConfigurationType *t, core->runController()->launchConfigurationTypes()) { qCDebug(APP) << t->id(); if (t->id() == QLatin1String("Native Application")) { type = t; break; } } if (!type) { QTextStream qerr(stderr); qerr << endl << i18n("Cannot find native launch configuration type") << endl; return 1; } if (launch && launch->type()->id() != QLatin1String("Native Application")) launch = nullptr; if (launch && launch->launcherForMode(debugStr) != parser.value(debugStr)) launch = nullptr; if (!launch) { qCDebug(APP) << launchName << "not found, creating a new one"; QPair launcher; launcher.first = debugStr; foreach (KDevelop::ILauncher *l, type->launchers()) { if (l->id() == parser.value(debugStr)) { if (l->supportedModes().contains(debugStr)) { launcher.second = l->id(); } } } if (launcher.second.isEmpty()) { QTextStream qerr(stderr); qerr << endl << i18n("Cannot find launcher %1", parser.value(debugStr)) << endl; return 1; } KDevelop::ILaunchConfiguration* ilaunch = core->runController()->createLaunchConfiguration(type, launcher, nullptr, launchName); launch = static_cast(ilaunch); } type->configureLaunchFromCmdLineArguments(launch->config(), debugArgs); launch->config().writeEntry("Break on Start", true); core->runControllerInternal()->setDefaultLaunch(launch); core->runControllerInternal()->execute(debugStr, launch); } else { openFiles(initialFiles); for(const auto& urlinfo: qAsConst(initialDirectories)) core->projectController()->openProjectForUrl(urlinfo.url); } #if KDEVELOP_SINGLE_APP // Set up remote arguments. QObject::connect(&app, &SharedTools::QtSingleApplication::messageReceived, &app, &KDevelopApplication::remoteArguments); QObject::connect(&app, &SharedTools::QtSingleApplication::fileOpenRequest, &app, &KDevelopApplication::fileOpenRequested); #endif qCDebug(APP) << "Done startup" << "- took:" << timer.elapsed() << "ms"; timer.invalidate(); return app.exec(); } + +#include "main.moc" diff --git a/kdevplatform/debugger/util/treeview.cpp b/kdevplatform/debugger/util/treeview.cpp index d2bd861e75..a451ab49fd 100644 --- a/kdevplatform/debugger/util/treeview.cpp +++ b/kdevplatform/debugger/util/treeview.cpp @@ -1,87 +1,88 @@ /* * This file is part of KDevelop * * Copyright 2008 Vladimir Prus * * This program 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. * * This program 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 this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "treeview.h" + +#include "treemodel.h" + #include #include #include -#include "treeview.h" -#include "treemodel.h" - using namespace KDevelop; AsyncTreeView::AsyncTreeView(TreeModel* model, QSortFilterProxyModel *proxy, QWidget *parent = nullptr) : QTreeView(parent) , m_proxy(proxy) { connect (this, &AsyncTreeView::expanded, this, &AsyncTreeView::slotExpanded); connect (this, &AsyncTreeView::collapsed, this, &AsyncTreeView::slotCollapsed); connect (this, &AsyncTreeView::clicked, this, &AsyncTreeView::slotClicked); connect (model, &TreeModel::itemChildrenReady, this, &AsyncTreeView::slotExpandedDataReady); } void AsyncTreeView::slotExpanded(const QModelIndex &index) { static_cast(model())->expanded(m_proxy->mapToSource(index)); } void AsyncTreeView::slotCollapsed(const QModelIndex &index) { static_cast(model())->collapsed(m_proxy->mapToSource(index)); resizeColumns(); } void AsyncTreeView::slotClicked(const QModelIndex &index) { static_cast(model())->clicked(m_proxy->mapToSource(index)); resizeColumns(); } QSize AsyncTreeView::sizeHint() const { //Assuming that columns are awlays resized to fit their contents, return a size that will fit all without a scrollbar QMargins margins = contentsMargins(); int horizontalSize = margins.left() + margins.right(); for (int i = 0; i < model()->columnCount(); ++i) { horizontalSize += columnWidth(i); } horizontalSize = qMin(horizontalSize, QApplication::desktop()->screenGeometry().width()*3/4); return QSize(horizontalSize, margins.top() + margins.bottom() + sizeHintForRow(0)); } void AsyncTreeView::resizeColumns() { for (int i = 0; i < model()->columnCount(); ++i) { this->resizeColumnToContents(i); } this->updateGeometry(); } void AsyncTreeView::slotExpandedDataReady() { resizeColumns(); } diff --git a/kdevplatform/documentation/standarddocumentationview.cpp b/kdevplatform/documentation/standarddocumentationview.cpp index 9ddc69543a..44894234f4 100644 --- a/kdevplatform/documentation/standarddocumentationview.cpp +++ b/kdevplatform/documentation/standarddocumentationview.cpp @@ -1,388 +1,394 @@ /* * This file is part of KDevelop * Copyright 2010 Aleix Pol Gonzalez * Copyright 2016 Igor Kushnir * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program 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 this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "standarddocumentationview.h" #include "documentationfindwidget.h" #include "debug.h" #include #include #include #include #include #include #ifdef USE_QTWEBKIT #include #include #include #include #else #include #include #include #include #include #include #include #include #endif using namespace KDevelop; #ifndef USE_QTWEBKIT class StandardDocumentationPage : public QWebEnginePage { + Q_OBJECT public: StandardDocumentationPage(QWebEngineProfile* profile, KDevelop::StandardDocumentationView* parent) : QWebEnginePage(profile, parent), m_view(parent) { } bool acceptNavigationRequest(const QUrl &url, NavigationType type, bool isMainFrame) override { qCDebug(DOCUMENTATION) << "navigating to..." << url << type; if (type == NavigationTypeLinkClicked && m_isDelegating) { emit m_view->linkClicked(url); return false; } return QWebEnginePage::acceptNavigationRequest(url, type, isMainFrame); } void setLinkDelegating(bool isDelegating) { m_isDelegating = isDelegating; } private: KDevelop::StandardDocumentationView* const m_view; bool m_isDelegating = false; }; #endif class KDevelop::StandardDocumentationViewPrivate { public: ZoomController* m_zoomController = nullptr; IDocumentation::Ptr m_doc; #ifdef USE_QTWEBKIT QWebView *m_view = nullptr; void init(StandardDocumentationView* parent) { m_view = new QWebView(parent); m_view->setContextMenuPolicy(Qt::NoContextMenu); QObject::connect(m_view, &QWebView::linkClicked, parent, &StandardDocumentationView::linkClicked); } #else QWebEngineView* m_view = nullptr; StandardDocumentationPage* m_page = nullptr; void init(StandardDocumentationView* parent) { // not using the shared default profile here: // prevents conflicts with qthelp scheme handler being registered onto that single default profile // due to async deletion of old pages and their CustomSchemeHandler instance auto* profile = new QWebEngineProfile(parent); m_page = new StandardDocumentationPage(profile, parent); m_view = new QWebEngineView(parent); m_view->setPage(m_page); // workaround for Qt::NoContextMenu broken with QWebEngineView, contextmenu event is always eaten // see https://bugreports.qt.io/browse/QTBUG-62345 // we have to enforce deferring of event ourselves m_view->installEventFilter(parent); } #endif }; StandardDocumentationView::StandardDocumentationView(DocumentationFindWidget* findWidget, QWidget* parent) : QWidget(parent) , d(new StandardDocumentationViewPrivate) { auto mainLayout = new QVBoxLayout(this); mainLayout->setMargin(0); setLayout(mainLayout); d->init(this); layout()->addWidget(d->m_view); findWidget->setEnabled(true); connect(findWidget, &DocumentationFindWidget::searchRequested, this, &StandardDocumentationView::search); connect(findWidget, &DocumentationFindWidget::searchDataChanged, this, &StandardDocumentationView::searchIncremental); connect(findWidget, &DocumentationFindWidget::searchFinished, this, &StandardDocumentationView::finishSearch); #ifdef USE_QTWEBKIT QFont sansSerifFont = QFontDatabase::systemFont(QFontDatabase::GeneralFont); QFont monospaceFont = QFontDatabase::systemFont(QFontDatabase::FixedFont); QWebSettings* s = d->m_view->settings(); s->setFontFamily(QWebSettings::StandardFont, sansSerifFont.family()); s->setFontFamily(QWebSettings::SerifFont, QStringLiteral("Serif")); s->setFontFamily(QWebSettings::SansSerifFont, sansSerifFont.family()); s->setFontFamily(QWebSettings::FixedFont, monospaceFont.family()); s->setFontSize(QWebSettings::DefaultFontSize, QFontInfo(sansSerifFont).pixelSize()); s->setFontSize(QWebSettings::DefaultFixedFontSize, QFontInfo(monospaceFont).pixelSize()); // Fixes for correct positioning. The problem looks like the following: // // 1) Some page is loaded and loadFinished() signal is emitted, // after this QWebView set right position inside page. // // 2) After loadFinished() emitting, page JS code finishes it's work and changes // font settings (size). This leads to page contents "moving" inside view widget // and as a result we have wrong position. // // Such behavior occurs for example with QtHelp pages. // // To fix the problem, first, we disable view painter updates during load to avoid content // "flickering" and also to hide font size "jumping". Secondly, we reset position inside page // after loading with using standard QWebFrame method scrollToAnchor(). connect(d->m_view, &QWebView::loadStarted, d->m_view, [this]() { d->m_view->setUpdatesEnabled(false); }); connect(d->m_view, &QWebView::loadFinished, this, [this](bool) { if (d->m_view->url().isValid()) { d->m_view->page()->mainFrame()->scrollToAnchor(d->m_view->url().fragment()); } d->m_view->setUpdatesEnabled(true); }); #endif } KDevelop::StandardDocumentationView::~StandardDocumentationView() = default; void StandardDocumentationView::search ( const QString& text, DocumentationFindWidget::FindOptions options ) { #ifdef USE_QTWEBKIT typedef QWebPage WebkitThing; #else typedef QWebEnginePage WebkitThing; #endif WebkitThing::FindFlags ff = {}; if(options & DocumentationFindWidget::Previous) ff |= WebkitThing::FindBackward; if(options & DocumentationFindWidget::MatchCase) ff |= WebkitThing::FindCaseSensitively; d->m_view->page()->findText(text, ff); } void StandardDocumentationView::searchIncremental(const QString& text, DocumentationFindWidget::FindOptions options) { #ifdef USE_QTWEBKIT typedef QWebPage WebkitThing; #else typedef QWebEnginePage WebkitThing; #endif WebkitThing::FindFlags findFlags; if (options & DocumentationFindWidget::MatchCase) findFlags |= WebkitThing::FindCaseSensitively; // calling with changed text with added or removed chars at end will result in current // selection kept, if also matching new text // behaviour on changed case sensitivity though is advancing to next match even if current // would be still matching. as there is no control about currently shown match, nothing // we can do about it. thankfully case sensitivity does not happen too often, so should // not be too grave UX // at least with webengine 5.9.1 there is a bug when switching from no-casesensitivy to // casesensitivity, that global matches are not updated and the ones with non-matching casing // still active. no workaround so far. d->m_view->page()->findText(text, findFlags); } void StandardDocumentationView::finishSearch() { // passing emptry string to reset search, as told in API docs d->m_view->page()->findText(QString()); } void StandardDocumentationView::initZoom(const QString& configSubGroup) { Q_ASSERT_X(!d->m_zoomController, "StandardDocumentationView::initZoom", "Can not initZoom a second time."); const KConfigGroup outerGroup(KSharedConfig::openConfig(), QStringLiteral("Documentation View")); const KConfigGroup configGroup(&outerGroup, configSubGroup); d->m_zoomController = new ZoomController(configGroup, this); connect(d->m_zoomController, &ZoomController::factorChanged, this, &StandardDocumentationView::updateZoomFactor); updateZoomFactor(d->m_zoomController->factor()); } void StandardDocumentationView::setDocumentation(const IDocumentation::Ptr& doc) { if(d->m_doc) disconnect(d->m_doc.data()); d->m_doc = doc; update(); if(d->m_doc) connect(d->m_doc.data(), &IDocumentation::descriptionChanged, this, &StandardDocumentationView::update); } void StandardDocumentationView::update() { if(d->m_doc) { setHtml(d->m_doc->description()); } else qCDebug(DOCUMENTATION) << "calling StandardDocumentationView::update() on an uninitialized view"; } void KDevelop::StandardDocumentationView::setOverrideCss(const QUrl& url) { #ifdef USE_QTWEBKIT d->m_view->settings()->setUserStyleSheetUrl(url); #else d->m_view->page()->runJavaScript(QLatin1String( "var link = document.createElement( 'link' );" "link.href = '") + url.toString() + QLatin1String("';" "link.type = 'text/css';" "link.rel = 'stylesheet';" "link.media = 'screen,print';" "document.getElementsByTagName( 'head' )[0].appendChild( link );") ); #endif } void KDevelop::StandardDocumentationView::load(const QUrl& url) { #ifdef USE_QTWEBKIT d->m_view->load(url); #else d->m_view->page()->load(url); #endif } void KDevelop::StandardDocumentationView::setHtml(const QString& html) { #ifdef USE_QTWEBKIT d->m_view->setHtml(html); #else d->m_view->page()->setHtml(html); #endif } #ifndef USE_QTWEBKIT class CustomSchemeHandler : public QWebEngineUrlSchemeHandler { + Q_OBJECT public: explicit CustomSchemeHandler(QNetworkAccessManager* nam, QObject *parent = nullptr) : QWebEngineUrlSchemeHandler(parent), m_nam(nam) {} void requestStarted(QWebEngineUrlRequestJob *job) override { const QUrl url = job->requestUrl(); auto reply = m_nam->get(QNetworkRequest(url)); job->reply("text/html", reply); } private: QNetworkAccessManager* m_nam; }; #endif void KDevelop::StandardDocumentationView::setNetworkAccessManager(QNetworkAccessManager* manager) { #ifdef USE_QTWEBKIT d->m_view->page()->setNetworkAccessManager(manager); #else d->m_view->page()->profile()->installUrlSchemeHandler("qthelp", new CustomSchemeHandler(manager, this)); #endif } void KDevelop::StandardDocumentationView::setDelegateLinks(bool delegate) { #ifdef USE_QTWEBKIT d->m_view->page()->setLinkDelegationPolicy(delegate ? QWebPage::DelegateAllLinks : QWebPage::DontDelegateLinks); #else d->m_page->setLinkDelegating(delegate); #endif } QMenu* StandardDocumentationView::createStandardContextMenu() { auto menu = new QMenu(this); #ifdef USE_QTWEBKIT typedef QWebPage WebkitThing; #else typedef QWebEnginePage WebkitThing; #endif auto copyAction = d->m_view->pageAction(WebkitThing::Copy); if (copyAction) { copyAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-copy"))); menu->addAction(copyAction); } return menu; } bool StandardDocumentationView::eventFilter(QObject* object, QEvent* event) { #ifndef USE_QTWEBKIT if (object == d->m_view) { // help QWebEngineView properly behave like expected as if Qt::NoContextMenu was set if (event->type() == QEvent::ContextMenu) { event->ignore(); return true; } } #endif return QWidget::eventFilter(object, event); } void StandardDocumentationView::contextMenuEvent(QContextMenuEvent* event) { auto menu = createStandardContextMenu(); if (menu->isEmpty()) { delete menu; return; } menu->setAttribute(Qt::WA_DeleteOnClose); menu->exec(event->globalPos()); } void StandardDocumentationView::updateZoomFactor(double zoomFactor) { d->m_view->setZoomFactor(zoomFactor); } void StandardDocumentationView::keyPressEvent(QKeyEvent* event) { if (d->m_zoomController && d->m_zoomController->handleKeyPressEvent(event)) { return; } QWidget::keyPressEvent(event); } void StandardDocumentationView::wheelEvent(QWheelEvent* event) { if (d->m_zoomController && d->m_zoomController->handleWheelEvent(event)) { return; } QWidget::wheelEvent(event); } + +#ifndef USE_QTWEBKIT +#include "standarddocumentationview.moc" +#endif diff --git a/kdevplatform/language/codegen/templateengine.cpp b/kdevplatform/language/codegen/templateengine.cpp index e70b6b5c89..83bcb65c16 100644 --- a/kdevplatform/language/codegen/templateengine.cpp +++ b/kdevplatform/language/codegen/templateengine.cpp @@ -1,77 +1,77 @@ /* * This file is part of KDevelop * * Copyright 2012 Milian Wolff * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program 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 this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "templateengine.h" +#include "templateengine_p.h" #include "debug.h" -#include "templateengine_p.h" #include "codedescription.h" #include "codedescriptionmetatypes.h" #include "archivetemplateloader.h" #include #include using namespace KDevelop; using namespace Grantlee; TemplateEngine* TemplateEngine::self() { static TemplateEngine* engine = new TemplateEngine; return engine; } TemplateEngine::TemplateEngine() : d(new TemplateEnginePrivate) { d->engine.setSmartTrimEnabled(true); qCDebug(LANGUAGE) << "Generic data locations:" << QStandardPaths::standardLocations(QStandardPaths::GenericDataLocation); const auto templateDirectories = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kdevcodegen/templates"), QStandardPaths::LocateDirectory); if (!templateDirectories.isEmpty()) { qCDebug(LANGUAGE) << "Found template directories:" << templateDirectories; addTemplateDirectories(QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("kdevcodegen/templates"), QStandardPaths::LocateDirectory)); } else { qCWarning(LANGUAGE) << "No template directories found -- templating engine will not work!"; } Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); Grantlee::registerMetaType(); d->engine.addTemplateLoader(QSharedPointer(ArchiveTemplateLoader::self())); } TemplateEngine::~TemplateEngine() { } void TemplateEngine::addTemplateDirectories(const QStringList& directories) { FileSystemTemplateLoader* loader = new FileSystemTemplateLoader; loader->setTemplateDirs(directories); d->engine.addTemplateLoader(QSharedPointer(loader)); } diff --git a/kdevplatform/language/duchain/definitions.cpp b/kdevplatform/language/duchain/definitions.cpp index 9bc186bea1..69a00591e5 100644 --- a/kdevplatform/language/duchain/definitions.cpp +++ b/kdevplatform/language/duchain/definitions.cpp @@ -1,224 +1,225 @@ /* This file is part of KDevelop Copyright 2008 David Nolden Copyright 2014 Kevin Funk This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "appendedlist.h" #include "definitions.h" + +#include "appendedlist.h" #include "declaration.h" #include "declarationid.h" #include "duchainpointer.h" #include #include "serialization/itemrepository.h" namespace KDevelop { DEFINE_LIST_MEMBER_HASH(DefinitionsItem, definitions, IndexedDeclaration) class DefinitionsItem { public: DefinitionsItem() { initializeAppendedLists(); } DefinitionsItem(const DefinitionsItem& rhs, bool dynamic = true) : declaration(rhs.declaration) { initializeAppendedLists(dynamic); copyListsFrom(rhs); } ~DefinitionsItem() { freeAppendedLists(); } unsigned int hash() const { //We only compare the declaration. This allows us implementing a map, although the item-repository //originally represents a set. return declaration.hash(); } unsigned int itemSize() const { return dynamicSize(); } uint classSize() const { return sizeof(DefinitionsItem); } DeclarationId declaration; START_APPENDED_LISTS(DefinitionsItem); APPENDED_LIST_FIRST(DefinitionsItem, IndexedDeclaration, definitions); END_APPENDED_LISTS(DefinitionsItem, definitions); }; class DefinitionsRequestItem { public: DefinitionsRequestItem(const DefinitionsItem& item) : m_item(item) { } enum { AverageSize = 30 //This should be the approximate average size of an Item }; unsigned int hash() const { return m_item.hash(); } uint itemSize() const { return m_item.itemSize(); } void createItem(DefinitionsItem* item) const { new (item) DefinitionsItem(m_item, false); } static void destroy(DefinitionsItem* item, KDevelop::AbstractItemRepository&) { item->~DefinitionsItem(); } static bool persistent(const DefinitionsItem*) { return true; } bool equals(const DefinitionsItem* item) const { return m_item.declaration == item->declaration; } const DefinitionsItem& m_item; }; class DefinitionsVisitor { public: DefinitionsVisitor(Definitions* _definitions, const QTextStream& _out) : definitions(_definitions) , out(_out) { } bool operator()(const DefinitionsItem* item) { QDebug qout(out.device()); auto id = item->declaration; const auto allDefinitions = definitions->definitions(id); qout << "Definitions for" << id.qualifiedIdentifier() << endl; for (const IndexedDeclaration& decl : allDefinitions) { if(decl.data()) { qout << " " << decl.data()->qualifiedIdentifier() << "in" << decl.data()->url().byteArray() << "at" << decl.data()->rangeInCurrentRevision() << endl; } } return true; } private: const Definitions* definitions; const QTextStream& out; }; class DefinitionsPrivate { public: DefinitionsPrivate() : m_definitions(QStringLiteral("Definition Map")) { } //Maps declaration-ids to definitions ItemRepository m_definitions; }; Definitions::Definitions() : d(new DefinitionsPrivate()) { } Definitions::~Definitions() = default; void Definitions::addDefinition(const DeclarationId& id, const IndexedDeclaration& definition) { DefinitionsItem item; item.declaration = id; item.definitionsList().append(definition); DefinitionsRequestItem request(item); uint index = d->m_definitions.findIndex(item); if(index) { //Check whether the item is already in the mapped list, else copy the list into the new created item const DefinitionsItem* oldItem = d->m_definitions.itemFromIndex(index); for(unsigned int a = 0; a < oldItem->definitionsSize(); ++a) { if(oldItem->definitions()[a] == definition) return; //Already there item.definitionsList().append(oldItem->definitions()[a]); } d->m_definitions.deleteItem(index); } //This inserts the changed item d->m_definitions.index(request); } void Definitions::removeDefinition(const DeclarationId& id, const IndexedDeclaration& definition) { DefinitionsItem item; item.declaration = id; DefinitionsRequestItem request(item); uint index = d->m_definitions.findIndex(item); if(index) { //Check whether the item is already in the mapped list, else copy the list into the new created item const DefinitionsItem* oldItem = d->m_definitions.itemFromIndex(index); for(unsigned int a = 0; a < oldItem->definitionsSize(); ++a) if(!(oldItem->definitions()[a] == definition)) item.definitionsList().append(oldItem->definitions()[a]); d->m_definitions.deleteItem(index); Q_ASSERT(d->m_definitions.findIndex(item) == 0); //This inserts the changed item if(item.definitionsSize() != 0) d->m_definitions.index(request); } } KDevVarLengthArray Definitions::definitions(const DeclarationId& id) const { KDevVarLengthArray ret; DefinitionsItem item; item.declaration = id; DefinitionsRequestItem request(item); uint index = d->m_definitions.findIndex(item); if(index) { const DefinitionsItem* repositoryItem = d->m_definitions.itemFromIndex(index); FOREACH_FUNCTION(const IndexedDeclaration& decl, repositoryItem->definitions) ret.append(decl); } return ret; } void Definitions::dump(const QTextStream& out) { QMutexLocker lock(d->m_definitions.mutex()); DefinitionsVisitor v(this, out); d->m_definitions.visitAllItems(v); } } diff --git a/kdevplatform/project/helper.cpp b/kdevplatform/project/helper.cpp index 4bc71b53d8..98c458e28b 100644 --- a/kdevplatform/project/helper.cpp +++ b/kdevplatform/project/helper.cpp @@ -1,234 +1,235 @@ /* This file is part of KDevelop Copyright 2010 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "debug.h" #include "helper.h" + +#include "debug.h" #include "path.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; bool KDevelop::removeUrl(const KDevelop::IProject* project, const QUrl& url, const bool isFolder) { qCDebug(PROJECT) << "Removing url:" << url << "from project" << project; QWidget* window = QApplication::activeWindow(); auto job = KIO::stat(url, KIO::StatJob::DestinationSide, 0); KJobWidgets::setWindow(job, window); if (!job->exec()) { qCWarning(PROJECT) << "tried to remove non-existing url:" << url << project << isFolder; return true; } IPlugin* vcsplugin=project->versionControlPlugin(); if(vcsplugin) { IBasicVersionControl* vcs=vcsplugin->extension(); // We have a vcs and the file/folder is controller, need to make the rename through vcs if(vcs->isVersionControlled(url)) { VcsJob* job=vcs->remove(QList() << url); if(job) { return job->exec(); } } } //if we didn't find a VCS, we remove using KIO (if the file still exists, the vcs plugin might have simply deleted the url without returning a job auto deleteJob = KIO::del(url); KJobWidgets::setWindow(deleteJob, window); if (!deleteJob->exec() && url.isLocalFile() && (QFileInfo::exists(url.toLocalFile()))) { KMessageBox::error( window, isFolder ? i18n( "Cannot remove folder %1.", url.toDisplayString(QUrl::PreferLocalFile) ) : i18n( "Cannot remove file %1.", url.toDisplayString(QUrl::PreferLocalFile) ) ); return false; } return true; } bool KDevelop::removePath(const KDevelop::IProject* project, const KDevelop::Path& path, const bool isFolder) { return removeUrl(project, path.toUrl(), isFolder); } bool KDevelop::createFile(const QUrl& file) { auto statJob = KIO::stat(file, KIO::StatJob::DestinationSide, 0); KJobWidgets::setWindow(statJob, QApplication::activeWindow()); if (statJob->exec()) { KMessageBox::error( QApplication::activeWindow(), i18n( "The file %1 already exists.", file.toDisplayString(QUrl::PreferLocalFile) ) ); return false; } { auto uploadJob = KIO::storedPut(QByteArray("\n"), file, -1); KJobWidgets::setWindow(uploadJob, QApplication::activeWindow()); if (!uploadJob->exec()) { KMessageBox::error( QApplication::activeWindow(), i18n( "Cannot create file %1.", file.toDisplayString(QUrl::PreferLocalFile) ) ); return false; } } return true; } bool KDevelop::createFile(const KDevelop::Path& file) { return createFile(file.toUrl()); } bool KDevelop::createFolder(const QUrl& folder) { auto mkdirJob = KIO::mkdir(folder); KJobWidgets::setWindow(mkdirJob, QApplication::activeWindow()); if (!mkdirJob->exec()) { KMessageBox::error( QApplication::activeWindow(), i18n( "Cannot create folder %1.", folder.toDisplayString(QUrl::PreferLocalFile) ) ); return false; } return true; } bool KDevelop::createFolder(const KDevelop::Path& folder) { return createFolder(folder.toUrl()); } bool KDevelop::renameUrl(const KDevelop::IProject* project, const QUrl& oldname, const QUrl& newname) { bool wasVcsMoved = false; IPlugin* vcsplugin = project->versionControlPlugin(); if (vcsplugin) { IBasicVersionControl* vcs = vcsplugin->extension(); // We have a vcs and the file/folder is controller, need to make the rename through vcs if (vcs->isVersionControlled(oldname)) { VcsJob* job = vcs->move(oldname, newname); if (job && !job->exec()) { return false; } wasVcsMoved = true; } } // Fallback for the case of no vcs, or not-vcs-managed file/folder // try to save-as the text document, so users can directly continue to work // on the renamed url as well as keeping the undo-stack intact IDocument* document = ICore::self()->documentController()->documentForUrl(oldname); if (document && document->textDocument()) { if (!document->textDocument()->saveAs(newname)) { return false; } if (!wasVcsMoved) { // unlink the old file removeUrl(project, oldname, false); } return true; } else if (!wasVcsMoved) { // fallback for non-textdocuments (also folders e.g.) KIO::CopyJob* job = KIO::move(oldname, newname); KJobWidgets::setWindow(job, QApplication::activeWindow()); bool success = job->exec(); if (success) { // save files that where opened in this folder under the new name Path oldBasePath(oldname); Path newBasePath(newname); foreach (auto doc, ICore::self()->documentController()->openDocuments()) { auto textDoc = doc->textDocument(); if (textDoc && oldname.isParentOf(doc->url())) { const auto path = Path(textDoc->url()); const auto relativePath = oldBasePath.relativePath(path); const auto newPath = Path(newBasePath, relativePath); textDoc->saveAs(newPath.toUrl()); } } } return success; } else { return true; } } bool KDevelop::renamePath(const KDevelop::IProject* project, const KDevelop::Path& oldName, const KDevelop::Path& newName) { return renameUrl(project, oldName.toUrl(), newName.toUrl()); } bool KDevelop::copyUrl(const KDevelop::IProject* project, const QUrl& source, const QUrl& target) { IPlugin* vcsplugin=project->versionControlPlugin(); if(vcsplugin) { IBasicVersionControl* vcs=vcsplugin->extension(); // We have a vcs and the file/folder is controller, need to make the rename through vcs if(vcs->isVersionControlled(source)) { VcsJob* job=vcs->copy(source, target); if(job) { return job->exec(); } } } // Fallback for the case of no vcs, or not-vcs-managed file/folder auto job = KIO::copy(source, target); KJobWidgets::setWindow(job, QApplication::activeWindow()); return job->exec(); } bool KDevelop::copyPath(const KDevelop::IProject* project, const KDevelop::Path& source, const KDevelop::Path& target) { return copyUrl(project, source.toUrl(), target.toUrl()); } Path KDevelop::proposedBuildFolder(const Path& sourceFolder) { Path proposedBuildFolder; if (sourceFolder.path().contains(QStringLiteral("/src/"))) { const QString srcBuildPath = sourceFolder.path().replace(QStringLiteral("/src/"), QStringLiteral("/build/")); Q_ASSERT(!srcBuildPath.isEmpty()); if (QDir(srcBuildPath).exists()) { proposedBuildFolder = Path(srcBuildPath); } } if (!proposedBuildFolder.isValid()) { proposedBuildFolder = Path(sourceFolder, QStringLiteral("build")); } return proposedBuildFolder; } diff --git a/kdevplatform/shell/runtimecontroller.cpp b/kdevplatform/shell/runtimecontroller.cpp index b33617e098..5ef195fa39 100644 --- a/kdevplatform/shell/runtimecontroller.cpp +++ b/kdevplatform/shell/runtimecontroller.cpp @@ -1,165 +1,169 @@ /* Copyright 2017 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "runtimecontroller.h" #include #include #include #include #include #include #include "core.h" #include "uicontroller.h" #include "mainwindow.h" #include "debug.h" using namespace KDevelop; class IdentityRuntime : public IRuntime { + Q_OBJECT +public: QString name() const override { return i18n("Host System"); } void startProcess(KProcess *process) const override { #if QT_VERSION < 0x050600 connect(process, static_cast(&QProcess::error), #else connect(process, &QProcess::errorOccurred, #endif this, [](QProcess::ProcessError error) { qCWarning(SHELL) << "process finished with error:" << error; }); process->start(); } void startProcess(QProcess *process) const override { #if QT_VERSION < 0x050600 connect(process, static_cast(&QProcess::error), #else connect(process, &QProcess::errorOccurred, #endif this, [](QProcess::ProcessError error) { qCWarning(SHELL) << "process finished with error:" << error; }); process->start(); } KDevelop::Path pathInHost(const KDevelop::Path & runtimePath) const override { return runtimePath; } KDevelop::Path pathInRuntime(const KDevelop::Path & localPath) const override { return localPath; } void setEnabled(bool /*enabled*/) override {} QByteArray getenv(const QByteArray & varname) const override { return qgetenv(varname.constData()); } }; KDevelop::RuntimeController::RuntimeController(KDevelop::Core* core) : m_core(core) { const bool haveUI = (core->setupFlags() != Core::NoUi); if (haveUI) { m_runtimesMenu.reset(new QMenu()); } addRuntimes(new IdentityRuntime); setCurrentRuntime(m_runtimes.first()); if (haveUI) { setupActions(); } } KDevelop::RuntimeController::~RuntimeController() { m_currentRuntime->setEnabled(false); m_currentRuntime = nullptr; } void RuntimeController::setupActions() { // TODO not multi-window friendly, FIXME KActionCollection* ac = m_core->uiControllerInternal()->defaultMainWindow()->actionCollection(); auto action = new QAction(this); action->setStatusTip(i18n("Allows to select a runtime")); action->setMenu(m_runtimesMenu.data()); action->setIcon(QIcon::fromTheme(QStringLiteral("file-library-symbolic"))); auto updateActionText = [action](IRuntime* currentRuntime){ action->setText(i18n("Runtime: %1", currentRuntime->name())); }; connect(this, &RuntimeController::currentRuntimeChanged, action, updateActionText); updateActionText(m_currentRuntime); ac->addAction(QStringLiteral("switch_runtimes"), action); } void KDevelop::RuntimeController::initialize() { } KDevelop::IRuntime * KDevelop::RuntimeController::currentRuntime() const { Q_ASSERT(m_currentRuntime); return m_currentRuntime; } QVector KDevelop::RuntimeController::availableRuntimes() const { return m_runtimes; } void KDevelop::RuntimeController::setCurrentRuntime(KDevelop::IRuntime* runtime) { if (m_currentRuntime == runtime) return; Q_ASSERT(m_runtimes.contains(runtime)); if (m_currentRuntime) { m_currentRuntime->setEnabled(false); } qCDebug(SHELL) << "setting runtime..." << runtime->name() << "was" << m_currentRuntime; m_currentRuntime = runtime; m_currentRuntime->setEnabled(true); Q_EMIT currentRuntimeChanged(runtime); } void KDevelop::RuntimeController::addRuntimes(KDevelop::IRuntime * runtime) { if (!runtime->parent()) runtime->setParent(this); if (m_core->setupFlags() != Core::NoUi) { QAction* runtimeAction = new QAction(runtime->name(), m_runtimesMenu.data()); runtimeAction->setCheckable(true); connect(runtimeAction, &QAction::triggered, runtime, [this, runtime]() { setCurrentRuntime(runtime); }); connect(this, &RuntimeController::currentRuntimeChanged, runtimeAction, [runtimeAction, runtime](IRuntime* currentRuntime) { runtimeAction->setChecked(runtime == currentRuntime); }); connect(runtime, &QObject::destroyed, this, [this, runtimeAction](QObject* obj) { Q_ASSERT(m_currentRuntime != obj); m_runtimes.removeAll(qobject_cast(obj)); delete runtimeAction; }); m_runtimesMenu->addAction(runtimeAction); } else { connect(runtime, &QObject::destroyed, this, [this](QObject* obj) { Q_ASSERT(m_currentRuntime != obj); m_runtimes.removeAll(qobject_cast(obj)); }); } m_runtimes << runtime; } + +#include "runtimecontroller.moc" diff --git a/kdevplatform/tests/json/declarationvalidator.cpp b/kdevplatform/tests/json/declarationvalidator.cpp index 8908789f65..162bcbce09 100644 --- a/kdevplatform/tests/json/declarationvalidator.cpp +++ b/kdevplatform/tests/json/declarationvalidator.cpp @@ -1,87 +1,89 @@ /* This file is part of KDevelop Copyright 2012 Olivier de Gaalon This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "language/duchain/declaration.h" + #include "declarationvalidator.h" + +#include "language/duchain/declaration.h" #include "testsuite.h" #include "jsondeclarationtests.h" #include namespace KDevelop { class DeclarationValidatorPrivate { public: DeclarationValidatorPrivate() : testsPassed(true) {} bool testsPassed; }; QByteArray preprocess(QByteArray json) { int commentIndex = json.indexOf('#', 0); while (commentIndex > -1) { int commentEnd = json.indexOf('\n', commentIndex); if (commentEnd == -1) { json.truncate(commentIndex); break; } json.remove(commentIndex, commentEnd - commentIndex); commentIndex = json.indexOf('#', commentIndex); } return '{' + json + '}'; } DeclarationValidator::DeclarationValidator() : d(new DeclarationValidatorPrivate) { } DeclarationValidator::~DeclarationValidator() { } bool DeclarationValidator::testsPassed() { return d->testsPassed; } void DeclarationValidator::visit(DUContext*) { } void DeclarationValidator::visit(Declaration* declaration) { QJsonParseError error; const auto json = preprocess(declaration->comment()); QJsonDocument doc = QJsonDocument::fromJson(json, &error); if (error.error == 0) { QVariantMap testData = doc.toVariant().toMap(); if (!KDevelop::runTests(testData, declaration)) d->testsPassed = false; } else { d->testsPassed = false; QMessageLogger logger(declaration->topContext()->url().byteArray().constData(), declaration->range().start.line, nullptr); logger.warning() << "Error parsing JSON test data:" << error.errorString() << "at offset" << error.offset << "JSON input was:\n" << json; } } } diff --git a/kdevplatform/util/texteditorhelpers.cpp b/kdevplatform/util/texteditorhelpers.cpp index 3304ca0033..02c0530dbd 100644 --- a/kdevplatform/util/texteditorhelpers.cpp +++ b/kdevplatform/util/texteditorhelpers.cpp @@ -1,83 +1,83 @@ /* This file is part of the KDE project Copyright 2015 Maciej Cencora This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include - #include "texteditorhelpers.h" #include #include +#include + namespace KDevelop { namespace { // TODO: this is a hack, but Kate does not provide interface for this int lineHeight(const KTextEditor::View* view, int curLine) { KTextEditor::Cursor c(curLine, 0); int currentHeight = view->cursorToCoordinate(c).y(); c.setLine(curLine + 1); if (view->cursorToCoordinate(c).y() < 0) { c.setLine(curLine - 1); } return std::abs(view->cursorToCoordinate(c).y() - currentHeight); } } QRect KTextEditorHelpers::getItemBoundingRect(const KTextEditor::View* view, const KTextEditor::Range& itemRange) { QPoint startPoint = view->mapToGlobal(view->cursorToCoordinate(itemRange.start())); QPoint endPoint = view->mapToGlobal(view->cursorToCoordinate(itemRange.end())); endPoint.ry() += lineHeight(view, itemRange.start().line()); return QRect(startPoint, endPoint); } KTextEditor::Cursor KTextEditorHelpers::extractCursor(const QString& input, int* pathLength) { // ":ll:cc", ":ll" static const QRegularExpression pattern(QStringLiteral(":(\\d+)(?::(\\d+))?$")); // "#Lll", "#nll", "#ll" as e.g. seen with repo web links static const QRegularExpression pattern2(QStringLiteral("#(?:n|L|)(\\d+)$")); auto match = pattern.match(input); if (!match.hasMatch()) { match = pattern2.match(input); } if (!match.hasMatch()) { if (pathLength) *pathLength = input.length(); return KTextEditor::Cursor::invalid(); } int line = match.capturedRef(1).toInt() - 1; // captured(2) for pattern2 will yield null QString, toInt() thus 0, so no need for if-else // don't use an invalid column when the line is valid int column = qMax(0, match.captured(2).toInt() - 1); if (pathLength) *pathLength = match.capturedStart(0); return {line, column}; } } diff --git a/plugins/clang/clangparsejob.h b/plugins/clang/clangparsejob.h index a473cf2c79..971b8944dc 100644 --- a/plugins/clang/clangparsejob.h +++ b/plugins/clang/clangparsejob.h @@ -1,63 +1,64 @@ /* This file is part of KDevelop Copyright 2013 Olivier de Gaalon Copyright 2013 Milian Wolff This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CLANGPARSEJOB_H #define CLANGPARSEJOB_H #include #include #include "duchain/clangparsingenvironment.h" #include "duchain/unsavedfile.h" class ClangSupport; class ParseSessionData; class ClangParseJob : public KDevelop::ParseJob { + Q_OBJECT public: ClangParseJob(const KDevelop::IndexedString& url, KDevelop::ILanguageSupport* languageSupport); ClangSupport* clang() const; enum CustomFeatures { Rescheduled = (KDevelop::TopDUContext::LastFeature << 1), AttachASTWithoutUpdating = (Rescheduled << 1), ///< Used when context is up to date, but has no AST attached. UpdateHighlighting = (AttachASTWithoutUpdating << 1) ///< Used when we only need to update highlighting }; protected: void run(ThreadWeaver::JobPointer self, ThreadWeaver::Thread *thread) override; const KDevelop::ParsingEnvironment* environment() const override; private: QExplicitlySharedDataPointer createSessionData() const; ClangParsingEnvironment m_environment; QVector m_unsavedFiles; bool m_tuDocumentIsUnsaved = false; QHash m_unsavedRevisions; }; #endif // CLANGPARSEJOB_H diff --git a/plugins/clang/duchain/macronavigationcontext.h b/plugins/clang/duchain/macronavigationcontext.h index b4ce69c632..606f9e8a49 100644 --- a/plugins/clang/duchain/macronavigationcontext.h +++ b/plugins/clang/duchain/macronavigationcontext.h @@ -1,50 +1,51 @@ /* Copyright 2007 David Nolden Copyright 2014 Kevin Funk This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef MACRONAVIGATIONCONTEXT_H #define MACRONAVIGATIONCONTEXT_H #include "clangprivateexport.h" #include "macrodefinition.h" #include #include #include class KDEVCLANGPRIVATE_EXPORT MacroNavigationContext : public KDevelop::AbstractNavigationContext { + Q_OBJECT public: explicit MacroNavigationContext(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation = KDevelop::DocumentCursor::invalid()); ~MacroNavigationContext() override; QString html(bool shorten) override; QString name() const override; private: QString retrievePreprocessedBody(const KDevelop::DocumentCursor& expansionLocation) const; const MacroDefinition::Ptr m_macro; QString m_body; QPointer m_widget; }; #endif diff --git a/plugins/clang/duchain/missingincludepathproblem.cpp b/plugins/clang/duchain/missingincludepathproblem.cpp index 7d648e88fb..c73eb09997 100644 --- a/plugins/clang/duchain/missingincludepathproblem.cpp +++ b/plugins/clang/duchain/missingincludepathproblem.cpp @@ -1,116 +1,118 @@ /* * This file is part of KDevelop * * Copyright 2014 Sergey Kalinichev * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * * This program 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 this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "missingincludepathproblem.h" #include #include #include #include #include namespace { void openConfigurationPage(const QString& path) { KDevelop::IDefinesAndIncludesManager::manager()->openConfigurationDialog(path); } } class AddCustomIncludePathAction : public KDevelop::IAssistantAction { Q_OBJECT public: explicit AddCustomIncludePathAction(const KDevelop::IndexedString& path) : m_path(path) {} QString description() const override { return i18n("Add Custom Include Path"); } void execute() override { openConfigurationPage(m_path.str()); emit executed(this); } private: KDevelop::IndexedString m_path; }; class OpenProjectForFileAssistant : public KDevelop::IAssistantAction { + Q_OBJECT public: explicit OpenProjectForFileAssistant(const KDevelop::IndexedString& path) : m_path(path) {} QString description() const override { return i18n("Open Project"); }; void execute() override { KDevelop::ICore::self()->projectController()->openProjectForUrl(m_path.toUrl()); emit executed(this); } private: KDevelop::IndexedString m_path; }; class MissingIncludePathAssistant : public ClangFixitAssistant { + Q_OBJECT public: MissingIncludePathAssistant(const QString& title, const KDevelop::IndexedString& path) : ClangFixitAssistant(title, {}) , m_path(path) {} void createActions() override { auto project = KDevelop::ICore::self()->projectController()->findProjectForUrl(m_path.toUrl()); if (!project) { addAction(KDevelop::IAssistantAction::Ptr(new OpenProjectForFileAssistant(m_path))); } addAction(KDevelop::IAssistantAction::Ptr(new AddCustomIncludePathAction(m_path))); } private: KDevelop::IndexedString m_path; }; MissingIncludePathProblem::MissingIncludePathProblem(CXDiagnostic diagnostic, CXTranslationUnit unit) : ClangProblem(diagnostic, unit) {} KDevelop::IAssistant::Ptr MissingIncludePathProblem::solutionAssistant() const { return KDevelop::IAssistant::Ptr(new MissingIncludePathAssistant(description(), finalLocation().document)); } #include "missingincludepathproblem.moc" diff --git a/plugins/clang/duchain/navigationwidget.cpp b/plugins/clang/duchain/navigationwidget.cpp index d79c811ec5..a7624eae12 100644 --- a/plugins/clang/duchain/navigationwidget.cpp +++ b/plugins/clang/duchain/navigationwidget.cpp @@ -1,128 +1,132 @@ /* * This file is part of KDevelop * Copyright 2014 Milian Wolff * Copyright 2014 Kevin Funk * * This program 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 this program. If not, see . */ #include "navigationwidget.h" #include "macronavigationcontext.h" #include "types/classspecializationtype.h" #include #include #include using namespace KDevelop; class DeclarationNavigationContext : public AbstractDeclarationNavigationContext { + Q_OBJECT public: using AbstractDeclarationNavigationContext::AbstractDeclarationNavigationContext; void htmlIdentifiedType(AbstractType::Ptr type, const IdentifiedType* idType) override { AbstractDeclarationNavigationContext::htmlIdentifiedType(type, idType); if (auto cst = dynamic_cast(type.data())) { modifyHtml() += QStringLiteral("< ").toHtmlEscaped(); bool first = true; const auto& templateParameters = cst->templateParameters(); for (const auto& type : templateParameters) { if (first) { first = false; } else { modifyHtml() += QStringLiteral(", "); } eventuallyMakeTypeLinks(type.abstractType()); } modifyHtml() += QStringLiteral(" >").toHtmlEscaped(); } } }; class IncludeNavigationContext : public KDevelop::AbstractIncludeNavigationContext { + Q_OBJECT public: IncludeNavigationContext(const KDevelop::IncludeItem& item, const KDevelop::TopDUContextPointer& topContext); protected: bool filterDeclaration(KDevelop::Declaration* decl) override; }; IncludeNavigationContext::IncludeNavigationContext(const IncludeItem& item, const KDevelop::TopDUContextPointer& topContext) : AbstractIncludeNavigationContext(item, topContext, StandardParsingEnvironment) {} bool IncludeNavigationContext::filterDeclaration(Declaration* decl) { QString declId = decl->identifier().identifier().str(); //filter out forward-declarations and macro-expansions without a range //And filter out declarations with reserved identifiers return !decl->qualifiedIdentifier().toString().isEmpty() && !decl->range().isEmpty() && !decl->isForwardDeclaration() && !(declId.startsWith(QLatin1String("__")) || (declId.startsWith(QLatin1Char('_')) && declId.length() > 1 && declId[1].isUpper()) ); } ClangNavigationWidget::ClangNavigationWidget(const DeclarationPointer& declaration, KDevelop::AbstractNavigationWidget::DisplayHints hints) : AbstractNavigationWidget() { setDisplayHints(hints); if (auto macro = declaration.dynamicCast()) { initBrowser(200); setContext(NavigationContextPointer(new MacroNavigationContext(macro))); } else { initBrowser(400); setContext(NavigationContextPointer(new DeclarationNavigationContext(declaration, {}))); } } ClangNavigationWidget::ClangNavigationWidget(const MacroDefinition::Ptr& macro, const KDevelop::DocumentCursor& expansionLocation, KDevelop::AbstractNavigationWidget::DisplayHints hints) : AbstractNavigationWidget() { setDisplayHints(hints); initBrowser(400); setContext(NavigationContextPointer(new MacroNavigationContext(macro, expansionLocation))); } ClangNavigationWidget::ClangNavigationWidget(const IncludeItem& includeItem, const KDevelop::TopDUContextPointer& topContext, const QString& htmlPrefix, const QString& htmlSuffix, KDevelop::AbstractNavigationWidget::DisplayHints hints) : AbstractNavigationWidget() { setDisplayHints(hints); initBrowser(200); //The first context is registered so it is kept alive by the shared-pointer mechanism auto context = new IncludeNavigationContext(includeItem, topContext); context->setPrefixSuffix(htmlPrefix, htmlSuffix); setContext(NavigationContextPointer(context)); } QString ClangNavigationWidget::shortDescription(const IncludeItem& includeItem) { IncludeNavigationContext ctx(includeItem, {}); return ctx.html(true); } + +#include "navigationwidget.moc" diff --git a/plugins/clazy/kdevclazy.json b/plugins/clazy/kdevclazy.json index cbc2180df8..8a25f7a2ac 100644 --- a/plugins/clazy/kdevclazy.json +++ b/plugins/clazy/kdevclazy.json @@ -1,49 +1,51 @@ { "KPlugin": { "Authors": [ { "Name": "Anton Anikin", "Name[x-test]": "xxAnton Anikinxx" } ], "Category": "Analyzers", "Description": "This plugin integrates Clazy to KDevelop", "Description[ca@valencia]": "Aquest connector integra el Clazy al KDevelop", "Description[ca]": "Aquest connector integra el Clazy al KDevelop", "Description[cs]": "Tento modul integruje podporu pro Clazy v KDevelop", "Description[de]": "Dieses Modul integriert Clazy in KDevelop", "Description[es]": "Este complemento integra Clazy en KDevelop", "Description[fr]": "Ce module externe intègre Clazy dans KDevelop", "Description[it]": "Questa estensione integra Clazy in KDevelop", "Description[nl]": "Deze plug-in integreert Clazy in KDevelop", "Description[pl]": "Ta wtyczka udostępnia obsługę Clazy w KDevelopie", "Description[pt]": "Este 'plugin' integra o Clazy no KDevelop", "Description[pt_BR]": "Este plugin integra o Clazy ao KDevelop", + "Description[sk]": "Tento plugin integruje Clazy do KDevelop.", "Description[sv]": "Insticksprogrammet integrerar Clazy i KDevelop", "Description[uk]": "За допомогою цього додатка можна інтегрувати Clazy до KDevelop", "Description[x-test]": "xxThis plugin integrates Clazy to KDevelopxx", "Icon": "clazy", "Id": "kdevclazy", "License": "GPL", "Name": "Clazy Support", "Name[ca@valencia]": "Implementació de Clazy", "Name[ca]": "Implementació de Clazy", "Name[cs]": "Podpora Clazy", "Name[de]": "Clazy-Unterstützung", "Name[es]": "Implementación de Clazy", "Name[fr]": "Prise en charge de Clazy", "Name[it]": "Supporto per Clazy", "Name[nl]": "Clazy-ondersteuning", "Name[pl]": "Obsługa Clazy", "Name[pt]": "Suporte para o Clazy", "Name[pt_BR]": "Suporte à Clazy", + "Name[sk]": "Podpora Clazy", "Name[sv]": "Clazy-stöd", "Name[uk]": "Підтримка Clazy", "Name[x-test]": "xxClazy Supportxx", "ServiceTypes": [ "KDevelop/Plugin" ] }, "X-KDevelop-Category": "Global", "X-KDevelop-Mode": "GUI" } diff --git a/plugins/clazy/plugin.h b/plugins/clazy/plugin.h index 68dc82c4e7..4834a473b6 100644 --- a/plugins/clazy/plugin.h +++ b/plugins/clazy/plugin.h @@ -1,91 +1,91 @@ /* This file is part of KDevelop Copyright 2018 Anton Anikin This program 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. This program 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 this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef KDEVCLAZY_PLUGIN_H #define KDEVCLAZY_PLUGIN_H #include "job.h" #include class KJob; namespace KDevelop { class IProject; } namespace Clazy { class ChecksDB; class ProblemModel; class Plugin : public KDevelop::IPlugin { Q_OBJECT public: - Plugin(QObject* parent, const QVariantList& = QVariantList()); + explicit Plugin(QObject* parent, const QVariantList& = QVariantList()); ~Plugin() override; int configPages() const override { return 1; } KDevelop::ConfigPage* configPage(int number, QWidget* parent) override; int perProjectConfigPages() const override { return 1; } KDevelop::ConfigPage* perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent) override; KDevelop::ContextMenuExtension contextMenuExtension(KDevelop::Context* context, QWidget* parent) override; void runClazy(KDevelop::IProject* project, const QString& path); bool isRunning() const; QSharedPointer checksDB() const; private: void killClazy(); void raiseProblemsView(); void raiseOutputView(); void updateActions(); void projectClosed(KDevelop::IProject* project); void runClazy(bool checkProject); void result(KJob* job); void reloadDB(); private: Job* m_job; KDevelop::IProject* m_project; ProblemModel* m_model; QAction* m_menuActionFile; QAction* m_menuActionProject; QAction* m_contextActionFile; QAction* m_contextActionProject; QAction* m_contextActionProjectItem; QSharedPointer m_db; }; } #endif diff --git a/plugins/cmake/cmakecodecompletionmodel.h b/plugins/cmake/cmakecodecompletionmodel.h index e013133b07..8e47448cf1 100644 --- a/plugins/cmake/cmakecodecompletionmodel.h +++ b/plugins/cmake/cmakecodecompletionmodel.h @@ -1,51 +1,52 @@ /* KDevelop CMake Support * * Copyright 2008 Aleix Pol * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKECODECOMPLETION_H #define CMAKECODECOMPLETION_H #include #include #include #include class CMakeDocumentation; namespace KTextEditor { class Document; class Range; } class CMakeCodeCompletionModel : public KTextEditor::CodeCompletionModel { + Q_OBJECT public: explicit CMakeCodeCompletionModel(QObject *parent); void completionInvoked(KTextEditor::View* view, const KTextEditor::Range& range, InvocationType invocationType) override; QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const override; void executeCompletionItem(KTextEditor::View* view, const KTextEditor::Range& word, const QModelIndex& index) const override; private: enum Type { Command, Variable, Macro, Path, Target }; Type indexType(int row) const; static QVector s_commands; QList< KDevelop::IndexedDeclaration > m_declarations; bool m_inside; QStringList m_paths; }; #endif diff --git a/plugins/cmake/cmakeextraargumentshistory.cpp b/plugins/cmake/cmakeextraargumentshistory.cpp index 14f5e87b15..344c57ff0a 100644 --- a/plugins/cmake/cmakeextraargumentshistory.cpp +++ b/plugins/cmake/cmakeextraargumentshistory.cpp @@ -1,70 +1,70 @@ /* KDevelop CMake Support * * Copyright 2016 René J.V. Bertin * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ +#include "cmakeextraargumentshistory.h" + #include #include -#include "cmakeextraargumentshistory.h" - namespace { const int maxExtraArgumentsInHistory = 15; } CMakeExtraArgumentsHistory::CMakeExtraArgumentsHistory(KComboBox* widget) : m_arguments(widget) { if (m_arguments) { KConfigGroup config = KSharedConfig::openConfig()->group("CMakeBuildDirChooser"); QStringList lastExtraArguments = config.readEntry("LastExtraArguments", QStringList()); m_arguments->addItem(QString()); m_arguments->addItems(lastExtraArguments); m_arguments->setInsertPolicy(QComboBox::InsertAtTop); KCompletion *comp = m_arguments->completionObject(); KComboBox::connect(m_arguments, static_cast(&KComboBox::returnPressed), comp, static_cast(&KCompletion::addItem)); comp->insertItems(lastExtraArguments); } else { qFatal("CMakeExtraArgumentsHistory initialised with invalid widget"); } } CMakeExtraArgumentsHistory::~CMakeExtraArgumentsHistory() { KConfigGroup config = KSharedConfig::openConfig()->group("CMakeBuildDirChooser"); config.writeEntry("LastExtraArguments", list()); config.sync(); } QStringList CMakeExtraArgumentsHistory::list() const { QStringList list; if (!m_arguments->currentText().isEmpty()) { list << m_arguments->currentText(); } for (int i = 0; i < qMin(maxExtraArgumentsInHistory, m_arguments->count()); ++i) { if (!m_arguments->itemText(i).isEmpty() && (m_arguments->currentText() != m_arguments->itemText(i))) { list << m_arguments->itemText(i); } } return list; } diff --git a/plugins/cmake/cmakehelpdocumentation.h b/plugins/cmake/cmakehelpdocumentation.h index ccf4062995..a0a7302791 100644 --- a/plugins/cmake/cmakehelpdocumentation.h +++ b/plugins/cmake/cmakehelpdocumentation.h @@ -1,36 +1,37 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKEHELPDOCUMENTATION_H #define CMAKEHELPDOCUMENTATION_H #include class CMakeHomeDocumentation : public KDevelop::IDocumentation { + Q_OBJECT public: KDevelop::IDocumentationProvider* provider() const override; QString name() const override; QString description() const override { return name(); } QWidget* documentationWidget ( KDevelop::DocumentationFindWidget* findWidget, QWidget* parent = nullptr ) override; }; #endif diff --git a/plugins/cmake/cmakenavigationwidget.cpp b/plugins/cmake/cmakenavigationwidget.cpp index 5219e2af0b..0f985d10a3 100644 --- a/plugins/cmake/cmakenavigationwidget.cpp +++ b/plugins/cmake/cmakenavigationwidget.cpp @@ -1,61 +1,65 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakenavigationwidget.h" #include #include #include using namespace KDevelop; class CMakeNavigationContext: public AbstractNavigationContext { + Q_OBJECT public: CMakeNavigationContext(const TopDUContextPointer& top, const QString& name, const QString& html) : AbstractNavigationContext(top, nullptr), mName(name), mDescription(html) {} QString name() const override { return mName; } QString html(bool shorten = false) override { Q_UNUSED(shorten); return mDescription; } private: QString mName; QString mDescription; }; class CMakeDeclarationNavigationContext: public AbstractDeclarationNavigationContext { + Q_OBJECT public: CMakeDeclarationNavigationContext(const DeclarationPointer& decl, const TopDUContextPointer& top) : AbstractDeclarationNavigationContext(decl, top) {} }; CMakeNavigationWidget::CMakeNavigationWidget(const TopDUContextPointer& top, const IDocumentation::Ptr& doc) { setContext(NavigationContextPointer(new CMakeNavigationContext(top, doc->name(), doc->description()))); } CMakeNavigationWidget::CMakeNavigationWidget(const KDevelop::DUChainPointer< KDevelop::TopDUContext >& top, KDevelop::Declaration* decl) { setContext(NavigationContextPointer(new CMakeDeclarationNavigationContext(DeclarationPointer(decl), top))); } + +#include "cmakenavigationwidget.moc" diff --git a/plugins/cmake/cmakenavigationwidget.h b/plugins/cmake/cmakenavigationwidget.h index b21ea40581..d73c20cd55 100644 --- a/plugins/cmake/cmakenavigationwidget.h +++ b/plugins/cmake/cmakenavigationwidget.h @@ -1,37 +1,38 @@ /* KDevelop CMake Support * * Copyright 2009 Aleix Pol * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #ifndef CMAKENAVIGATIONWIDGET_H #define CMAKENAVIGATIONWIDGET_H #include #include #include namespace KDevelop { class IDocumentation; } class CMakeNavigationWidget : public KDevelop::AbstractNavigationWidget { + Q_OBJECT public: CMakeNavigationWidget(const KDevelop::TopDUContextPointer& top, const KDevelop::IDocumentation::Ptr& doc); CMakeNavigationWidget(const KDevelop::TopDUContextPointer& top, KDevelop::Declaration* decl); }; #endif // CMAKENAVIGATIONWIDGET_H diff --git a/plugins/cmake/tests/kdevprojectopen.cpp b/plugins/cmake/tests/kdevprojectopen.cpp index 991106dcc6..65f04d0978 100644 --- a/plugins/cmake/tests/kdevprojectopen.cpp +++ b/plugins/cmake/tests/kdevprojectopen.cpp @@ -1,94 +1,97 @@ /* This file is part of KDevelop Copyright 2013 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include -#include -#include +#include "kdevprojectopen.h" + #include #include #include -#include "kdevprojectopen.h" #include "testhelpers.h" + +#include +#include + +#include #include #include using namespace KDevelop; KDevProjectOpen::KDevProjectOpen(QObject* parent) : QObject(parent) { AutoTestShell::init(); TestCore::initialize(); cleanup(); connect(ICore::self()->projectController(), &IProjectController::projectOpened, this, &KDevProjectOpen::projectDone); } void KDevProjectOpen::cleanup() { foreach(IProject* p, ICore::self()->projectController()->projects()) { ICore::self()->projectController()->closeProject(p); } Q_ASSERT(ICore::self()->projectController()->projects().isEmpty()); } void KDevProjectOpen::openProject(const QUrl& path) { const TestProjectPaths paths = projectPaths(path.toLocalFile()); defaultConfigure(paths); m_toOpen++; ICore::self()->projectController()->openProject(paths.projectFile.toUrl()); } void KDevProjectOpen::projectDone(IProject* ) { m_toOpen--; if(m_toOpen==0) { cleanup(); qApp->exit(); } } int main(int argc, char** argv) { QApplication app(argc, argv); KAboutData aboutData( QStringLiteral("kdevprojectopen"), i18n( "KDevelop" ), QStringLiteral("0.99"), i18n("opens a project then closes it, debugging tool"), KAboutLicense::GPL, i18n( "Copyright 1999-2012, The KDevelop developers" ), QString(), QStringLiteral("http://www.kdevelop.org/") ); aboutData.addAuthor( i18n("Aleix Pol Gonzalez"), i18n( "" ), QStringLiteral("aleixpol@kde.org") ); KAboutData::setApplicationData(aboutData); QCommandLineParser parser; aboutData.setupCommandLine(&parser); parser.addPositionalArgument(QStringLiteral("projects"), i18n("Projects to load")); parser.process(app); aboutData.processCommandLine(&parser); if(parser.positionalArguments().isEmpty()) { parser.showHelp(1); } KDevProjectOpen opener; foreach(const QString& arg, parser.positionalArguments()) { opener.openProject(QUrl::fromUserInput(arg)); } return app.exec(); } diff --git a/plugins/cmakebuilder/cmakebuilder.cpp b/plugins/cmakebuilder/cmakebuilder.cpp index c4142fa2cf..194e1fcdde 100644 --- a/plugins/cmakebuilder/cmakebuilder.cpp +++ b/plugins/cmakebuilder/cmakebuilder.cpp @@ -1,269 +1,270 @@ /* KDevelop CMake Support * * Copyright 2006-2007 Andreas Pakulat * * This program 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. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */ #include "cmakebuilder.h" #include "debug.h" #include #include #include #include #include #include #include #include "cmakejob.h" #include "prunejob.h" #include "cmakebuilderpreferences.h" #include "cmakeutils.h" #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(CMakeBuilderFactory, "kdevcmakebuilder.json", registerPlugin(); ) class ErrorJob : public KJob { + Q_OBJECT public: ErrorJob(QObject* parent, const QString& error) : KJob(parent) , m_error(error) {} void start() override { setError(!m_error.isEmpty()); setErrorText(m_error); emitResult(); } private: QString m_error; }; CMakeBuilder::CMakeBuilder(QObject *parent, const QVariantList &) : KDevelop::IPlugin(QStringLiteral("kdevcmakebuilder"), parent) { addBuilder(QStringLiteral("Makefile"), QStringList{QStringLiteral("Unix Makefiles"), QStringLiteral("NMake Makefiles"), QStringLiteral("MinGW Makefiles")}, core()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IMakeBuilder"))); addBuilder(QStringLiteral("build.ninja"), QStringList(QStringLiteral("Ninja")), core()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IProjectBuilder"), QStringLiteral("KDevNinjaBuilder"))); } CMakeBuilder::~CMakeBuilder() { } void CMakeBuilder::addBuilder(const QString& neededfile, const QStringList& generators, KDevelop::IPlugin* i) { if( i ) { IProjectBuilder* b = i->extension(); if( b ) { m_builders[neededfile] = b; for (const QString& gen : generators) { m_buildersForGenerator[gen] = b; } // can't use new signal/slot syntax here, IProjectBuilder is not a QObject connect(i, SIGNAL(built(KDevelop::ProjectBaseItem*)), this, SIGNAL(built(KDevelop::ProjectBaseItem*))); connect(i, SIGNAL(failed(KDevelop::ProjectBaseItem*)), this, SIGNAL(failed(KDevelop::ProjectBaseItem*))); connect(i, SIGNAL(cleaned(KDevelop::ProjectBaseItem*)), this, SIGNAL(cleaned(KDevelop::ProjectBaseItem*))); connect(i, SIGNAL(installed(KDevelop::ProjectBaseItem*)), this, SIGNAL(installed(KDevelop::ProjectBaseItem*))); qCDebug(KDEV_CMAKEBUILDER) << "Added builder " << i->metaObject()->className() << "for" << neededfile; } else qCWarning(KDEV_CMAKEBUILDER) << "Couldn't add" << i->metaObject()->className(); } } KJob* CMakeBuilder::build(KDevelop::ProjectBaseItem *dom) { KDevelop::IProject* p = dom->project(); IProjectBuilder* builder = builderForProject(p); if( builder ) { bool valid; KJob* configure = checkConfigureJob(dom->project(), valid); KJob* build = nullptr; if(dom->file()) { IMakeBuilder* makeBuilder = dynamic_cast(builder); if (!makeBuilder) { return new ErrorJob(this, i18n("Could not find the make builder. Check your installation")); } KDevelop::ProjectFileItem* file = dom->file(); int lastDot = file->text().lastIndexOf(QLatin1Char('.')); QString target = file->text().mid(0, lastDot) + QLatin1String(".o"); build = makeBuilder->executeMakeTarget(dom->parent(), target); qCDebug(KDEV_CMAKEBUILDER) << "create build job for target" << build << dom << target; } qCDebug(KDEV_CMAKEBUILDER) << "Building with" << builder; if (!build) { build = builder->build(dom); } if( configure ) { qCDebug(KDEV_CMAKEBUILDER) << "creating composite job"; KDevelop::BuilderJob* builderJob = new KDevelop::BuilderJob; builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, dom ); builderJob->addCustomJob( KDevelop::BuilderJob::Build, build, dom ); builderJob->updateJobName(); build = builderJob; } return build; } return new ErrorJob(this, i18n("Could not find a builder for %1", p->name())); } KJob* CMakeBuilder::clean(KDevelop::ProjectBaseItem *dom) { IProjectBuilder* builder = builderForProject(dom->project()); if( builder ) { bool valid; KJob* configure = checkConfigureJob(dom->project(), valid); KDevelop::ProjectBaseItem* item = dom; if(dom->file()) //It doesn't work to compile a file item=(KDevelop::ProjectBaseItem*) dom->parent(); qCDebug(KDEV_CMAKEBUILDER) << "Cleaning with" << builder; KJob* clean = builder->clean(item); if( configure ) { KDevelop::BuilderJob* builderJob = new KDevelop::BuilderJob; builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, item ); builderJob->addCustomJob( KDevelop::BuilderJob::Clean, clean, item ); builderJob->updateJobName(); clean = builderJob; } return clean; } return new ErrorJob(this, i18n("Could not find a builder for %1", dom->project()->name())); } KJob* CMakeBuilder::install(KDevelop::ProjectBaseItem *dom, const QUrl &installPrefix) { IProjectBuilder* builder = builderForProject(dom->project()); if( builder ) { bool valid; KJob* configure = checkConfigureJob(dom->project(), valid); KDevelop::ProjectBaseItem* item = dom; if(dom->file()) item=(KDevelop::ProjectBaseItem*) dom->parent(); qCDebug(KDEV_CMAKEBUILDER) << "Installing with" << builder; KJob* install = builder->install(item, installPrefix); if( configure ) { KDevelop::BuilderJob* builderJob = new KDevelop::BuilderJob; builderJob->addCustomJob( KDevelop::BuilderJob::Configure, configure, item ); builderJob->addCustomJob( KDevelop::BuilderJob::Install, install, item ); builderJob->updateJobName(); install = builderJob; } return install; } return new ErrorJob(this, i18n("Could not find a builder for %1", dom->project()->name())); } KJob* CMakeBuilder::checkConfigureJob(KDevelop::IProject* project, bool& valid) { valid = false; KJob* configure = nullptr; if( CMake::checkForNeedingConfigure(project) ) { configure = this->configure(project); } else if( CMake::currentBuildDir(project).isEmpty() ) { return new ErrorJob(this, i18n("No Build Directory configured, cannot install")); } valid = true; return configure; } KJob* CMakeBuilder::configure( KDevelop::IProject* project ) { if( CMake::currentBuildDir( project ).isEmpty() ) { return new ErrorJob(this, i18n("No Build Directory configured, cannot configure")); } CMakeJob* job = new CMakeJob(this); job->setProject(project); connect(job, &KJob::result, this, [this, project] { emit configured(project); }); return job; } KJob* CMakeBuilder::prune( KDevelop::IProject* project ) { return new PruneJob(project); } KDevelop::IProjectBuilder* CMakeBuilder::builderForProject(KDevelop::IProject* p) const { QString builddir = CMake::currentBuildDir( p ).toLocalFile(); QMap::const_iterator it = m_builders.constBegin(), itEnd = m_builders.constEnd(); for(; it!=itEnd; ++it) { if (QFile::exists(builddir+QLatin1Char('/')+it.key())) return it.value(); } //It means that it still has to be generated, so use the builder for //the generator we use return m_buildersForGenerator[CMake::defaultGenerator()]; } QList< KDevelop::IProjectBuilder* > CMakeBuilder::additionalBuilderPlugins( KDevelop::IProject* project ) const { IProjectBuilder* b = builderForProject( project ); QList< KDevelop::IProjectBuilder* > ret; if(b) ret << b; return ret; } int CMakeBuilder::configPages() const { return 1; } KDevelop::ConfigPage* CMakeBuilder::configPage(int number, QWidget* parent) { if (number == 0) { return new CMakeBuilderPreferences(this, parent); } return nullptr; } #include "cmakebuilder.moc" diff --git a/plugins/cppcheck/problemmodel.h b/plugins/cppcheck/problemmodel.h index 70013e0f5e..681338f7e2 100644 --- a/plugins/cppcheck/problemmodel.h +++ b/plugins/cppcheck/problemmodel.h @@ -1,71 +1,72 @@ /* This file is part of KDevelop Copyright 2017 Anton Anikin This program 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. This program 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 this program; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #pragma once #include namespace KDevelop { class IProject; } namespace cppcheck { class Plugin; class ProblemModel : public KDevelop::ProblemModel { + Q_OBJECT public: explicit ProblemModel(Plugin* plugin); ~ProblemModel() override; KDevelop::IProject* project() const; void addProblems(const QVector& problems); void setProblems(); void reset(); void reset(KDevelop::IProject* project, const QString& path); void show(); void forceFullUpdate() override; private: void fixProblemFinalLocation(KDevelop::IProblem::Ptr problem); bool problemExists(KDevelop::IProblem::Ptr newProblem); void setMessage(const QString& message); using KDevelop::ProblemModel::setProblems; Plugin* m_plugin; KDevelop::IProject* m_project; QString m_path; KDevelop::DocumentRange m_pathLocation; QVector m_problems; }; } diff --git a/plugins/cppcheck/tests/test_cppcheckjob.cpp b/plugins/cppcheck/tests/test_cppcheckjob.cpp index ebd5ecd167..5b50b6b321 100644 --- a/plugins/cppcheck/tests/test_cppcheckjob.cpp +++ b/plugins/cppcheck/tests/test_cppcheckjob.cpp @@ -1,91 +1,91 @@ /************************************************************************************* * Copyright 2016 (C) Anton Anikin * * * * This program 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. * * * * This program 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 this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ +#include "test_cppcheckjob.h" + #include #include #include -#include "test_cppcheckjob.h" - #include "job.h" #include "parameters.h" using namespace KDevelop; using namespace cppcheck; class JobTester : public Job { public: explicit JobTester(const Parameters& params) : Job(params) {} using Job::postProcessStdout; using Job::postProcessStderr; QString standardOutput() const { return m_standardOutput.join('\n'); } QString xmlOutput() const { return m_xmlOutput.join('\n'); } }; void TestCppcheckJob::initTestCase() { AutoTestShell::init({"kdevcppcheck"}); TestCore::initialize(Core::NoUi); } void TestCppcheckJob::cleanupTestCase() { TestCore::shutdown(); } void TestCppcheckJob::testJob() { QStringList stdoutOutput = { "Checking source1.cpp...", "1/2 files checked 50% done", "Checking source2.cpp...", "2/2 files checked 50% done" }; QStringList stderrOutput = { "(information) Couldn't find path given by -I '/missing_include_dir_1/'", "(information) Couldn't find path given by -I '/missing_include_dir_2/'", "", "", " ", " ", " ", " ", "" }; Parameters jobParams; JobTester jobTester(jobParams); jobTester.postProcessStderr(stderrOutput); jobTester.postProcessStdout(stdoutOutput); // move non-XML elements from stderrOutput stdoutOutput.push_front(stderrOutput[1]); stdoutOutput.push_front(stderrOutput[0]); stderrOutput.pop_front(); stderrOutput.pop_front(); QCOMPARE(jobTester.standardOutput(), stdoutOutput.join('\n')); QCOMPARE(jobTester.xmlOutput(), stderrOutput.join('\n')); } QTEST_GUILESS_MAIN(TestCppcheckJob) diff --git a/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp b/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp index 32a289eac6..a046fb6e3a 100644 --- a/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp +++ b/plugins/custom-definesandincludes/kcm_widget/definesandincludesconfigpage.cpp @@ -1,92 +1,92 @@ /************************************************************************ * * * Copyright 2010 Andreas Pakulat * * * * This program 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 or version 3 of the License, or * * (at your option) any later version. * * * * This program 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 this program; if not, see . * ************************************************************************/ +#include "definesandincludesconfigpage.h" + #include #include #include "projectpathswidget.h" #include "customdefinesandincludes.h" #include "../compilerprovider/compilerprovider.h" #include #include #include #include #include -#include "definesandincludesconfigpage.h" - DefinesAndIncludesConfigPage::DefinesAndIncludesConfigPage(KDevelop::IPlugin* plugin, const KDevelop::ProjectConfigOptions& options, QWidget* parent) : ProjectConfigPage(plugin, options, parent) { QVBoxLayout* layout = new QVBoxLayout( this ); configWidget = new ProjectPathsWidget( this ); configWidget->setProject( project() ); connect(configWidget, &ProjectPathsWidget::changed, this, &DefinesAndIncludesConfigPage::changed); layout->addWidget( configWidget ); } DefinesAndIncludesConfigPage::~DefinesAndIncludesConfigPage() { } void DefinesAndIncludesConfigPage::loadFrom( KConfig* cfg ) { configWidget->clear(); auto settings = SettingsManager::globalInstance(); configWidget->setPaths( settings->readPaths( cfg ) ); } void DefinesAndIncludesConfigPage::saveTo(KConfig* cfg, KDevelop::IProject*) { auto settings = SettingsManager::globalInstance(); settings->writePaths( cfg, configWidget->paths() ); if ( settings->needToReparseCurrentProject( cfg ) ) { KDevelop::ICore::self()->projectController()->reparseProject(project(), true); } } void DefinesAndIncludesConfigPage::reset() { ProjectConfigPage::reset(); loadFrom(CustomDefinesAndIncludes::self()->config()); } void DefinesAndIncludesConfigPage::apply() { ProjectConfigPage::apply(); saveTo(CustomDefinesAndIncludes::self()->config(), project()); } QString DefinesAndIncludesConfigPage::name() const { return i18n("Language Support"); } QString DefinesAndIncludesConfigPage::fullName() const { return i18n("Configure Language Support"); } QIcon DefinesAndIncludesConfigPage::icon() const { return QIcon::fromTheme(QStringLiteral("kdevelop")); } diff --git a/plugins/debuggercommon/dialogs/selectcoredialog.h b/plugins/debuggercommon/dialogs/selectcoredialog.h index bbd1eaa6c8..5e059bf190 100644 --- a/plugins/debuggercommon/dialogs/selectcoredialog.h +++ b/plugins/debuggercommon/dialogs/selectcoredialog.h @@ -1,45 +1,46 @@ /* * GDB Debugger Support * * Copyright 2009 Niko Sams * * This program 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. * * This program 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 this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef SELECTCOREDIALOG_H #define SELECTCOREDIALOG_H #include #include #include "ui_selectcoredialog.h" namespace KDevMI { class SelectCoreDialog : public QDialog { + Q_OBJECT public: explicit SelectCoreDialog(QWidget *parent = nullptr); QUrl executableFile() const; QUrl core() const; private: Ui::SelectCoreDialog m_ui; }; } // end of namespace KDevMI #endif diff --git a/plugins/gdb/memviewdlg.cpp b/plugins/gdb/memviewdlg.cpp index 0278136ebb..88eb14a257 100644 --- a/plugins/gdb/memviewdlg.cpp +++ b/plugins/gdb/memviewdlg.cpp @@ -1,470 +1,473 @@ /*************************************************************************** begin : Tue Oct 5 1999 copyright : (C) 1999 by John Birch email : jbb@kdevelop.org ************************************************************************** * Copyright 2006 Vladimir Prus *************************************************************************** * * * This program 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. * * * ***************************************************************************/ #include "memviewdlg.h" #include "dbgglobal.h" #include "debugsession.h" #include "mi/micommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using KDevMI::MI::CommandType; namespace KDevMI { namespace GDB { /** Container for controls that select memory range. * The memory range selection is embedded into memory view widget, it's not a standalone dialog. However, we want to have easy way to hide/show all controls, so we group them in this class. */ class MemoryRangeSelector : public QWidget { + Q_OBJECT public: QLineEdit* startAddressLineEdit; QLineEdit* amountLineEdit; QPushButton* okButton; QPushButton* cancelButton; explicit MemoryRangeSelector(QWidget* parent) : QWidget(parent) { QVBoxLayout* l = new QVBoxLayout(this); // Form layout: labels + address field auto formLayout = new QFormLayout(); l->addLayout(formLayout); startAddressLineEdit = new QLineEdit(this); formLayout->addRow(i18n("Start:"), startAddressLineEdit); amountLineEdit = new QLineEdit(this); formLayout->addRow(i18n("Amount:"), amountLineEdit); auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel, this); l->addWidget(buttonBox); okButton = buttonBox->button(QDialogButtonBox::Ok); cancelButton = buttonBox->button(QDialogButtonBox::Cancel); setLayout(l); connect(startAddressLineEdit, &QLineEdit::returnPressed, okButton, [this]() { okButton->animateClick(); }); connect(amountLineEdit, &QLineEdit::returnPressed, okButton, [this]() { okButton->animateClick(); }); } }; MemoryView::MemoryView(QWidget* parent) : QWidget(parent), // New memory view can be created only when debugger is active, // so don't set s_appNotStarted here. m_memViewView(nullptr), m_debuggerState(0) { setWindowTitle(i18n("Memory view")); initWidget(); if (isOk()) slotEnableOrDisable(); auto debugController = KDevelop::ICore::self()->debugController(); Q_ASSERT(debugController); connect(debugController, &KDevelop::IDebugController::currentSessionChanged, this, &MemoryView::currentSessionChanged); } void MemoryView::currentSessionChanged(KDevelop::IDebugSession* s) { DebugSession *session = qobject_cast(s); if (!session) return; connect(session, &DebugSession::debuggerStateChanged, this, &MemoryView::slotStateChanged); } void MemoryView::slotStateChanged(DBGStateFlags oldState, DBGStateFlags newState) { Q_UNUSED(oldState); debuggerStateChanged(newState); } void MemoryView::initWidget() { QVBoxLayout *l = new QVBoxLayout(this); l->setContentsMargins(0, 0, 0, 0); m_memViewModel = new Okteta::ByteArrayModel(0, -1, this); m_memViewView = new Okteta::ByteArrayColumnView(this); m_memViewView->setByteArrayModel(m_memViewModel); m_memViewModel->setReadOnly(false); m_memViewView->setReadOnly(false); m_memViewView->setOverwriteMode(true); m_memViewView->setOverwriteOnly(true); m_memViewModel->setAutoDelete(false); m_memViewView->setValueCoding( Okteta::ByteArrayColumnView::HexadecimalCoding ); m_memViewView->setNoOfGroupedBytes(4); m_memViewView->setByteSpacingWidth(2); m_memViewView->setGroupSpacingWidth(12); m_memViewView->setLayoutStyle(Okteta::AbstractByteArrayView::FullSizeLayoutStyle); m_memViewView->setShowsNonprinting(false); m_memViewView->setSubstituteChar(QLatin1Char('*')); m_rangeSelector = new MemoryRangeSelector(this); l->addWidget(m_rangeSelector); connect(m_rangeSelector->okButton, &QPushButton::clicked, this, &MemoryView::slotChangeMemoryRange); connect(m_rangeSelector->cancelButton, &QPushButton::clicked, this, &MemoryView::slotHideRangeDialog); connect(m_rangeSelector->startAddressLineEdit, &QLineEdit::textChanged, this, &MemoryView::slotEnableOrDisable); connect(m_rangeSelector->amountLineEdit, &QLineEdit::textChanged, this, &MemoryView::slotEnableOrDisable); l->addWidget(m_memViewView); } void MemoryView::debuggerStateChanged(DBGStateFlags state) { if (isOk()) { m_debuggerState = state; slotEnableOrDisable(); } } void MemoryView::slotHideRangeDialog() { m_rangeSelector->hide(); } void MemoryView::slotChangeMemoryRange() { DebugSession *session = qobject_cast( KDevelop::ICore::self()->debugController()->currentSession()); if (!session) return; QString amount = m_rangeSelector->amountLineEdit->text(); if(amount.isEmpty()) amount = QStringLiteral("sizeof(%1)").arg(m_rangeSelector->startAddressLineEdit->text()); session->addCommand(new MI::ExpressionValueCommand(amount, this, &MemoryView::sizeComputed)); } void MemoryView::sizeComputed(const QString& size) { DebugSession *session = qobject_cast( KDevelop::ICore::self()->debugController()->currentSession()); if (!session) return; session->addCommand(MI::DataReadMemory, QStringLiteral("%1 x 1 1 %2") .arg(m_rangeSelector->startAddressLineEdit->text(), size), this, &MemoryView::memoryRead); } void MemoryView::memoryRead(const MI::ResultRecord& r) { const MI::Value& content = r[QStringLiteral("memory")][0][QStringLiteral("data")]; bool startStringConverted; m_memStart = r[QStringLiteral("addr")].literal().toULongLong(&startStringConverted, 16); m_memData.resize(content.size()); m_memStartStr = m_rangeSelector->startAddressLineEdit->text(); m_memAmountStr = m_rangeSelector->amountLineEdit->text(); setWindowTitle(i18np("%2 (1 byte)","%2 (%1 bytes)",m_memData.size(),m_memStartStr)); emit captionChanged(windowTitle()); for(int i = 0; i < content.size(); ++i) { m_memData[i] = content[i].literal().toInt(nullptr, 16); } m_memViewModel->setData(reinterpret_cast(m_memData.data()), m_memData.size()); slotHideRangeDialog(); } void MemoryView::memoryEdited(int start, int end) { DebugSession *session = qobject_cast( KDevelop::ICore::self()->debugController()->currentSession()); if (!session) return; for(int i = start; i <= end; ++i) { session->addCommand(MI::GdbSet, QStringLiteral("*(char*)(%1 + %2) = %3") .arg(m_memStart) .arg(i) .arg(QString::number(m_memData[i]))); } } void MemoryView::contextMenuEvent(QContextMenuEvent *e) { if (!isOk()) return; QMenu menu(this); bool app_running = !(m_debuggerState & s_appNotStarted); QAction* reload = menu.addAction(i18n("&Reload")); reload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); reload->setEnabled(app_running && !m_memData.isEmpty() ); QActionGroup* formatGroup = nullptr; QActionGroup* groupingGroup = nullptr; if (m_memViewModel && m_memViewView) { // make Format menu with action group QMenu* formatMenu = menu.addMenu(i18n("&Format")); formatGroup = new QActionGroup(formatMenu); QAction *binary = formatGroup->addAction(i18n("&Binary")); binary->setData(Okteta::ByteArrayColumnView::BinaryCoding); binary->setShortcut(Qt::Key_B); formatMenu->addAction(binary); QAction *octal = formatGroup->addAction(i18n("&Octal")); octal->setData(Okteta::ByteArrayColumnView::OctalCoding); octal->setShortcut(Qt::Key_O); formatMenu->addAction(octal); QAction *decimal = formatGroup->addAction(i18n("&Decimal")); decimal->setData(Okteta::ByteArrayColumnView::DecimalCoding); decimal->setShortcut(Qt::Key_D); formatMenu->addAction(decimal); QAction *hex = formatGroup->addAction(i18n("&Hexadecimal")); hex->setData(Okteta::ByteArrayColumnView::HexadecimalCoding); hex->setShortcut(Qt::Key_H); formatMenu->addAction(hex); foreach(QAction* act, formatGroup->actions()) { act->setCheckable(true); act->setChecked(act->data().toInt() == m_memViewView->valueCoding()); act->setShortcutContext(Qt::WidgetWithChildrenShortcut); } // make Grouping menu with action group QMenu* groupingMenu = menu.addMenu(i18n("&Grouping")); groupingGroup = new QActionGroup(groupingMenu); QAction *group0 = groupingGroup->addAction(i18n("&0")); group0->setData(0); group0->setShortcut(Qt::Key_0); groupingMenu->addAction(group0); QAction *group1 = groupingGroup->addAction(i18n("&1")); group1->setData(1); group1->setShortcut(Qt::Key_1); groupingMenu->addAction(group1); QAction *group2 = groupingGroup->addAction(i18n("&2")); group2->setData(2); group2->setShortcut(Qt::Key_2); groupingMenu->addAction(group2); QAction *group4 = groupingGroup->addAction(i18n("&4")); group4->setData(4); group4->setShortcut(Qt::Key_4); groupingMenu->addAction(group4); QAction *group8 = groupingGroup->addAction(i18n("&8")); group8->setData(8); group8->setShortcut(Qt::Key_8); groupingMenu->addAction(group8); QAction *group16 = groupingGroup->addAction(i18n("1&6")); group16->setData(16); group16->setShortcut(Qt::Key_6); groupingMenu->addAction(group16); foreach(QAction* act, groupingGroup->actions()) { act->setCheckable(true); act->setChecked(act->data().toInt() == m_memViewView->noOfGroupedBytes()); act->setShortcutContext(Qt::WidgetWithChildrenShortcut); } } QAction* write = menu.addAction(i18n("Write changes")); write->setIcon(QIcon::fromTheme(QStringLiteral("document-save"))); write->setEnabled(app_running && m_memViewView && m_memViewView->isModified()); QAction* range = menu.addAction(i18n("Change memory range")); range->setEnabled(app_running && !m_rangeSelector->isVisible()); range->setIcon(QIcon::fromTheme(QStringLiteral("document-edit"))); QAction* close = menu.addAction(i18n("Close this view")); close->setIcon(QIcon::fromTheme(QStringLiteral("window-close"))); QAction* result = menu.exec(e->globalPos()); if (result == reload) { // We use m_memStart and m_memAmount stored in this, // not textual m_memStartStr and m_memAmountStr, // because program position might have changes and expressions // are no longer valid. DebugSession *session = qobject_cast( KDevelop::ICore::self()->debugController()->currentSession()); if (session) { session->addCommand(MI::DataReadMemory, QStringLiteral("%1 x 1 1 %2").arg(m_memStart).arg(m_memData.size()), this, &MemoryView::memoryRead); } } if (result && formatGroup && formatGroup == result->actionGroup()) m_memViewView->setValueCoding( (Okteta::ByteArrayColumnView::ValueCoding)result->data().toInt()); if (result && groupingGroup && groupingGroup == result->actionGroup()) m_memViewView->setNoOfGroupedBytes(result->data().toInt()); if (result == write) { memoryEdited(0, m_memData.size()); m_memViewView->setModified(false); } if (result == range) { m_rangeSelector->startAddressLineEdit->setText(m_memStartStr); m_rangeSelector->amountLineEdit->setText(m_memAmountStr); m_rangeSelector->show(); m_rangeSelector->startAddressLineEdit->setFocus(); } if (result == close) deleteLater(); } bool MemoryView::isOk() const { return m_memViewView; } void MemoryView::slotEnableOrDisable() { bool app_started = !(m_debuggerState & s_appNotStarted); bool enabled_ = app_started && !m_rangeSelector->startAddressLineEdit->text().isEmpty(); m_rangeSelector->okButton->setEnabled(enabled_); } MemoryViewerWidget::MemoryViewerWidget(CppDebuggerPlugin* /*plugin*/, QWidget* parent) : QWidget(parent) { setWindowIcon(QIcon::fromTheme(QStringLiteral("server-database"), windowIcon())); setWindowTitle(i18n("Memory viewer")); QAction * newMemoryViewerAction = new QAction(this); newMemoryViewerAction->setShortcutContext(Qt::WidgetWithChildrenShortcut); newMemoryViewerAction->setText(i18n("New memory viewer")); newMemoryViewerAction->setToolTip(i18nc("@info:tooltip", "Open a new memory viewer.")); newMemoryViewerAction->setIcon(QIcon::fromTheme(QStringLiteral("window-new"))); connect(newMemoryViewerAction, &QAction::triggered, this , &MemoryViewerWidget::slotAddMemoryView); addAction(newMemoryViewerAction); QVBoxLayout *l = new QVBoxLayout(this); l->setContentsMargins(0, 0, 0, 0); m_toolBox = new QToolBox(this); m_toolBox->setContentsMargins(0, 0, 0, 0); l->addWidget(m_toolBox); setLayout(l); // Start with one empty memory view. slotAddMemoryView(); } void MemoryViewerWidget::slotAddMemoryView() { MemoryView* widget = new MemoryView(this); m_toolBox->addItem(widget, widget->windowTitle()); m_toolBox->setCurrentIndex(m_toolBox->indexOf(widget)); connect(widget, &MemoryView::captionChanged, this, &MemoryViewerWidget::slotChildCaptionChanged); } void MemoryViewerWidget::slotChildCaptionChanged(const QString& caption) { const QWidget* s = static_cast(sender()); QWidget* ncs = const_cast(s); QString cap = caption; // Prevent intepreting '&' as accelerator specifier. cap.replace(QLatin1Char('&'), QLatin1String("&&")); m_toolBox->setItemText(m_toolBox->indexOf(ncs), cap); } } // end of namespace GDB } // end of namespace KDevMI + +#include "memviewdlg.moc" diff --git a/plugins/ghprovider/ghdialog.cpp b/plugins/ghprovider/ghdialog.cpp index dc2f6e73db..0a4cdb488a 100644 --- a/plugins/ghprovider/ghdialog.cpp +++ b/plugins/ghprovider/ghdialog.cpp @@ -1,197 +1,198 @@ /* This file is part of KDevelop * * Copyright (C) 2012-2013 Miquel Sabaté * * This program 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. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "ghdialog.h" + +#include +#include + +#include +#include +#include + #include #include #include #include #include #include -#include -#include -#include - -#include -#include -#include - static QString invalidAccountText() { return i18n("You have not authorized KDevelop to use your GitHub account. " "If you authorize KDevelop, you will be able to fetch your " "public/private repositories and the repositories from your " "organizations."); } static QString tokenLinkStatementText() { return i18nc("%1 is the URL with the GitHub token settings", "You can check the authorization for this application and " "others at %1", QStringLiteral("https://github.com/settings/tokens.")); } namespace gh { Dialog::Dialog(QWidget *parent, Account *account) : QDialog(parent) , m_account(account) { auto mainWidget = new QWidget(this); auto mainLayout = new QVBoxLayout; setLayout(mainLayout); mainLayout->addWidget(mainWidget); auto buttonBox = new QDialogButtonBox(); if (m_account->validAccount()) { m_text = new QLabel(i18n("You are logged in as %1.
%2", m_account->name(), tokenLinkStatementText()), this); auto logOutButton = new QPushButton; logOutButton->setText(i18n("Log Out")); logOutButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-cancel"))); buttonBox->addButton(logOutButton, QDialogButtonBox::ActionRole); connect(logOutButton, &QPushButton::clicked, this, &Dialog::revokeAccess); auto forceSyncButton = new QPushButton; forceSyncButton->setText(i18n("Force Sync")); forceSyncButton->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); buttonBox->addButton(forceSyncButton, QDialogButtonBox::ActionRole); connect(forceSyncButton, &QPushButton::clicked, this, &Dialog::syncUser); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); } else { m_text = new QLabel(invalidAccountText(), this); buttonBox->addButton(QDialogButtonBox::Cancel); auto authorizeButton = new QPushButton; buttonBox->addButton(authorizeButton, QDialogButtonBox::ActionRole); authorizeButton->setText(i18n("Authorize")); authorizeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-ok"))); connect(authorizeButton, &QPushButton::clicked, this, &Dialog::authorizeClicked); } m_text->setWordWrap(true); m_text->setOpenExternalLinks(true); setMinimumWidth(350); mainLayout->addWidget(m_text); mainLayout->addWidget(buttonBox); connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept); connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject); setWindowTitle(i18n("GitHub Account")); } void Dialog::authorizeClicked() { QPointer dlg = new KPasswordDialog(this, KPasswordDialog::ShowUsernameLine); dlg->setPrompt(i18n("Enter a login and a password")); if(dlg->exec()) { m_text->setAlignment(Qt::AlignCenter); m_text->setText(i18n("Waiting for response")); m_account->setName(dlg->username()); Resource *rs = m_account->resource(); rs->authenticate(dlg->username(), dlg->password()); connect(rs, &Resource::twoFactorAuthRequested, this, &Dialog::twoFactorResponse); connect(rs, &Resource::authenticated, this, &Dialog::authorizeResponse); } delete dlg; } void Dialog::authorizeResponse(const QByteArray &id, const QByteArray &token, const QString &tokenName) { Q_UNUSED(tokenName); Resource *rs = m_account->resource(); disconnect(rs, &Resource::authenticated, this, &Dialog::authorizeResponse); if (id.isEmpty()) { m_text->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); m_text->setText(invalidAccountText()); m_account->setName(QString()); KMessageBox::sorry(this, i18n("Authentication failed. Please try again.\n\n" "Could not create token: \"%1\"\n%2", tokenName, tokenLinkStatementText()), i18n("GitHub Authorization Failed")); return; } else{ KMessageBox::information(this, i18n("Authentication succeeded.\n\n" "Created token: \"%1\"\n%2", tokenName, tokenLinkStatementText()), i18n("GitHub Account Authorized")); } m_account->saveToken(id, token); syncUser(); } void Dialog::twoFactorResponse(const QString &transferHeader) { auto code = QInputDialog::getText(this, i18n("Authentication Code"), i18n("OTP Code")); Resource* rs = m_account->resource(); disconnect(rs, &Resource::twoFactorAuthRequested, this, &Dialog::twoFactorResponse); rs->twoFactorAuthenticate(transferHeader, code); } void Dialog::syncUser() { Resource *rs = m_account->resource(); connect(rs, &Resource::orgsUpdated, this, &Dialog::updateOrgs); m_text->setAlignment(Qt::AlignCenter); m_text->setText(i18n("Waiting for response")); rs->getOrgs(m_account->token()); } void Dialog::updateOrgs(const QStringList& orgs) { Resource *rs = m_account->resource(); disconnect(rs, &Resource::orgsUpdated, this, &Dialog::updateOrgs); if (!orgs.isEmpty()) m_account->setOrgs(orgs); emit shouldUpdate(); close(); } void Dialog::revokeAccess() { QPointer dlg = new KPasswordDialog(this); dlg->setPrompt(i18n("Please, write your password here.")); if(dlg->exec()) { m_account->invalidate(dlg->password()); emit shouldUpdate(); close(); } delete dlg; } } // End of namespace gh diff --git a/plugins/ghprovider/ghlineedit.cpp b/plugins/ghprovider/ghlineedit.cpp index 4852091ed5..9463d72f02 100644 --- a/plugins/ghprovider/ghlineedit.cpp +++ b/plugins/ghprovider/ghlineedit.cpp @@ -1,60 +1,60 @@ /* This file is part of KDevelop * * Copyright (C) 2012-2013 Miquel Sabaté * * This program 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. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "ghlineedit.h" #include #include -#include namespace gh { LineEdit::LineEdit(QWidget *parent) : QLineEdit(parent) { m_timer = new QTimer(this); m_timer->setInterval(500); connect(m_timer, &QTimer::timeout, this, &LineEdit::timeOut); } LineEdit::~LineEdit() { /* There's nothing to do here! */ } void LineEdit::keyPressEvent(QKeyEvent *e) { m_timer->stop(); if (e->key() == Qt::Key_Return) { e->accept(); emit returnPressed(); return; } m_timer->start(); QLineEdit::keyPressEvent(e); } void LineEdit::timeOut() { m_timer->stop(); if (!text().isEmpty()) emit returnPressed(); } } // End of namespace gh diff --git a/plugins/ghprovider/ghproviderplugin.cpp b/plugins/ghprovider/ghproviderplugin.cpp index 94fbda6de6..d318d6dead 100644 --- a/plugins/ghprovider/ghproviderplugin.cpp +++ b/plugins/ghprovider/ghproviderplugin.cpp @@ -1,58 +1,58 @@ /* This file is part of KDevelop * * Copyright (C) 2012-2013 Miquel Sabaté * * This program 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. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ - -#include -#include +#include #include -#include #include +#include +#include + using namespace KDevelop; K_PLUGIN_FACTORY_WITH_JSON(KDevGHProviderFactory, "kdevghprovider.json", registerPlugin();) namespace gh { ProviderPlugin::ProviderPlugin(QObject *parent, const QList &args) : IPlugin(QStringLiteral("kdevghprovider"), parent) { Q_UNUSED(args); } ProviderPlugin::~ProviderPlugin() { /* There's nothing to do here! */ } QString ProviderPlugin::name() const { return i18n("GitHub"); } IProjectProviderWidget * ProviderPlugin::providerWidget(QWidget *parent) { return new ProviderWidget(parent); } } // End of namespace gh #include "ghproviderplugin.moc" diff --git a/plugins/ghprovider/ghproviderwidget.cpp b/plugins/ghprovider/ghproviderwidget.cpp index 4fe5671316..06978574ba 100644 --- a/plugins/ghprovider/ghproviderwidget.cpp +++ b/plugins/ghprovider/ghproviderwidget.cpp @@ -1,175 +1,175 @@ /* This file is part of KDevelop * * Copyright (C) 2012-2013 Miquel Sabaté * * This program 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. * * This program 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 this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include +#include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include -#include +#include +#include using namespace KDevelop; namespace gh { ProviderWidget::ProviderWidget(QWidget *parent) : IProjectProviderWidget(parent) { setLayout(new QVBoxLayout()); m_projects = new QListView(this); connect(m_projects, &QListView::clicked, this, &ProviderWidget::projectIndexChanged); m_waiting = new QLabel(i18n("Waiting for response"), this); m_waiting->setAlignment(Qt::AlignCenter); m_waiting->hide(); ProviderModel *model = new ProviderModel(this); m_projects->setModel(model); m_projects->setEditTriggers(QAbstractItemView::NoEditTriggers); m_resource = new Resource(this, model); m_account = new Account(m_resource); connect(m_resource, &Resource::reposUpdated, m_waiting, &QLabel::hide); QHBoxLayout *topLayout = new QHBoxLayout(); m_edit = new LineEdit(this); m_edit->setPlaceholderText(i18n("Search")); m_edit->setToolTip(i18n("You can press the Return key if you do not want to wait")); connect(m_edit, &LineEdit::returnPressed, this, &ProviderWidget::searchRepo); topLayout->addWidget(m_edit); m_combo = new QComboBox(this); m_combo->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); connect(m_combo, static_cast(&QComboBox::currentIndexChanged), this, &ProviderWidget::searchRepo); fillCombo(); topLayout->addWidget(m_combo); QPushButton *settings = new QPushButton(QIcon::fromTheme(QStringLiteral("configure")), QString(), this); settings->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed); settings->setToolTip(i18n("Click this button to configure your GitHub account")); connect(settings, &QPushButton::clicked, this, &ProviderWidget::showSettings); topLayout->addWidget(settings); layout()->addItem(topLayout); layout()->addWidget(m_waiting); layout()->addWidget(m_projects); } KDevelop::VcsJob * ProviderWidget::createWorkingCopy(const QUrl &dest) { QModelIndex pos = m_projects->currentIndex(); if (!pos.isValid()) return nullptr; auto plugin = ICore::self()->pluginController()->pluginForExtension(QStringLiteral("org.kdevelop.IBasicVersionControl"), QStringLiteral("kdevgit")); if (!plugin) { KMessageBox::error(nullptr, i18n("The Git plugin could not be loaded which is required to import a GitHub project."), i18n("GitHub Provider Error")); return nullptr; } QString url = pos.data(ProviderModel::VcsLocationRole).toString(); if (m_account->validAccount()) url = QLatin1String("https://") + m_account->token() + QLatin1Char('@') + url.midRef(8); QUrl real = QUrl(url); VcsLocation loc(real); auto vc = plugin->extension(); Q_ASSERT(vc); return vc->createWorkingCopy(loc, dest); } void ProviderWidget::fillCombo() { m_combo->clear(); m_combo->addItem(i18n("User"), 1); m_combo->addItem(i18n("Organization"), 3); if (m_account->validAccount()) { m_combo->addItem(m_account->name(), 0); m_combo->setCurrentIndex(2); } const QStringList &orgs = m_account->orgs(); for (const QString& org : orgs) m_combo->addItem(org, 2); } bool ProviderWidget::isCorrect() const { return m_projects->currentIndex().isValid(); } void ProviderWidget::projectIndexChanged(const QModelIndex ¤tIndex) { if (currentIndex.isValid()) { QString name = currentIndex.data().toString(); emit changed(name); } } void ProviderWidget::showSettings() { Dialog *dialog = new Dialog(this, m_account); connect(dialog, &Dialog::shouldUpdate, this, &ProviderWidget::fillCombo); dialog->show(); } void ProviderWidget::searchRepo() { bool enabled = true; QString uri, text = m_edit->text(); int idx = m_combo->itemData(m_combo->currentIndex()).toInt(); switch (idx) { case 0: /* Looking for this user's repo */ uri = QStringLiteral("/user/repos"); enabled = false; break; case 1: /* Looking for some user's repo */ if (text == m_account->name()) uri = QStringLiteral("/user/repos"); else uri = QStringLiteral("/users/%1/repos").arg(text); break; case 2: /* Known organization */ text = m_combo->currentText(); enabled = false; default:/* Looking for some organization's repo. */ uri = QStringLiteral("/orgs/%1/repos").arg(text); break; } m_edit->setEnabled(enabled); m_waiting->show(); m_resource->searchRepos(uri, m_account->token()); } } // End of namespace gh diff --git a/plugins/grepview/tests/test_findreplace.cpp b/plugins/grepview/tests/test_findreplace.cpp index 334fccf235..ec76295e08 100644 --- a/plugins/grepview/tests/test_findreplace.cpp +++ b/plugins/grepview/tests/test_findreplace.cpp @@ -1,200 +1,201 @@ /*************************************************************************** * Copyright 1999-2001 Bernd Gehrmann and the KDevelop Team * * bernd@kdevelop.org * * Copyright 2010 Julien Desgats * * * * This program 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. * * * ***************************************************************************/ +#include "test_findreplace.h" + #include #include #include #include #include #include -#include "test_findreplace.h" #include "../grepjob.h" #include "../grepviewplugin.h" #include "../grepoutputmodel.h" void FindReplaceTest::initTestCase() { KDevelop::AutoTestShell::init(); KDevelop::TestCore::initialize(KDevelop::Core::NoUi); } void FindReplaceTest::cleanupTestCase() { KDevelop::TestCore::shutdown(); } void FindReplaceTest::testFind_data() { QTest::addColumn("subject"); QTest::addColumn("search"); QTest::addColumn("matches"); QTest::newRow("Basic") << "foobar" << QRegExp("foo") << (MatchList() << Match(0, 0, 3)); QTest::newRow("Multiple matches") << "foobar\nbar\nbarfoo" << QRegExp("foo") << (MatchList() << Match(0, 0, 3) << Match(2, 3, 6)); QTest::newRow("Multiple on same line") << "foobarbaz" << QRegExp("ba") << (MatchList() << Match(0, 3, 5) << Match(0, 6, 8)); QTest::newRow("Multiple sticked together") << "foofoobar" << QRegExp("foo") << (MatchList() << Match(0, 0, 3) << Match(0, 3, 6)); QTest::newRow("RegExp (member call)") << "foo->bar ();\nbar();" << QRegExp("\\->\\s*\\b(bar)\\b\\s*\\(") << (MatchList() << Match(0, 3, 10)); // the matching must be started after the last previous match QTest::newRow("RegExp (greedy match)") << "foofooo" << QRegExp("[o]+") << (MatchList() << Match(0, 1, 3) << Match(0, 4, 7)); QTest::newRow("Matching EOL") << "foobar\nfoobar" << QRegExp("foo.*") << (MatchList() << Match(0, 0, 6) << Match(1, 0, 6)); QTest::newRow("Matching EOL (Windows style)") << "foobar\r\nfoobar" << QRegExp("foo.*") << (MatchList() << Match(0, 0, 6) << Match(1, 0, 6)); QTest::newRow("Empty lines handling") << "foo\n\n\n" << QRegExp("bar") << (MatchList()); QTest::newRow("Can match empty string (at EOL)") << "foobar\n" << QRegExp(".*") << (MatchList() << Match(0, 0, 6)); QTest::newRow("Matching empty string anywhere") << "foobar\n" << QRegExp("") << (MatchList()); } void FindReplaceTest::testFind() { QFETCH(QString, subject); QFETCH(QRegExp, search); QFETCH(MatchList, matches); QTemporaryFile file; QVERIFY(file.open()); file.write(subject.toUtf8()); file.close(); GrepOutputItem::List actualMatches = grepFile(file.fileName(), search); QCOMPARE(actualMatches.length(), matches.length()); for(int i=0; im_range.start().line(), matches[i].line); QCOMPARE(actualMatches[i].change()->m_range.start().column(), matches[i].start); QCOMPARE(actualMatches[i].change()->m_range.end().column(), matches[i].end); } // check that file has not been altered by grepFile QVERIFY(file.open()); QCOMPARE(QString(file.readAll()), subject); } void FindReplaceTest::testReplace_data() { QTest::addColumn("subject"); QTest::addColumn("searchPattern"); QTest::addColumn("searchTemplate"); QTest::addColumn("replace"); QTest::addColumn("replaceTemplate"); QTest::addColumn("result"); QTest::newRow("Raw replace") << (FileList() << File(QStringLiteral("myfile.txt"), QStringLiteral("some text\nreplacement\nsome other test\n")) << File(QStringLiteral("otherfile.txt"), QStringLiteral("some replacement text\n\n"))) << "replacement" << "%s" << "dummy" << "%s" << (FileList() << File(QStringLiteral("myfile.txt"), QStringLiteral("some text\ndummy\nsome other test\n")) << File(QStringLiteral("otherfile.txt"), QStringLiteral("some dummy text\n\n"))); // see bug: https://bugs.kde.org/show_bug.cgi?id=301362 QTest::newRow("LF character replace") << (FileList() << File(QStringLiteral("somefile.txt"), QStringLiteral("hello world\\n"))) << "\\\\n" << "%s" << "\\n\\n" << "%s" << (FileList() << File(QStringLiteral("somefile.txt"), QStringLiteral("hello world\\n\\n"))); QTest::newRow("Template replace") << (FileList() << File(QStringLiteral("somefile.h"), QStringLiteral("struct Foo {\n void setFoo(int foo);\n};")) << File(QStringLiteral("somefile.cpp"), QStringLiteral("instance->setFoo(0);\n setFoo(0); /*not replaced*/"))) << "setFoo" << "\\->\\s*\\b%s\\b\\s*\\(" << "setBar" << "->%s(" << (FileList() << File(QStringLiteral("somefile.h"), QStringLiteral("struct Foo {\n void setFoo(int foo);\n};")) << File(QStringLiteral("somefile.cpp"), QStringLiteral("instance->setBar(0);\n setFoo(0); /*not replaced*/"))); QTest::newRow("Template with captures") << (FileList() << File(QStringLiteral("somefile.cpp"), QStringLiteral("inst::func(1, 2)\n otherInst :: func (\"foo\")\n func()"))) << "func" << "([a-z0-9_$]+)\\s*::\\s*\\b%s\\b\\s*\\(" << "REPL" << "\\1::%s(" << (FileList() << File(QStringLiteral("somefile.cpp"), QStringLiteral("inst::REPL(1, 2)\n otherInst::REPL(\"foo\")\n func()"))); QTest::newRow("Regexp pattern") << (FileList() << File(QStringLiteral("somefile.txt"), QStringLiteral("foobar\n foooobar\n fake"))) << "f\\w*o" << "%s" << "FOO" << "%s" << (FileList() << File(QStringLiteral("somefile.txt"), QStringLiteral("FOObar\n FOObar\n fake"))); } void FindReplaceTest::testReplace() { QFETCH(FileList, subject); QFETCH(QString, searchPattern); QFETCH(QString, searchTemplate); QFETCH(QString, replace); QFETCH(QString, replaceTemplate); QFETCH(FileList, result); QTemporaryDir tempDir; QDir dir(tempDir.path()); // we need some convenience functions that are not in QTemporaryDir foreach(const File& fileData, subject) { QFile file(dir.filePath(fileData.first)); QVERIFY(file.open(QIODevice::WriteOnly)); QVERIFY(file.write(fileData.second.toUtf8()) != -1); file.close(); } GrepJob *job = new GrepJob(this); GrepOutputModel *model = new GrepOutputModel(job); GrepJobSettings settings; job->setOutputModel(model); job->setDirectoryChoice(QList() << QUrl::fromLocalFile(dir.path())); settings.projectFilesOnly = false; settings.caseSensitive = true; settings.regexp = true; settings.depth = -1; // fully recursive settings.pattern = searchPattern; settings.searchTemplate = searchTemplate; settings.replacementTemplate = replaceTemplate; settings.files = QStringLiteral("*"); settings.exclude = QString(); job->setSettings(settings); QVERIFY(job->exec()); QVERIFY(model->hasResults()); model->setReplacement(replace); model->makeItemsCheckable(true); model->doReplacements(); foreach(const File& fileData, result) { QFile file(dir.filePath(fileData.first)); QVERIFY(file.open(QIODevice::ReadOnly)); QCOMPARE(QString(file.readAll()), fileData.second); file.close(); } tempDir.remove(); } QTEST_MAIN(FindReplaceTest) diff --git a/plugins/manpage/manpageplugin.cpp b/plugins/manpage/manpageplugin.cpp index 3bbbf9ca7f..691c6e92d9 100644 --- a/plugins/manpage/manpageplugin.cpp +++ b/plugins/manpage/manpageplugin.cpp @@ -1,156 +1,157 @@ /* This file is part of KDevelop Copyright 2010 Yannick Motta Copyright 2010 Benjamin Port This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include +#include "manpageplugin.h" + +#include "manpagedocumentation.h" +#include "manpagemodel.h" #include +#include +#include #include #include #include #include #include #include #include #include #include +#include + #include #include -#include -#include - -#include "manpageplugin.h" -#include "manpagedocumentation.h" -#include "manpagemodel.h" using namespace KDevelop; K_PLUGIN_FACTORY_WITH_JSON(ManPageFactory, "kdevmanpage.json", registerPlugin(); ) ManPagePlugin::ManPagePlugin(QObject* parent, const QVariantList& args) : IPlugin(QStringLiteral("kdevmanpage"), parent) { Q_UNUSED(args); ManPageDocumentation::s_provider = this; m_model = new ManPageModel(this); } ManPagePlugin::~ManPagePlugin() { delete m_model; } QString ManPagePlugin::name() const { return i18n("Man Page"); } QIcon ManPagePlugin::icon() const { return QIcon::fromTheme(QStringLiteral("application-x-troff-man")); } ManPageModel* ManPagePlugin::model() const{ return m_model; } IDocumentation::Ptr ManPagePlugin::documentationForDeclaration( Declaration* dec ) const { Q_ASSERT(dec); Q_ASSERT(dec->topContext()); Q_ASSERT(dec->topContext()->parsingEnvironmentFile()); static const IndexedString cppLanguage("C++"); // TODO remove because of new clang parser? static const IndexedString clangLanguage("Clang"); const IndexedString declarationLanguage(dec->topContext()->parsingEnvironmentFile()->language()); if (declarationLanguage != cppLanguage && declarationLanguage != clangLanguage) return {}; // Don't show man-page documentation for files that are part of our project if (core()->projectController()->findProjectForUrl(dec->topContext()->url().toUrl())) return {}; // Don't show man-page documentation for files that are not in /usr/include, because then we // most probably will be confusing the global function-name with a local one if (!dec->topContext()->url().str().startsWith(QLatin1String("/usr/"))) return {}; ///@todo Do more verification to make sure that we're showing the correct documentation for the declaration QString identifier; IDocumentation::Ptr result; // First, try to find help for qualified identifier like 'std::vector' { DUChainReadLocker lock; identifier = dec->qualifiedIdentifier().toString(RemoveTemplateInformation); } result = documentationForIdentifier(identifier); if (result.data()) return result; // Second, try to find help for simple identifier like 'sin' { DUChainReadLocker lock; identifier = dec->identifier().toString(RemoveTemplateInformation); } result = documentationForIdentifier(identifier); if (result.data()) return result; return {}; } KDevelop::IDocumentation::Ptr ManPagePlugin::documentationForIdentifier(const QString& identifier) const { if (!m_model->containsIdentifier(identifier)) return KDevelop::IDocumentation::Ptr(nullptr); if (m_model->identifierInSection(identifier, QStringLiteral("3"))) return IDocumentation::Ptr(new ManPageDocumentation(identifier, QUrl(QLatin1String("man:(3)/") + identifier))); if (m_model->identifierInSection(identifier, QStringLiteral("2"))) return IDocumentation::Ptr(new ManPageDocumentation(identifier, QUrl(QLatin1String("man:(2)/") + identifier))); return IDocumentation::Ptr(new ManPageDocumentation(identifier, QUrl(QLatin1String("man:/") + identifier))); } QAbstractItemModel* ManPagePlugin::indexModel() const { return m_model->indexList(); } IDocumentation::Ptr ManPagePlugin::documentationForIndex(const QModelIndex& index) const { QString name = index.data().toString(); return IDocumentation::Ptr(new ManPageDocumentation(name, QUrl(QLatin1String("man:")+name))); } IDocumentation::Ptr ManPagePlugin::homePage() const { return IDocumentation::Ptr(new ManPageHomeDocumentation); } #include "manpageplugin.moc" diff --git a/plugins/ninjabuilder/ninjabuilder.cpp b/plugins/ninjabuilder/ninjabuilder.cpp index ed9e098f87..232a0f1fd9 100644 --- a/plugins/ninjabuilder/ninjabuilder.cpp +++ b/plugins/ninjabuilder/ninjabuilder.cpp @@ -1,209 +1,210 @@ /* This file is part of KDevelop Copyright 2012 Aleix Pol Gonzalez Copyright 2017 Kevin Funk This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License version 2 as published by the Free Software Foundation. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "ninjabuilder.h" #include "ninjajob.h" #include "ninjabuilderpreferences.h" #include #include #include #include #include #include #include #include #include K_PLUGIN_FACTORY_WITH_JSON(NinjaBuilderFactory, "kdevninja.json", registerPlugin(); ) NinjaBuilder::NinjaBuilder(QObject* parent, const QVariantList&) : KDevelop::IPlugin(QStringLiteral("kdevninja"), parent) { if (NinjaJob::ninjaExecutable().isEmpty()) { setErrorDescription(i18n("Unable to find ninja executable. Is it installed on the system?")); } } static QStringList targetsInFolder(KDevelop::ProjectFolderItem* item) { QStringList ret; const auto targets = item->targetList(); ret.reserve(targets.size()); for (auto* target : targets) { ret += target->text(); } return ret; } /** * Returns the first non-empty list of targets in folder @p item * or any of its ancestors if possible */ static QStringList closestTargetsForFolder(KDevelop::ProjectFolderItem* item) { KDevelop::ProjectFolderItem* current = item; while (current) { const QStringList targets = targetsInFolder(current); if (!targets.isEmpty()) { return targets; } current = (current->parent() ? current->parent()->folder() : nullptr); } return QStringList(); } static QStringList argumentsForItem(KDevelop::ProjectBaseItem* item) { if (!item->parent() && QFile::exists(item->project()->buildSystemManager()->buildDirectory(item->project()->projectItem()).toLocalFile())) { return QStringList(); } switch (item->type()) { case KDevelop::ProjectBaseItem::File: return QStringList(item->path().toLocalFile() + QLatin1Char('^')); case KDevelop::ProjectBaseItem::Target: case KDevelop::ProjectBaseItem::ExecutableTarget: case KDevelop::ProjectBaseItem::LibraryTarget: return QStringList(item->target()->text()); case KDevelop::ProjectBaseItem::Folder: case KDevelop::ProjectBaseItem::BuildFolder: return closestTargetsForFolder(item->folder()); } return QStringList(); } NinjaJob* NinjaBuilder::runNinja(KDevelop::ProjectBaseItem* item, NinjaJob::CommandType commandType, const QStringList& args, const QByteArray& signal) { ///Running the same builder twice may result in serious problems, ///so kill jobs already running on the same project foreach (NinjaJob* ninjaJob, m_activeNinjaJobs.data()) { if (item && ninjaJob->item() && ninjaJob->item()->project() == item->project() && ninjaJob->commandType() == commandType) { qCDebug(NINJABUILDER) << "killing running ninja job, due to new started build on same project:" << ninjaJob; ninjaJob->kill(KJob::EmitResult); } } // Build arguments using data from KCM QStringList jobArguments; KSharedConfigPtr config = item->project()->projectConfiguration(); KConfigGroup group = config->group("NinjaBuilder"); if (!group.readEntry("Abort on First Error", true)) { jobArguments << QStringLiteral("-k"); } if (group.readEntry("Override Number Of Jobs", false)) { int jobCount = group.readEntry("Number Of Jobs", 1); if (jobCount > 0) { jobArguments << QStringLiteral("-j%1").arg(jobCount); } } int errorCount = group.readEntry("Number Of Errors", 1); if (errorCount > 1) { jobArguments << QStringLiteral("-k%1").arg(errorCount); } if (group.readEntry("Display Only", false)) { jobArguments << QStringLiteral("-n"); } QString extraOptions = group.readEntry("Additional Options", QString()); if (!extraOptions.isEmpty()) { foreach (const QString& option, KShell::splitArgs(extraOptions)) { jobArguments << option; } } jobArguments << args; NinjaJob* job = new NinjaJob(item, commandType, jobArguments, signal, this); m_activeNinjaJobs.append(job); return job; } KJob* NinjaBuilder::build(KDevelop::ProjectBaseItem* item) { return runNinja(item, NinjaJob::BuildCommand, argumentsForItem(item), "built"); } KJob* NinjaBuilder::clean(KDevelop::ProjectBaseItem* item) { return runNinja(item, NinjaJob::CleanCommand, QStringList(QStringLiteral("-t")) << QStringLiteral("clean"), "cleaned"); } KJob* NinjaBuilder::install(KDevelop::ProjectBaseItem* item) { NinjaJob* installJob = runNinja(item, NinjaJob::InstallCommand, QStringList(QStringLiteral("install")), "installed"); installJob->setIsInstalling(true); KSharedConfigPtr configPtr = item->project()->projectConfiguration(); KConfigGroup builderGroup(configPtr, "NinjaBuilder"); bool installAsRoot = builderGroup.readEntry("Install As Root", false); if (installAsRoot) { KDevelop::BuilderJob* job = new KDevelop::BuilderJob; job->addCustomJob(KDevelop::BuilderJob::Build, build(item), item); job->addCustomJob(KDevelop::BuilderJob::Install, installJob, item); job->updateJobName(); return job; } else { return installJob; } } int NinjaBuilder::perProjectConfigPages() const { return 1; } KDevelop::ConfigPage* NinjaBuilder::perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent) { if (number == 0) { return new NinjaBuilderPreferences(this, options, parent); } return nullptr; } class ErrorJob : public KJob { + Q_OBJECT public: ErrorJob(QObject* parent, const QString& error) : KJob(parent) , m_error(error) {} void start() override { setError(!m_error.isEmpty()); setErrorText(m_error); emitResult(); } private: QString m_error; }; KJob* NinjaBuilder::install(KDevelop::ProjectBaseItem* dom, const QUrl& installPath) { return installPath.isEmpty() ? install(dom) : new ErrorJob(nullptr, i18n("Cannot specify prefix in %1, on ninja", installPath.toDisplayString())); } #include "ninjabuilder.moc" diff --git a/plugins/qmljs/codecompletion/model.cpp b/plugins/qmljs/codecompletion/model.cpp index 2429dda651..f7715dfbb0 100644 --- a/plugins/qmljs/codecompletion/model.cpp +++ b/plugins/qmljs/codecompletion/model.cpp @@ -1,39 +1,40 @@ /* * This file is part of qmljs, the QML/JS language support plugin for KDevelop * Copyright (c) 2013 Sven Brauch * * This program 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 this program. If not, see . * */ -#include "worker.h" #include "model.h" +#include "worker.h" + namespace QmlJS { CodeCompletionModel::CodeCompletionModel(QObject* parent) : KDevelop::CodeCompletionModel(parent) { } KDevelop::CodeCompletionWorker* CodeCompletionModel::createCompletionWorker() { return new CodeCompletionWorker(this); } } diff --git a/plugins/qmljs/codecompletion/model.h b/plugins/qmljs/codecompletion/model.h index 5ae0959a05..c724055b52 100644 --- a/plugins/qmljs/codecompletion/model.h +++ b/plugins/qmljs/codecompletion/model.h @@ -1,42 +1,43 @@ /* * This file is part of qmljs, the QML/JS language support plugin for KDevelop * Copyright (c) 2013 Sven Brauch * * This program 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 this program. If not, see . * */ #ifndef QMLJS_MODEL_H #define QMLJS_MODEL_H #include "codecompletionexport.h" #include namespace QmlJS { class KDEVQMLJSCOMPLETION_EXPORT CodeCompletionModel : public KDevelop::CodeCompletionModel { + Q_OBJECT public: explicit CodeCompletionModel(QObject* parent); protected: KDevelop::CodeCompletionWorker* createCompletionWorker() override; }; } #endif // QMLJS_MODEL_H diff --git a/plugins/qmljs/codecompletion/worker.h b/plugins/qmljs/codecompletion/worker.h index 3f9a30ee74..8873c77360 100644 --- a/plugins/qmljs/codecompletion/worker.h +++ b/plugins/qmljs/codecompletion/worker.h @@ -1,44 +1,45 @@ /* * This file is part of qmljs, the QML/JS language support plugin for KDevelop * Copyright (c) 2013 Sven Brauch * * This program 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 this program. If not, see . * */ #ifndef QMLJS_WORKER_H #define QMLJS_WORKER_H #include #include namespace QmlJS { class CodeCompletionWorker : public KDevelop::CodeCompletionWorker { + Q_OBJECT public: explicit CodeCompletionWorker(KDevelop::CodeCompletionModel* model); protected: KDevelop::CodeCompletionContext* createCompletionContext( const KDevelop::DUContextPointer& context, const QString& contextText, const QString& followingText, const KDevelop::CursorInRevision& position) const override; }; } #endif // QMLJS_WORKER_H diff --git a/plugins/qmljs/duchain/navigation/declarationnavigationcontext.h b/plugins/qmljs/duchain/navigation/declarationnavigationcontext.h index 90f1d74ebf..501165601a 100644 --- a/plugins/qmljs/duchain/navigation/declarationnavigationcontext.h +++ b/plugins/qmljs/duchain/navigation/declarationnavigationcontext.h @@ -1,42 +1,43 @@ /* * This file is part of qmljs, the QML/JS language support plugin for KDevelop * Copyright (c) 2014 Denis Steckelmacher * * This program 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 this program. If not, see . * */ #ifndef __DECLARATIONNAVIGATIONCONTEXT_H__ #define __DECLARATIONNAVIGATIONCONTEXT_H__ #include #include namespace QmlJS { class DeclarationNavigationContext : public KDevelop::AbstractDeclarationNavigationContext { + Q_OBJECT public: using KDevelop::AbstractDeclarationNavigationContext::AbstractDeclarationNavigationContext; protected: void htmlIdentifiedType(KDevelop::AbstractType::Ptr type, const KDevelop::IdentifiedType* idType) override; void eventuallyMakeTypeLinks(KDevelop::AbstractType::Ptr type) override; }; } #endif diff --git a/plugins/qmljs/duchain/navigation/navigationwidget.h b/plugins/qmljs/duchain/navigation/navigationwidget.h index a8dfe1e984..cdd5872224 100644 --- a/plugins/qmljs/duchain/navigation/navigationwidget.h +++ b/plugins/qmljs/duchain/navigation/navigationwidget.h @@ -1,52 +1,53 @@ /* * This file is part of qmljs, the QML/JS language support plugin for KDevelop * Copyright (c) 2014 Denis Steckelmacher * * This program 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) version 3 or any later version * accepted by the membership of KDE e.V. (or its successor approved * by the membership of KDE e.V.), which shall act as a proxy * defined in Section 14 of version 3 of the license. * * This program 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 this program. If not, see . * */ #ifndef __NAVIGATIONWIDGET_H__ #define __NAVIGATIONWIDGET_H__ #include #include "duchainexport.h" namespace KDevelop { class IncludeItem; } namespace QmlJS { class KDEVQMLJSDUCHAIN_EXPORT NavigationWidget : public KDevelop::AbstractNavigationWidget { + Q_OBJECT public: NavigationWidget(KDevelop::Declaration* decl, KDevelop::TopDUContext* topContext, const QString& htmlPrefix, const QString& htmlSuffix, KDevelop::AbstractNavigationWidget::DisplayHints hints); NavigationWidget(const KDevelop::IncludeItem& includeItem, const KDevelop::TopDUContextPointer& topContext, const QString& htmlPrefix, const QString& htmlSuffix, KDevelop::AbstractNavigationWidget::DisplayHints hints); }; } #endif diff --git a/plugins/qmljs/qmljsparsejob.h b/plugins/qmljs/qmljsparsejob.h index 39cc8c7b3d..cb5d970b9c 100644 --- a/plugins/qmljs/qmljsparsejob.h +++ b/plugins/qmljs/qmljsparsejob.h @@ -1,35 +1,36 @@ /************************************************************************************* * Copyright (C) 2012 by Aleix Pol * * Copyright (C) 2012 by Milian Wolff * * * * This program 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. * * * * This program 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 this program; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA * *************************************************************************************/ #ifndef PARSEQMLJSJOB_H #define PARSEQMLJSJOB_H #include class QmlJsParseJob : public KDevelop::ParseJob { + Q_OBJECT public: QmlJsParseJob(const KDevelop::IndexedString& url, KDevelop::ILanguageSupport* languageSupport); protected: void run(ThreadWeaver::JobPointer pointer, ThreadWeaver::Thread* thread) override; }; #endif // PARSEQMLJSJOB_H diff --git a/plugins/qthelp/qthelpconfig.cpp b/plugins/qthelp/qthelpconfig.cpp index 6bf4e1f458..bbb0639443 100644 --- a/plugins/qthelp/qthelpconfig.cpp +++ b/plugins/qthelp/qthelpconfig.cpp @@ -1,355 +1,358 @@ /* This file is part of KDevelop Copyright 2010 Benjamin Port Copyright 2014 Kevin Funk Copyright 2016 Andreas Cord-Landwehr This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "qthelpconfig.h" #include #include #include #include #include #include #include #include "ui_qthelpconfig.h" #include "ui_qthelpconfigeditdialog.h" #include "qthelp_config_shared.h" #include "debug.h" #include "qthelpplugin.h" enum Column { NameColumn, PathColumn, IconColumn, GhnsColumn, ConfigColumn }; class QtHelpConfigEditDialog : public QDialog, public Ui_QtHelpConfigEditDialog { + Q_OBJECT public: explicit QtHelpConfigEditDialog(QTreeWidgetItem* modifiedItem, QtHelpConfig* parent = nullptr) : QDialog(parent) , m_modifiedItem(modifiedItem) , m_config(parent) { setupUi(this); if (modifiedItem) { setWindowTitle(i18n("Modify Entry")); } else { setWindowTitle(i18n("Add New Entry")); } qchIcon->setIcon(QStringLiteral("qtlogo")); } bool checkQtHelpFile(); void accept() override; private: QTreeWidgetItem* m_modifiedItem; QtHelpConfig* m_config; }; bool QtHelpConfigEditDialog::checkQtHelpFile() { //verify if the file is valid and if there is a name if(qchName->text().isEmpty()){ KMessageBox::error(this, i18n("Name cannot be empty.")); return false; } return m_config->checkNamespace(qchRequester->text(), m_modifiedItem); } void QtHelpConfigEditDialog::accept() { if (!checkQtHelpFile()) return; QDialog::accept(); } QtHelpConfig::QtHelpConfig(QtHelpPlugin* plugin, QWidget *parent) : KDevelop::ConfigPage(plugin, nullptr, parent) { m_configWidget = new Ui::QtHelpConfigUI; m_configWidget->setupUi(this); m_configWidget->addButton->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); connect(m_configWidget->addButton, &QPushButton::clicked, this, &QtHelpConfig::add); // Table m_configWidget->qchTable->setColumnHidden(IconColumn, true); m_configWidget->qchTable->setColumnHidden(GhnsColumn, true); m_configWidget->qchTable->model()->setHeaderData(ConfigColumn, Qt::Horizontal, QVariant()); m_configWidget->qchTable->header()->setSectionsMovable(false); m_configWidget->qchTable->header()->setStretchLastSection(false); m_configWidget->qchTable->header()->setSectionResizeMode(NameColumn, QHeaderView::Stretch); m_configWidget->qchTable->header()->setSectionResizeMode(PathColumn, QHeaderView::Stretch); m_configWidget->qchTable->header()->setSectionResizeMode(ConfigColumn, QHeaderView::Fixed); // Add GHNS button KNS3::Button *knsButton = new KNS3::Button(i18nc("Allow user to get some API documentation with GHNS", "Get New Documentation"), QStringLiteral("kdevelop-qthelp.knsrc"), m_configWidget->boxQchManage); m_configWidget->tableCtrlLayout->insertWidget(1, knsButton); connect(knsButton, &KNS3::Button::dialogFinished, this, &QtHelpConfig::knsUpdate); connect(m_configWidget->loadQtDocsCheckBox, &QCheckBox::toggled, this, static_cast(&QtHelpConfig::changed)); m_configWidget->qchSearchDir->setMode(KFile::Directory); connect(m_configWidget->qchSearchDir, &KUrlRequester::textChanged, this, &QtHelpConfig::changed); // Set availability information for QtHelp m_configWidget->messageAvailabilityQtDocs->setCloseButtonVisible(false); if(plugin->isQtHelpAvailable()) { m_configWidget->messageAvailabilityQtDocs->setVisible(false); } else { m_configWidget->messageAvailabilityQtDocs->setText( i18n("The command \"qmake -query\" could not provide a path to a QtHelp file (QCH).")); m_configWidget->loadQtDocsCheckBox->setVisible(false); } reset(); } QtHelpConfig::~QtHelpConfig() { delete m_configWidget; } KDevelop::ConfigPage::ConfigPageType QtHelpConfig::configPageType() const { return KDevelop::ConfigPage::DocumentationConfigPage; } void QtHelpConfig::apply() { QStringList iconList, nameList, pathList, ghnsList; for (int i = 0; i < m_configWidget->qchTable->topLevelItemCount(); i++) { const QTreeWidgetItem* item = m_configWidget->qchTable->topLevelItem(i); nameList << item->text(0); pathList << item->text(1); iconList << item->text(2); ghnsList << item->text(3); } QString searchDir = m_configWidget->qchSearchDir->text(); bool loadQtDoc = m_configWidget->loadQtDocsCheckBox->isChecked(); qtHelpWriteConfig(iconList, nameList, pathList, ghnsList, searchDir, loadQtDoc); static_cast(plugin())->readConfig(); } void QtHelpConfig::reset() { m_configWidget->qchTable->clear(); QStringList iconList, nameList, pathList, ghnsList; QString searchDir; bool loadQtDoc; qtHelpReadConfig(iconList, nameList, pathList, ghnsList, searchDir, loadQtDoc); const int size = qMin(qMin(iconList.size(), nameList.size()), pathList.size()); for(int i = 0; i < size; ++i) { QString ghnsStatus = ghnsList.size()>i ? ghnsList.at(i) : QStringLiteral("0"); addTableItem(iconList.at(i), nameList.at(i), pathList.at(i), ghnsStatus); } m_configWidget->qchSearchDir->setText(searchDir); m_configWidget->loadQtDocsCheckBox->setChecked(loadQtDoc); emit changed(); } void QtHelpConfig::defaults() { bool change = false; if(m_configWidget->qchTable->topLevelItemCount() > 0) { m_configWidget->qchTable->clear(); change = true; } if(!m_configWidget->loadQtDocsCheckBox->isChecked()){ m_configWidget->loadQtDocsCheckBox->setChecked(true); change = true; } if (change) { emit changed(); } } void QtHelpConfig::add() { QPointer dialog = new QtHelpConfigEditDialog(nullptr, this); if (dialog->exec()) { QTreeWidgetItem* item = addTableItem(dialog->qchIcon->icon(), dialog->qchName->text(), dialog->qchRequester->text(), QStringLiteral("0")); m_configWidget->qchTable->setCurrentItem(item); emit changed(); } delete dialog; } void QtHelpConfig::modify(QTreeWidgetItem* item) { if (!item) return; QPointer dialog = new QtHelpConfigEditDialog(item, this); if (item->text(GhnsColumn) != QLatin1String("0")) { dialog->qchRequester->setText(i18n("Documentation provided by GHNS")); dialog->qchRequester->setEnabled(false); } else { dialog->qchRequester->setText(item->text(PathColumn)); dialog->qchRequester->setEnabled(true); } dialog->qchName->setText(item->text(NameColumn)); dialog->qchIcon->setIcon(item->text(IconColumn)); if (dialog->exec()) { item->setIcon(NameColumn, QIcon(dialog->qchIcon->icon())); item->setText(NameColumn, dialog->qchName->text()); item->setText(IconColumn, dialog->qchIcon->icon()); if(item->text(GhnsColumn) == QLatin1String("0")) { item->setText(PathColumn, dialog->qchRequester->text()); } emit changed(); } delete dialog; } bool QtHelpConfig::checkNamespace(const QString& filename, QTreeWidgetItem* modifiedItem) { QString qtHelpNamespace = QHelpEngineCore::namespaceName(filename); if (qtHelpNamespace.isEmpty()) { // Open error message (not valid Qt Compressed Help file) KMessageBox::error(this, i18n("Qt Compressed Help file is not valid.")); return false; } // verify if it's the namespace it's not already in the list for(int i=0; i < m_configWidget->qchTable->topLevelItemCount(); i++) { const QTreeWidgetItem* item = m_configWidget->qchTable->topLevelItem(i); if (item != modifiedItem){ if (qtHelpNamespace == QHelpEngineCore::namespaceName(item->text(PathColumn))) { // Open error message, documentation already imported KMessageBox::error(this, i18n("Documentation already imported")); return false; } } } return true; } void QtHelpConfig::remove(QTreeWidgetItem* item) { if (!item) return; delete item; emit changed(); } void QtHelpConfig::knsUpdate(const KNS3::Entry::List& list) { if (list.isEmpty()) return; for (const KNS3::Entry& e : list) { if(e.status() == KNS3::Entry::Installed) { if(e.installedFiles().size() == 1) { QString filename = e.installedFiles().at(0); if(checkNamespace(filename, nullptr)){ QTreeWidgetItem* item = addTableItem(QStringLiteral("documentation"), e.name(), filename, QStringLiteral("1")); m_configWidget->qchTable->setCurrentItem(item); } else { qCDebug(QTHELP) << "namespace error"; } } } else if(e.status() == KNS3::Entry::Deleted) { if(e.uninstalledFiles().size() == 1) { for(int i=0; i < m_configWidget->qchTable->topLevelItemCount(); i++) { QTreeWidgetItem* item = m_configWidget->qchTable->topLevelItem(i); if (e.uninstalledFiles().at(0) == item->text(PathColumn)) { delete item; break; } } } } } emit changed(); } QString QtHelpConfig::name() const { return i18n("Qt Help"); } QString QtHelpConfig::fullName() const { return i18n("Configure Qt Help Settings"); } QIcon QtHelpConfig::icon() const { return QIcon::fromTheme(QStringLiteral("qtlogo")); } QTreeWidgetItem * QtHelpConfig::addTableItem(const QString &icon, const QString &name, const QString &path, const QString &ghnsStatus) { QTreeWidgetItem *item = new QTreeWidgetItem(m_configWidget->qchTable); item->setIcon(NameColumn, QIcon::fromTheme(icon)); item->setText(NameColumn, name); item->setToolTip(NameColumn, name); item->setText(PathColumn, path); item->setToolTip(PathColumn, path); item->setText(IconColumn, icon); item->setText(GhnsColumn, ghnsStatus); QWidget *ctrlWidget = new QWidget(item->treeWidget()); ctrlWidget->setLayout(new QHBoxLayout(ctrlWidget)); QToolButton *modifyBtn = new QToolButton(item->treeWidget()); modifyBtn->setIcon(QIcon::fromTheme(QStringLiteral("document-edit"))); modifyBtn->setToolTip(i18n("Modify")); connect(modifyBtn, &QPushButton::clicked, this, [=](){ modify(item); }); QToolButton *removeBtn = new QToolButton(item->treeWidget()); removeBtn->setIcon(QIcon::fromTheme(QStringLiteral("entry-delete"))); removeBtn->setToolTip(i18n("Delete")); if (item->text(GhnsColumn) != QLatin1String("0")) { // KNS3 currently does not provide API to uninstall entries // just removing the files results in wrong installed states in the KNS3 dialog // TODO: add API to KNS to remove files without UI interaction removeBtn->setEnabled(false); removeBtn->setToolTip(i18n("Please uninstall this via GHNS")); } else { connect(removeBtn, &QPushButton::clicked, this, [=](){ remove(item); }); } ctrlWidget->layout()->addWidget(modifyBtn); ctrlWidget->layout()->addWidget(removeBtn); m_configWidget->qchTable->setItemWidget(item, ConfigColumn, ctrlWidget); return item; } + +#include "qthelpconfig.moc" diff --git a/plugins/qthelp/qthelpnetwork.h b/plugins/qthelp/qthelpnetwork.h index f6868f9cd1..5689ac1c50 100644 --- a/plugins/qthelp/qthelpnetwork.h +++ b/plugins/qthelp/qthelpnetwork.h @@ -1,60 +1,62 @@ /* This file is part of KDevelop Copyright 2009 Aleix Pol This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef QTHELPNETWORK_H #define QTHELPNETWORK_H #include "debug.h" #include #include #include #include #include class HelpNetworkReply : public QNetworkReply { + Q_OBJECT public: HelpNetworkReply(const QNetworkRequest &request, const QByteArray &fileData, const QString &mimeType); void abort() override {} qint64 bytesAvailable() const override { return data.length() + QNetworkReply::bytesAvailable(); } protected: qint64 readData(char *data, qint64 maxlen) override; private: QByteArray data; qint64 origLen; }; class HelpNetworkAccessManager : public QNetworkAccessManager { + Q_OBJECT public: explicit HelpNetworkAccessManager(QHelpEngineCore *engine, QObject *parent = nullptr); ~HelpNetworkAccessManager() override; protected: QNetworkReply *createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData = nullptr) override; private: QHelpEngineCore *m_helpEngine; }; #endif diff --git a/plugins/standardoutputview/tests/test_standardoutputview.cpp b/plugins/standardoutputview/tests/test_standardoutputview.cpp index 90f3656264..eabdf7e869 100644 --- a/plugins/standardoutputview/tests/test_standardoutputview.cpp +++ b/plugins/standardoutputview/tests/test_standardoutputview.cpp @@ -1,228 +1,229 @@ /* Copyright (C) 2011 Silvère Lestang This program 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. This program 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 this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "test_standardoutputview.h" + #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include "test_standardoutputview.h" #include "../outputwidget.h" #include "../toolviewdata.h" namespace KDevelop { class IUiController; } QTEST_MAIN(StandardOutputViewTest) const QString StandardOutputViewTest::toolViewTitle = QStringLiteral("my_toolview"); void StandardOutputViewTest::initTestCase() { KDevelop::AutoTestShell::init({QStringLiteral("KDevStandardOutputView")}); m_testCore = new KDevelop::TestCore(); m_testCore->initialize(KDevelop::Core::Default); m_controller = m_testCore->uiControllerInternal(); QTest::qWait(500); // makes sure that everything is loaded (don't know if it's required) m_stdOutputView = nullptr; KDevelop::IPluginController* plugin_controller = m_testCore->pluginController(); // make sure KDevStandardOutputView is loaded KDevelop::IPlugin* plugin = plugin_controller->loadPlugin(QStringLiteral("KDevStandardOutputView")); QVERIFY(plugin); m_stdOutputView = dynamic_cast(plugin); QVERIFY(m_stdOutputView); } void StandardOutputViewTest::cleanupTestCase() { m_testCore->cleanup(); delete m_testCore; } OutputWidget* StandardOutputViewTest::toolViewPointer(const QString& toolViewTitle) { const QList< Sublime::View* > views = m_controller->activeArea()->toolViews(); for (Sublime::View* view : views) { Sublime::ToolDocument *doc = dynamic_cast(view->document()); if(doc) { if(doc->title() == toolViewTitle && view->hasWidget()) { return dynamic_cast(view->widget()); } } } return nullptr; } void StandardOutputViewTest::testRegisterAndRemoveToolView() { toolViewId = m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::HistoryView); QVERIFY(toolViewPointer(toolViewTitle)); // re-registering should return the same tool view instead of creating a new one QCOMPARE(toolViewId, m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::HistoryView)); m_stdOutputView->removeToolView(toolViewId); QVERIFY(!toolViewPointer(toolViewTitle)); } void StandardOutputViewTest::testActions() { toolViewId = m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::MultipleView, QIcon()); OutputWidget* outputWidget = toolViewPointer(toolViewTitle); QVERIFY(outputWidget); QList actions = outputWidget->actions(); QCOMPARE(actions.size(), 11); m_stdOutputView->removeToolView(toolViewId); QVERIFY(!toolViewPointer(toolViewTitle)); QList addedActions; addedActions.append(new QAction(QStringLiteral("Action1"), nullptr)); addedActions.append(new QAction(QStringLiteral("Action2"), nullptr)); toolViewId = m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::HistoryView, QIcon(), KDevelop::IOutputView::ShowItemsButton | KDevelop::IOutputView::AddFilterAction, addedActions); outputWidget = toolViewPointer(toolViewTitle); QVERIFY(outputWidget); actions = outputWidget->actions(); QCOMPARE(actions.size(), 16); QCOMPARE(actions[actions.size()-2]->text(), addedActions[0]->text()); QCOMPARE(actions[actions.size()-1]->text(), addedActions[1]->text()); m_stdOutputView->removeToolView(toolViewId); QVERIFY(!toolViewPointer(toolViewTitle)); } void StandardOutputViewTest::testRegisterAndRemoveOutput() { toolViewId = m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::MultipleView, QIcon()); OutputWidget* outputWidget = toolViewPointer(toolViewTitle); QVERIFY(outputWidget); for(int i = 0; i < 5; i++) { outputId[i] = m_stdOutputView->registerOutputInToolView(toolViewId, QStringLiteral("output%1").arg(i)); } for(int i = 0; i < 5; i++) { QCOMPARE(outputWidget->data->outputdata.value(outputId[i])->title, QStringLiteral("output%1").arg(i)); QCOMPARE(outputWidget->m_tabwidget->tabText(i), QStringLiteral("output%1").arg(i)); } for(int i = 0; i < 5; i++) { m_stdOutputView->removeOutput(outputId[i]); QVERIFY(!outputWidget->data->outputdata.contains(outputId[i])); } QCOMPARE(outputWidget->m_tabwidget->count(), 0); m_stdOutputView->removeToolView(toolViewId); QVERIFY(!toolViewPointer(toolViewTitle)); toolViewId = m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::HistoryView, QIcon(), KDevelop::IOutputView::ShowItemsButton | KDevelop::IOutputView::AddFilterAction); outputWidget = toolViewPointer(toolViewTitle); QVERIFY(outputWidget); for(int i = 0; i < 5; i++) { outputId[i] = m_stdOutputView->registerOutputInToolView(toolViewId, QStringLiteral("output%1").arg(i)); } for(int i = 0; i < 5; i++) { QCOMPARE(outputWidget->data->outputdata.value(outputId[i])->title, QStringLiteral("output%1").arg(i)); } for(int i = 0; i < 5; i++) { m_stdOutputView->removeOutput(outputId[i]); QVERIFY(!outputWidget->data->outputdata.contains(outputId[i])); } QCOMPARE(outputWidget->m_stackwidget->count(), 0); m_stdOutputView->removeToolView(toolViewId); QVERIFY(!toolViewPointer(toolViewTitle)); } void StandardOutputViewTest::testSetModelAndDelegate() { toolViewId = m_stdOutputView->registerToolView(toolViewTitle, KDevelop::IOutputView::MultipleView, QIcon()); OutputWidget* outputWidget = toolViewPointer(toolViewTitle); QVERIFY(outputWidget); QAbstractItemModel* model = new QStandardItemModel; QPointer checkModel(model); QAbstractItemDelegate* delegate = new QItemDelegate; QPointer checkDelegate(delegate); outputId[0] = m_stdOutputView->registerOutputInToolView(toolViewId, QStringLiteral("output")); m_stdOutputView->setModel(outputId[0], model); m_stdOutputView->setDelegate(outputId[0], delegate); QCOMPARE(outputWidget->m_views.value(outputId[0]).view->model(), model); QCOMPARE(outputWidget->m_views.value(outputId[0]).view->itemDelegate(), delegate); QVERIFY(model->parent()); // they have a parent (the outputdata), so parent() != 0x0 QVERIFY(delegate->parent()); m_stdOutputView->removeToolView(toolViewId); QVERIFY(!toolViewPointer(toolViewTitle)); // view deleted, hence model + delegate deleted QVERIFY(!checkModel.data()); QVERIFY(!checkDelegate.data()); } void StandardOutputViewTest::testStandardToolViews() { QFETCH(KDevelop::IOutputView::StandardToolView, view); int id = m_stdOutputView->standardToolView(view); QVERIFY(id); QCOMPARE(id, m_stdOutputView->standardToolView(view)); } void StandardOutputViewTest::testStandardToolViews_data() { QTest::addColumn("view"); QTest::newRow("build") << KDevelop::IOutputView::BuildView; QTest::newRow("run") << KDevelop::IOutputView::RunView; QTest::newRow("debug") << KDevelop::IOutputView::DebugView; QTest::newRow("test") << KDevelop::IOutputView::TestView; QTest::newRow("vcs") << KDevelop::IOutputView::VcsView; }