diff --git a/kdevplatform/documentation/standarddocumentationview.cpp b/kdevplatform/documentation/standarddocumentationview.cpp index b173e50847..6d684e7b9f 100644 --- a/kdevplatform/documentation/standarddocumentationview.cpp +++ b/kdevplatform/documentation/standarddocumentationview.cpp @@ -1,388 +1,388 @@ /* * 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 { 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, "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 = 0; + 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 { public: explicit CustomSchemeHandler(QNetworkAccessManager* nam, QObject *parent = 0) : 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); } diff --git a/kdevplatform/language/codecompletion/codecompletiontesthelper.h b/kdevplatform/language/codecompletion/codecompletiontesthelper.h index ff60d502f7..154cda96be 100644 --- a/kdevplatform/language/codecompletion/codecompletiontesthelper.h +++ b/kdevplatform/language/codecompletion/codecompletiontesthelper.h @@ -1,234 +1,234 @@ /* This file is part of KDevelop Copyright 2006 Hamish Rodda Copyright 2007-2009 David Nolden 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 KDEVPLATFORM_CODECOMPLETIONTESTHELPER_H #define KDEVPLATFORM_CODECOMPLETIONTESTHELPER_H #include #include #include "../duchain/declaration.h" #include "../duchain/duchain.h" #include "codecompletionitem.h" #include #include #include #include using namespace KTextEditor; using namespace KDevelop; /** * Helper-class for testing completion-items * Just initialize it with the context and the text, and then use the members, for simple cases only "names" * the template parameter is your language specific CodeCompletionContext */ template struct CodeCompletionItemTester { using Element = QExplicitlySharedDataPointer; using Item = QExplicitlySharedDataPointer; using Context = QExplicitlySharedDataPointer; //Standard constructor CodeCompletionItemTester(DUContext* context, const QString& text = "; ", const QString& followingText = QString(), const CursorInRevision& position = CursorInRevision::invalid()) : completionContext(new T(DUContextPointer(context), text, followingText, position.isValid() ? position : context->range().end)) { init(); } //Can be used if you already have the completion context CodeCompletionItemTester(const Context& context) : completionContext(context) { init(); } //Creates a CodeCompletionItemTester for the parent context CodeCompletionItemTester parent() const { Context parent = Context(dynamic_cast(completionContext->parentContext())); Q_ASSERT(parent); return CodeCompletionItemTester(parent); } void addElements(const QList& elements) { foreach(Element element, elements) { Item item(dynamic_cast(element.data())); if(item) items << item; CompletionTreeNode* node = dynamic_cast(element.data()); if(node) addElements(node->children); } } bool containsDeclaration(Declaration* dec) const { foreach(Item item, items) { if (item->declaration().data() == dec) { return true; } } return false; } QList items; // All items retrieved QStringList names; // Names of all completion-items Context completionContext; //Convenience-function to retrieve data from completion-items by name QVariant itemData(QString itemName, int column = KTextEditor::CodeCompletionModel::Name, int role = Qt::DisplayRole) const { return itemData(names.indexOf(itemName), column, role); } QVariant itemData(int itemNumber, int column = KTextEditor::CodeCompletionModel::Name, int role = Qt::DisplayRole) const { if(itemNumber < 0 || itemNumber >= items.size()) return QVariant(); return itemData(items[itemNumber], column, role); } QVariant itemData(Item item, int column = KTextEditor::CodeCompletionModel::Name, int role = Qt::DisplayRole) const { - return item->data(fakeModel().index(0, column), role, 0); + return item->data(fakeModel().index(0, column), role, nullptr); } Item findItem(const QString& itemName) const { const auto idx = names.indexOf(itemName); if (idx < 0) { return {}; } return items[idx]; } private: void init() { if ( !completionContext || !completionContext->isValid() ) { qWarning() << "invalid completion context"; return; } bool abort = false; items = completionContext->completionItems(abort); addElements(completionContext->ungroupedElements()); foreach(Item i, items) { - names << i->data(fakeModel().index(0, KTextEditor::CodeCompletionModel::Name), Qt::DisplayRole, 0).toString(); + names << i->data(fakeModel().index(0, KTextEditor::CodeCompletionModel::Name), Qt::DisplayRole, nullptr).toString(); } } static QStandardItemModel& fakeModel() { static QStandardItemModel model; model.setColumnCount(10); model.setRowCount(10); return model; } }; /** * Helper class that inserts the given text into the duchain under the specified name, * allows parsing it with a simple call to parse(), and automatically releases the top-context * * The duchain must not be locked when this object is destroyed */ struct InsertIntoDUChain { ///Artificially inserts a file called @p name with the text @p text - InsertIntoDUChain(const QString& name, const QString& text) : m_insertedCode(IndexedString(name), text), m_topContext(0) { + InsertIntoDUChain(const QString& name, const QString& text) : m_insertedCode(IndexedString(name), text), m_topContext(nullptr) { } ~InsertIntoDUChain() { get(); release(); } ///The duchain must not be locked when this is called void release() { if(m_topContext) { DUChainWriteLocker lock; - m_topContext = 0; + m_topContext = nullptr; QList< TopDUContext* > chains = DUChain::self()->chainsForDocument(m_insertedCode.file()); foreach(TopDUContext* top, chains) DUChain::self()->removeDocumentChain(top); } } TopDUContext* operator->() { get(); return m_topContext.data(); } TopDUContext* tryGet() { DUChainReadLocker lock; return DUChain::self()->chainForDocument(m_insertedCode.file(), false); } void get() { if(!m_topContext) m_topContext = tryGet(); } ///Helper function: get a declaration based on its qualified identifier Declaration* getDeclaration(const QString& id) { get(); if(!topContext()) - return 0; + return nullptr; return DeclarationId(IndexedQualifiedIdentifier(QualifiedIdentifier(id))).getDeclaration(topContext()); } TopDUContext* topContext() { return m_topContext.data(); } /** * Parses this inserted code as a stand-alone top-context * The duchain must not be locked when this is called * * @param features The features that should be requested for the top-context * @param update Whether the top-context should be updated if it already exists. Else it will be deleted. */ void parse(uint features = TopDUContext::AllDeclarationsContextsAndUses, bool update = false) { if(!update) release(); m_topContext = DUChain::self()->waitForUpdate(m_insertedCode.file(), (TopDUContext::Features)features, false); Q_ASSERT(m_topContext); DUChainReadLocker lock; Q_ASSERT(!m_topContext->parsingEnvironmentFile()->isProxyContext()); } InsertArtificialCodeRepresentation m_insertedCode; ReferencedTopDUContext m_topContext; }; #endif // KDEVPLATFORM_CODECOMPLETIONTESTHELPER_H diff --git a/kdevplatform/language/util/setrepository.h b/kdevplatform/language/util/setrepository.h index 269fbb519c..7c2f2928a2 100644 --- a/kdevplatform/language/util/setrepository.h +++ b/kdevplatform/language/util/setrepository.h @@ -1,482 +1,482 @@ /*************************************************************************** Copyright 2007 David Nolden ***************************************************************************/ /*************************************************************************** * * * 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. * * * ***************************************************************************/ #ifndef KDEVPLATFORM_SETREPOSITORY_H #define KDEVPLATFORM_SETREPOSITORY_H #include "basicsetrepository.h" #include #include /** * This header defines convenience-class that allow handling set-repositories using the represented higher-level objects instead * of indices to them. * */ namespace Utils { /** * Use this class to conveniently iterate over the items in a set. * @tparam T The type the indices will be converted to * @tparam Conversion Should be a class that has a toIndex member function that takes an object of type T as parameter, and returns an index, * and a toItem member function that takes an index, and returns an item of type T. * */ template class ConvenientIterator : public Conversion { public: explicit ConvenientIterator(const Set::Iterator& it = Set::Iterator()) : m_it(it) { } explicit ConvenientIterator(const Set& set) : m_it(set.iterator()) { } operator bool() const { return m_it; } ConvenientIterator& operator++() { ++m_it; return *this; } T operator*() const { return Conversion::toItem(*m_it); } uint index() const { return *m_it; } private: Set::Iterator m_it; }; struct DummyLocker { }; template struct IdentityConversion { static T toIndex(const T& t) { return t; } static T toItem(const T& t) { return t; } }; ///This is a virtual set-node that allows conveniently iterating through the tree-structure, ///accessing the contained items directly, and accessing the ranges. template class VirtualSetNode { private: using ClassType = VirtualSetNode; public: inline explicit VirtualSetNode(const SetNodeData* data = nullptr) : m_data(data) { } inline bool isValid() const { return (bool)m_data; } ///If this returns false, a left and a right node are available. ///If this returns true, this node represents a single item, that can be retrieved by calling item() or operator*. inline bool isFinalNode() const { return m_data->leftNode() == 0; } inline T firstItem() const { return Conversion::toItem(start()); } inline T lastItem() const { return Conversion::toItem(end()-1); } inline T operator*() const { return Conversion::toItem(start()); } inline ClassType leftChild() const { if(m_data->leftNode()) return ClassType(StaticRepository::repository()->nodeFromIndex(m_data->leftNode())); else return ClassType(nullptr); } inline ClassType rightChild() const { if(m_data->rightNode()) return ClassType(StaticRepository::repository()->nodeFromIndex(m_data->rightNode())); else return ClassType(nullptr); } ///Returns the start of this node's range. If this is a final node, the length of the range is 1. inline uint start() const { return m_data->start(); } ///Returns the end of this node's range. inline uint end() const { return m_data->end(); } private: const SetNodeData* m_data; }; template class StorableSet : public Conversion { public: typedef VirtualSetNode Node; StorableSet(const StorableSet& rhs) : m_setIndex(rhs.m_setIndex) { StaticAccessLocker lock; Q_UNUSED(lock); if(doReferenceCounting) set().staticRef(); } explicit StorableSet(const std::set& indices) { StaticAccessLocker lock; Q_UNUSED(lock); m_setIndex = StaticRepository::repository()->createSet(indices).setIndex(); if(doReferenceCounting) set().staticRef(); } StorableSet() { } ~StorableSet() { StaticAccessLocker lock; Q_UNUSED(lock); if(doReferenceCounting) set().staticUnref(); } void insert(const T& t) { insertIndex(Conversion::toIndex(t)); } bool isEmpty() const { return m_setIndex == 0; } uint count() const { return set().count(); } void insertIndex(uint index) { StaticAccessLocker lock; Q_UNUSED(lock); Set set(m_setIndex, StaticRepository::repository()); Set oldSet(set); Set addedSet = StaticRepository::repository()->createSet(index); if(doReferenceCounting) addedSet.staticRef(); set += addedSet; m_setIndex = set.setIndex(); if(doReferenceCounting) { set.staticRef(); oldSet.staticUnref(); addedSet.staticUnref(); } } void remove(const T& t) { removeIndex(Conversion::toIndex(t)); } void removeIndex(uint index) { StaticAccessLocker lock; Q_UNUSED(lock); Set set(m_setIndex, StaticRepository::repository()); Set oldSet(set); Set removedSet = StaticRepository::repository()->createSet(index); if(doReferenceCounting) { removedSet.staticRef(); } set -= removedSet; m_setIndex = set.setIndex(); if(doReferenceCounting) { set.staticRef(); oldSet.staticUnref(); removedSet.staticUnref(); } } Set set() const { return Set(m_setIndex, StaticRepository::repository()); } bool contains(const T& item) const { return containsIndex(Conversion::toIndex(item)); } bool containsIndex(uint index) const { StaticAccessLocker lock; Q_UNUSED(lock); Set set(m_setIndex, StaticRepository::repository()); return set.contains(index); } StorableSet& operator +=(const StorableSet& rhs) { StaticAccessLocker lock; Q_UNUSED(lock); Set set(m_setIndex, StaticRepository::repository()); Set oldSet(set); Set otherSet(rhs.m_setIndex, StaticRepository::repository()); set += otherSet; m_setIndex = set.setIndex(); if(doReferenceCounting) { set.staticRef(); oldSet.staticUnref(); } return *this; } StorableSet& operator -=(const StorableSet& rhs) { StaticAccessLocker lock; Q_UNUSED(lock); Set set(m_setIndex, StaticRepository::repository()); Set oldSet(set); Set otherSet(rhs.m_setIndex, StaticRepository::repository()); set -= otherSet; m_setIndex = set.setIndex(); if(doReferenceCounting) { set.staticRef(); oldSet.staticUnref(); } return *this; } StorableSet& operator &=(const StorableSet& rhs) { StaticAccessLocker lock; Q_UNUSED(lock); Set set(m_setIndex, StaticRepository::repository()); Set oldSet(set); Set otherSet(rhs.m_setIndex, StaticRepository::repository()); set &= otherSet; m_setIndex = set.setIndex(); if(doReferenceCounting) { set.staticRef(); oldSet.staticUnref(); } return *this; } StorableSet& operator=(const StorableSet& rhs) { StaticAccessLocker lock; Q_UNUSED(lock); if(doReferenceCounting) set().staticUnref(); m_setIndex = rhs.m_setIndex; if(doReferenceCounting) set().staticRef(); return *this; } StorableSet operator +(const StorableSet& rhs) const { StorableSet ret(*this); ret += rhs; return ret; } StorableSet operator -(const StorableSet& rhs) const { StorableSet ret(*this); ret -= rhs; return ret; } StorableSet operator &(const StorableSet& rhs) const { StorableSet ret(*this); ret &= rhs; return ret; } bool operator==(const StorableSet& rhs) const { return m_setIndex == rhs.m_setIndex; } typedef ConvenientIterator Iterator; Iterator iterator() const { return ConvenientIterator(set()); } Node node() const { return Node(StaticRepository::repository()->nodeFromIndex(m_setIndex)); } uint setIndex() const { return m_setIndex; } private: uint m_setIndex = 0; }; template uint qHash(const StorableSet& set) { return set.setIndex(); } /** This is a helper-class that helps inserting a bunch of items into a set without caring about grouping them together. * * It creates a much better tree-structure if many items are inserted at one time, and this class helps doing that in * cases where there is no better choice then storing a temporary list of items and inserting them all at once. * * This set will then care about really inserting them into the repository once the real set is requested. * * @todo eventually make this unnecessary * * @tparam T Should be the type that should be dealt * @tparam Conversion Should be a class that has a toIndex member function that takes an object of type T as parameter, and returns an index, * and a toItem member function that takes an index, and returns an item of type T. **/ template class LazySet : public Conversion { public: /** @param rep The repository the set should belong/belongs to * @param lockBeforeAccess If this is nonzero, the given mutex will be locked before each modification to the repository. * @param basicSet If this is explicitly given, the given set will be used as base. However it will not be changed. * * @warning Watch for deadlocks, never use this class while the mutex given through lockBeforeAccess is locked */ - explicit LazySet(BasicSetRepository* rep, QMutex* lockBeforeAccess = 0, const Set& basicSet = Set()) : m_rep(rep), m_set(basicSet), m_lockBeforeAccess(lockBeforeAccess) { + explicit LazySet(BasicSetRepository* rep, QMutex* lockBeforeAccess = nullptr, const Set& basicSet = Set()) : m_rep(rep), m_set(basicSet), m_lockBeforeAccess(lockBeforeAccess) { } void insert(const T& t) { if(!m_temporaryRemoveIndices.empty()) apply(); m_temporaryIndices.insert(Conversion::toIndex(t)); } void insertIndex(uint index) { if(!m_temporaryRemoveIndices.empty()) apply(); m_temporaryIndices.insert(index); } void remove(const T& t) { if(!m_temporaryIndices.empty()) apply(); m_temporaryRemoveIndices.insert(Conversion::toIndex(t)); } ///Returns the set this LazySet represents. When this is called, the set is constructed in the repository. Set set() const { apply(); return m_set; } ///@warning this is expensive, because the set is constructed bool contains(const T& item) const { QMutexLocker l(m_lockBeforeAccess); uint index = Conversion::toIndex(item); if( m_temporaryRemoveIndices.empty() ) { //Simplification without creating the set if(m_temporaryIndices.find(index) != m_temporaryIndices.end()) return true; return m_set.contains(index); } return set().contains(index); } LazySet& operator +=(const Set& set) { if(!m_temporaryRemoveIndices.empty()) apply(); QMutexLocker l(m_lockBeforeAccess); m_set += set; return *this; } LazySet& operator -=(const Set& set) { if(!m_temporaryIndices.empty()) apply(); QMutexLocker l(m_lockBeforeAccess); m_set -= set; return *this; } LazySet operator +(const Set& set) const { apply(); QMutexLocker l(m_lockBeforeAccess); Set ret = m_set + set; return LazySet(m_rep, m_lockBeforeAccess, ret); } LazySet operator -(const Set& set) const { apply(); QMutexLocker l(m_lockBeforeAccess); Set ret = m_set - set; return LazySet(m_rep, m_lockBeforeAccess, ret); } void clear() { QMutexLocker l(m_lockBeforeAccess); m_set = Set(); m_temporaryIndices.clear(); m_temporaryRemoveIndices.clear(); } ConvenientIterator iterator() const { apply(); return ConvenientIterator(set()); } private: void apply() const { if(!m_temporaryIndices.empty()) { QMutexLocker l(m_lockBeforeAccess); Set tempSet = m_rep->createSet(m_temporaryIndices); m_temporaryIndices.clear(); m_set += tempSet; } if(!m_temporaryRemoveIndices.empty()) { QMutexLocker l(m_lockBeforeAccess); Set tempSet = m_rep->createSet(m_temporaryRemoveIndices); m_temporaryRemoveIndices.clear(); m_set -= tempSet; } } BasicSetRepository* m_rep; mutable Set m_set; QMutex* m_lockBeforeAccess; typedef std::set IndexList; mutable IndexList m_temporaryIndices; mutable IndexList m_temporaryRemoveIndices; }; ///Persistent repository that manages string-sets, also correctly increasing the string reference-counts as needed struct KDEVPLATFORMLANGUAGE_EXPORT StringSetRepository : public Utils::BasicSetRepository { explicit StringSetRepository(const QString& name); void itemRemovedFromSets(uint index) override; void itemAddedToSets(uint index) override; }; } #endif diff --git a/kdevplatform/tests/json/jsonducontexttests.h b/kdevplatform/tests/json/jsonducontexttests.h index 6c569786b0..79f54186ed 100644 --- a/kdevplatform/tests/json/jsonducontexttests.h +++ b/kdevplatform/tests/json/jsonducontexttests.h @@ -1,179 +1,179 @@ /* 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. */ #ifndef KDEVPLATFORM_JSONDUCONTEXTTESTS_H #define KDEVPLATFORM_JSONDUCONTEXTTESTS_H #include "language/duchain/ducontext.h" #include "jsontesthelpers.h" /** * JSON Object Specification: * FindDeclObject: Mapping of (string) search ids to DeclTestObjects * IndexDeclObject: Mapping of (string) declaration position indexes to DeclTestObjects * IndexCtxtObject: Mapping of (string) context position indexes to CtxtTestObjects * * Quick Reference: * findDeclarations : FindDeclObject * declarations : IndexDeclObject * childCount : int * localDeclarationCount : int * type : string * null : bool * owner : DeclTestObject * importedParents : IndexCtxtObject * range : string */ namespace KDevelop { namespace DUContextTests { using namespace JsonTestHelpers; ///JSON type: FindDeclObject ///@returns whether each declaration can be found and passes its tests ContextTest(findDeclarations) { VERIFY_TYPE(QVariantMap); QString INVALID_ERROR = "Attempted to test invalid context."; QString NOT_FOUND_ERROR = "Could not find declaration \"%1\"."; QString DECL_ERROR = "Declaration found with \"%1\" did not pass tests."; if (!ctxt) return INVALID_ERROR; QVariantMap findDecls = value.toMap(); for (QVariantMap::iterator it = findDecls.begin(); it != findDecls.end(); ++it) { QualifiedIdentifier searchId(it.key()); QList ret = ctxt->findDeclarations(searchId, CursorInRevision::invalid()); if (!ret.size()) return NOT_FOUND_ERROR.arg(it.key()); if (!runTests(it.value().toMap(), ret.first())) return DECL_ERROR.arg(it.key()); } return SUCCESS(); } ///JSON type: IndexDeclObject ///@returns whether a declaration exists at each index and each declaration passes its tests ContextTest(declarations) { VERIFY_TYPE(QVariantMap); QString INVALID_ERROR = "Attempted to test invalid context."; QString NOT_FOUND_ERROR = "No declaration at index \"%1\"."; QString DECL_ERROR = "Declaration at index \"%1\" did not pass tests."; if (!ctxt) return INVALID_ERROR; QVariantMap findDecls = value.toMap(); for (QVariantMap::iterator it = findDecls.begin(); it != findDecls.end(); ++it) { int index = it.key().toInt(); - QVector decls = ctxt->localDeclarations(0); + QVector decls = ctxt->localDeclarations(nullptr); if (decls.size() <= index) return NOT_FOUND_ERROR; if (!runTests(it.value().toMap(), decls.at(index))) return DECL_ERROR.arg(it.key()); } return SUCCESS(); } ///JSON type: int ///@returns whether the number of child contexts matches the given value ContextTest(childCount) { return compareValues(ctxt->childContexts().size(), value, "Context's child count"); } ///JSON type: int ///@returns whether the number of local declarations matches the given value ContextTest(localDeclarationCount) { return compareValues(ctxt->localDeclarations().size(), value, "Context's local declaration count"); } ///JSON type: string ///@returns whether the context's type matches the given value ContextTest(type) { QString contextTypeString; switch(ctxt->type()) { case DUContext::Class: contextTypeString = "Class"; break; case DUContext::Enum: contextTypeString = "Enum"; break; case DUContext::Namespace: contextTypeString = "Namespace"; break; case DUContext::Function: contextTypeString = "Function"; break; case DUContext::Template: contextTypeString = "Template"; break; case DUContext::Global: contextTypeString = "Global"; break; case DUContext::Helper: contextTypeString = "Helper"; break; case DUContext::Other: contextTypeString = "Other"; break; } return compareValues(contextTypeString, value, "Context's type"); } ///JSON type: bool ///@returns whether the context's nullity matches the given value ContextTest(null) { - return compareValues(ctxt == 0, value, "Context's nullity"); + return compareValues(ctxt == nullptr, value, "Context's nullity"); } //JSON type: DeclTestObject ///@returns the context's owner ContextTest(owner) { return testObject(ctxt->owner(), value, "Context's owner"); } ///JSON type: IndexCtxtObject ///@returns whether a context exists at each index and each context passes its tests ContextTest(importedParents) { VERIFY_TYPE(QVariantMap); QString INVALID_ERROR = "Attempted to test invalid context."; QString NOT_FOUND_ERROR = "No imported context at index \"%1\"."; QString CONTEXT_ERROR = "Context at index \"%1\" did not pass tests."; if (!ctxt) return INVALID_ERROR; QVariantMap findDecls = value.toMap(); for (QVariantMap::iterator it = findDecls.begin(); it != findDecls.end(); ++it) { int index = it.key().toInt(); QVector imports = ctxt->importedParentContexts(); if (imports.size() <= index) return NOT_FOUND_ERROR; if (!runTests(it.value().toMap(), imports.at(index).context(ctxt->topContext()))) return CONTEXT_ERROR.arg(it.key()); } return SUCCESS(); } ///JSON type: string ///@returns stringified context range ContextTest(range) { if (!ctxt) { return "Invalid Context"; } return compareValues(rangeStr(ctxt->range()), value, "Contexts's range"); } } } #endif //KDEVPLATFORM_JSONDUCONTEXTTESTS_H diff --git a/plugins/cmake/tests/cmakeparsertest.cpp b/plugins/cmake/tests/cmakeparsertest.cpp index e40cdbd293..5c165ef9e6 100644 --- a/plugins/cmake/tests/cmakeparsertest.cpp +++ b/plugins/cmake/tests/cmakeparsertest.cpp @@ -1,127 +1,127 @@ /* KDevelop CMake Support * * Copyright 2006 Matt Rogers * * 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 "cmakeparsertest.h" #include #include "cmListFileLexer.h" #include "cmakelistsparser.h" CMakeParserTest::CMakeParserTest() {} CMakeParserTest::~CMakeParserTest() {} void CMakeParserTest::testLexerCreation() { cmListFileLexer* lexer = cmListFileLexer_New(); - QVERIFY( lexer != 0 ); + QVERIFY( lexer != nullptr ); cmListFileLexer_Delete( lexer ); } void CMakeParserTest::testLexerWithFile() { QTemporaryFile tempFile; tempFile.setAutoRemove( false ); tempFile.open(); if ( !QFile::exists( tempFile.fileName() ) ) QFAIL( "Unable to open temporary file" ); QString tempName = tempFile.fileName(); tempFile.close(); //hacks to the get name of the file cmListFileLexer* lexer = cmListFileLexer_New(); if ( !lexer ) QFAIL( "unable to create lexer" ); QVERIFY( cmListFileLexer_SetFileName( lexer, qPrintable( tempName ), nullptr ) ); cmListFileLexer_Delete( lexer ); tempFile.remove(); } void CMakeParserTest::testParserWithGoodData() { // QFAIL( "the magic is missing" ); QFETCH( QString, text ); QTemporaryFile tempFile; tempFile.setAutoRemove( false ); tempFile.open(); if ( !QFile::exists( tempFile.fileName() ) ) QFAIL( "Unable to open temporary file" ); tempFile.write( text.toUtf8() ); QString tempName = tempFile.fileName(); tempFile.close(); //hacks to the get name of the file const bool parseError = CMakeListsParser::readCMakeFile( tempName ).isEmpty(); QVERIFY( parseError == false ); tempFile.remove(); } void CMakeParserTest::testParserWithGoodData_data() { QTest::addColumn( "text" ); QTest::newRow( "good data1" ) << "project(foo)\nset(foobar_SRCS foo.h foo.c)"; QTest::newRow( "good data2" ) << "set(foobar_SRCS foo.h foo.c)\n" "add_executable( foo ${foobar_SRCS})"; QTest::newRow( "test data" ) << "add_test(mytest \"mytest\")\n"; } void CMakeParserTest::testParserWithBadData() { QFETCH( QString, text ); QTemporaryFile tempFile; tempFile.setAutoRemove( false ); tempFile.open(); if ( !QFile::exists( tempFile.fileName() ) ) QFAIL( "Unable to open temporary file" ); tempFile.write( text.toUtf8() ); QString tempName = tempFile.fileName(); tempFile.close(); //hacks to the get name of the file // CMakeAst* ast = new CMakeAst; // bool parseError = CMakeListsParser::parseCMakeFile( ast, qPrintable( tempName ) ); // delete ast; // QVERIFY( parseError == true ); tempFile.remove(); } void CMakeParserTest::testParserWithBadData_data() { QTest::addColumn( "text" ); //just plain wrong. :) QTest::newRow( "bad data 1" ) << "foo bar baz zippedy do dah"; //missing right parenthesis QTest::newRow( "bad data 2" ) << "set(mysrcs_SRCS foo.c\n\n\n"; //extra identifiers between functions. cmake doesn't allow plain identifiers QTest::newRow( "bad data 3" ) << "the(quick) brown fox jumped(over) the lazy dog"; //invalid due to no newline before next command QTest::newRow( "bad data 4" ) << "project(foo) set(mysrcs_SRCS foo.c)"; } // void CMakeParserTest::testAstCreation() // { // } QTEST_GUILESS_MAIN( CMakeParserTest ) diff --git a/plugins/cvs/tests/test_cvs.cpp b/plugins/cvs/tests/test_cvs.cpp index 86332b186c..fdb36489b5 100644 --- a/plugins/cvs/tests/test_cvs.cpp +++ b/plugins/cvs/tests/test_cvs.cpp @@ -1,144 +1,144 @@ /*************************************************************************** * Copyright 2007 Robert Gruber * * * * 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_cvs.h" #include #include #include #include #include #include #include #define CVSTEST_BASEDIR "/tmp/kdevcvs_testdir/" #define CVS_REPO CVSTEST_BASEDIR "repo/" #define CVS_IMPORT CVSTEST_BASEDIR "import/" #define CVS_TESTFILE_NAME "testfile" #define CVS_CHECKOUT CVSTEST_BASEDIR "working/" void TestCvs::initTestCase() { KDevelop::AutoTestShell::init(); KDevelop::TestCore::initialize(KDevelop::Core::NoUi); m_proxy = new CvsProxy; // If the basedir for this cvs test exists from a // previous run; remove it... cleanup(); } void TestCvs::cleanupTestCase() { KDevelop::TestCore::shutdown(); delete m_proxy; } void TestCvs::init() { // Now create the basic directory structure QDir tmpdir(QStringLiteral("/tmp")); tmpdir.mkdir(CVSTEST_BASEDIR); tmpdir.mkdir(CVS_REPO); tmpdir.mkdir(CVS_IMPORT); } void TestCvs::cleanup() { if ( QFileInfo::exists(CVSTEST_BASEDIR) ) KIO::del(QUrl::fromLocalFile(QStringLiteral(CVSTEST_BASEDIR)))->exec(); } void TestCvs::repoInit() { // make job that creates the local repository - CvsJob* j = new CvsJob(0); + CvsJob* j = new CvsJob(nullptr); QVERIFY( j ); j->setDirectory(CVSTEST_BASEDIR); *j << "cvs" << "-d" << CVS_REPO << "init"; // try to start the job QVERIFY( j->exec() ); //check if the CVSROOT directory in the new local repository exists now QVERIFY( QFileInfo::exists(QString(CVS_REPO "/CVSROOT")) ); } void TestCvs::importTestData() { // create a file so we don't import an empty dir QFile f(CVS_IMPORT "" CVS_TESTFILE_NAME); if(f.open(QIODevice::WriteOnly)) { QTextStream input( &f ); input << "HELLO WORLD"; } f.flush(); CvsJob* j = m_proxy->import(QUrl::fromLocalFile(CVS_IMPORT), CVS_REPO, QStringLiteral("test"), QStringLiteral("vendor"), QStringLiteral("release"), QStringLiteral("test import message")); QVERIFY( j ); // try to start the job QVERIFY( j->exec() ); //check if the directory has been added to the repository QString testdir(CVS_REPO "/test"); QVERIFY( QFileInfo::exists(testdir) ); //check if the file has been added to the repository QString testfile(CVS_REPO "/test/" CVS_TESTFILE_NAME ",v"); QVERIFY( QFileInfo::exists(testfile) ); } void TestCvs::checkoutTestData() { CvsJob* j = m_proxy->checkout(QUrl::fromLocalFile(CVS_CHECKOUT), CVS_REPO, QStringLiteral("test")); QVERIFY( j ); // try to start the job QVERIFY( j->exec() ); //check if the directory is there QString testdir(CVS_CHECKOUT); QVERIFY( QFileInfo::exists(testdir) ); //check if the file is there QString testfile(CVS_CHECKOUT "" CVS_TESTFILE_NAME); QVERIFY( QFileInfo::exists(testfile) ); } void TestCvs::testInitAndImport() { repoInit(); importTestData(); checkoutTestData(); } void TestCvs::testLogFolder() { repoInit(); importTestData(); checkoutTestData(); QString testdir(CVS_CHECKOUT); KDevelop::VcsRevision rev = KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Head); CvsJob* job = m_proxy->log(QUrl::fromLocalFile(testdir), rev); QVERIFY(job); } QTEST_MAIN(TestCvs) diff --git a/plugins/gdb/memviewdlg.cpp b/plugins/gdb/memviewdlg.cpp index 2907db2593..87f7fe9ef6 100644 --- a/plugins/gdb/memviewdlg.cpp +++ b/plugins/gdb/memviewdlg.cpp @@ -1,470 +1,470 @@ /*************************************************************************** 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 { 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('*'); 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(0, 16); + 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('&', QLatin1String("&&")); m_toolBox->setItemText(m_toolBox->indexOf(ncs), cap); } } // end of namespace GDB } // end of namespace KDevMI diff --git a/plugins/ghprovider/ghproviderwidget.cpp b/plugins/ghprovider/ghproviderwidget.cpp index e22e811037..5e7e06a247 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 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")), QLatin1String(""), 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(0, i18n("The Git plugin could not be loaded which is required to import a GitHub project."), i18n("GitHub Provider Error")); + 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 = "https://" + m_account->token() + "@" + url.mid(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(); foreach (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