diff --git a/debugger/breakpoint/breakpointmodel.cpp b/debugger/breakpoint/breakpointmodel.cpp index c1b68b49fb..8de7e8faa9 100644 --- a/debugger/breakpoint/breakpointmodel.cpp +++ b/debugger/breakpoint/breakpointmodel.cpp @@ -1,640 +1,640 @@ /* This file is part of the KDE project Copyright (C) 2002 Matthias Hoelzer-Kluepfel Copyright (C) 2002 John Firebaugh Copyright (C) 2006, 2008 Vladimir Prus Copyright (C) 2007 Hamish Rodda Copyright (C) 2009 Niko Sams 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, see . */ #include "breakpointmodel.h" #include #include #include #include #include #include #include "../interfaces/icore.h" #include "../interfaces/idebugcontroller.h" #include "../interfaces/idocumentcontroller.h" #include "../interfaces/idocument.h" #include "../interfaces/ipartcontroller.h" #include #include #include #include "util/debug.h" #include "breakpoint.h" #include #include #include #include #include #define IF_DEBUG(x) using namespace KDevelop; using namespace KTextEditor; namespace { IBreakpointController* breakpointController() { KDevelop::ICore* core = KDevelop::ICore::self(); if (!core) { return nullptr; } IDebugController* controller = core->debugController(); if (!controller) { return nullptr; } IDebugSession* session = controller->currentSession(); return session ? session->breakpointController() : nullptr; } } // anonymous namespace BreakpointModel::BreakpointModel(QObject* parent) : QAbstractTableModel(parent), m_dontUpdateMarks(false) { connect(this, &BreakpointModel::dataChanged, this, &BreakpointModel::updateMarks); if (KDevelop::ICore::self()->partController()) { //TODO remove if foreach(KParts::Part* p, KDevelop::ICore::self()->partController()->parts()) slotPartAdded(p); connect(KDevelop::ICore::self()->partController(), &IPartController::partAdded, this, &BreakpointModel::slotPartAdded); } connect (KDevelop::ICore::self()->documentController(), &IDocumentController::textDocumentCreated, this, &BreakpointModel::textDocumentCreated); connect (KDevelop::ICore::self()->documentController(), &IDocumentController::documentSaved, this, &BreakpointModel::documentSaved); } BreakpointModel::~BreakpointModel() { qDeleteAll(m_breakpoints); } void BreakpointModel::slotPartAdded(KParts::Part* part) { if (KTextEditor::Document* doc = dynamic_cast(part)) { MarkInterface *iface = dynamic_cast(doc); if( !iface ) return; iface->setMarkDescription((MarkInterface::MarkTypes)BreakpointMark, i18n("Breakpoint")); iface->setMarkPixmap((MarkInterface::MarkTypes)BreakpointMark, *breakpointPixmap()); iface->setMarkPixmap((MarkInterface::MarkTypes)PendingBreakpointMark, *pendingBreakpointPixmap()); iface->setMarkPixmap((MarkInterface::MarkTypes)ReachedBreakpointMark, *reachedBreakpointPixmap()); iface->setMarkPixmap((MarkInterface::MarkTypes)DisabledBreakpointMark, *disabledBreakpointPixmap()); iface->setEditableMarks( MarkInterface::Bookmark | BreakpointMark ); updateMarks(); } } void BreakpointModel::textDocumentCreated(KDevelop::IDocument* doc) { KTextEditor::MarkInterface *iface = qobject_cast(doc->textDocument()); if (iface) { // can't use new signal slot syntax here, MarkInterface is not a QObject connect(doc->textDocument(), SIGNAL( markChanged(KTextEditor::Document*, KTextEditor::Mark, KTextEditor::MarkInterface::MarkChangeAction)), this, SLOT(markChanged(KTextEditor::Document*, KTextEditor::Mark, KTextEditor::MarkInterface::MarkChangeAction))); connect(doc->textDocument(), SIGNAL(markContextMenuRequested(KTextEditor::Document*, KTextEditor::Mark, QPoint, bool&)), SLOT(markContextMenuRequested(KTextEditor::Document*, KTextEditor::Mark, QPoint, bool&))); } } void BreakpointModel::markContextMenuRequested(Document* document, Mark mark, const QPoint &pos, bool& handled) { int type = mark.type; qCDebug(DEBUGGER) << type; /* Is this a breakpoint mark, to begin with? */ if (!(type & AllBreakpointMarks)) return; Breakpoint *b = breakpoint(document->url(), mark.line); if (!b) { - QMessageBox::critical(nullptr, i18n("Breakpoint not found"), i18n("Couldn't find breakpoing at %1:%2", document->url().toString(), mark.line)); + QMessageBox::critical(nullptr, i18n("Breakpoint not found"), i18n("Couldn't find breakpoint at %1:%2", document->url().toString(), mark.line)); return; } QMenu menu; QAction deleteAction(QIcon::fromTheme("edit-delete"), i18n("&Delete Breakpoint"), 0); QAction disableAction(QIcon::fromTheme("dialog-cancel"), i18n("&Disable Breakpoint"), 0); QAction enableAction(QIcon::fromTheme("dialog-ok-apply"), i18n("&Enable Breakpoint"), 0); menu.addAction(&deleteAction); if (b->enabled()) { menu.addAction(&disableAction); } else { menu.addAction(&enableAction); } QAction *a = menu.exec(pos); if (a == &deleteAction) { b->setDeleted(); } else if (a == &disableAction) { b->setData(Breakpoint::EnableColumn, Qt::Unchecked); } else if (a == &enableAction) { b->setData(Breakpoint::EnableColumn, Qt::Checked); } handled = true; } QVariant BreakpointModel::headerData(int section, Qt::Orientation orientation, int role) const { if (orientation == Qt::Vertical) return QVariant(); if (role == Qt::DecorationRole ) { if (section == 0) return QIcon::fromTheme("dialog-ok-apply"); else if (section == 1) return QIcon::fromTheme("system-switch-user"); } if (role == Qt::DisplayRole) { if (section == 0 || section == 1) return ""; if (section == 2) return i18n("Type"); if (section == 3) return i18n("Location"); if (section == 4) return i18n("Condition"); } if (role == Qt::ToolTipRole) { if (section == 0) return i18n("Active status"); if (section == 1) return i18n("State"); return headerData(section, orientation, Qt::DisplayRole); } return QVariant(); } Qt::ItemFlags BreakpointModel::flags(const QModelIndex &index) const { /* FIXME: all this logic must be in item */ if (!index.isValid()) return 0; if (index.column() == 0) return static_cast( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsUserCheckable); if (index.column() == Breakpoint::LocationColumn || index.column() == Breakpoint::ConditionColumn) return static_cast( Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable); return static_cast(Qt::ItemIsEnabled | Qt::ItemIsSelectable); } QModelIndex BreakpointModel::breakpointIndex(KDevelop::Breakpoint* b, int column) { int row = m_breakpoints.indexOf(b); if (row == -1) return QModelIndex(); return index(row, column); } bool KDevelop::BreakpointModel::removeRows(int row, int count, const QModelIndex& parent) { if (count < 1 || (row < 0) || (row + count) > rowCount(parent)) return false; IBreakpointController* controller = breakpointController(); beginRemoveRows(parent, row, row+count-1); for (int i=0; i < count; ++i) { Breakpoint* b = m_breakpoints.at(row); b->m_deleted = true; if (controller) controller->breakpointAboutToBeDeleted(row); m_breakpoints.removeAt(row); b->m_model = 0; // To be changed: the controller is currently still responsible for deleting the breakpoint // object } endRemoveRows(); updateMarks(); scheduleSave(); return true; } int KDevelop::BreakpointModel::rowCount(const QModelIndex& parent) const { if (!parent.isValid()) { return m_breakpoints.count(); } return 0; } int KDevelop::BreakpointModel::columnCount(const QModelIndex& parent) const { Q_UNUSED(parent); return 5; } QVariant BreakpointModel::data(const QModelIndex& index, int role) const { if (!index.parent().isValid() && index.row() < m_breakpoints.count()) { return m_breakpoints.at(index.row())->data(index.column(), role); } return QVariant(); } bool KDevelop::BreakpointModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!index.parent().isValid() && index.row() < m_breakpoints.count() && (role == Qt::EditRole || role == Qt::CheckStateRole)) { return m_breakpoints.at(index.row())->setData(index.column(), value); } return false; } void BreakpointModel::updateState(int row, Breakpoint::BreakpointState state) { Breakpoint* breakpoint = m_breakpoints.at(row); if (state != breakpoint->m_state) { breakpoint->m_state = state; reportChange(breakpoint, Breakpoint::StateColumn); } } void BreakpointModel::updateHitCount(int row, int hitCount) { Breakpoint* breakpoint = m_breakpoints.at(row); if (hitCount != breakpoint->m_hitCount) { breakpoint->m_hitCount = hitCount; reportChange(breakpoint, Breakpoint::HitCountColumn); } } void BreakpointModel::updateErrorText(int row, const QString& errorText) { Breakpoint* breakpoint = m_breakpoints.at(row); if (breakpoint->m_errorText != errorText) { breakpoint->m_errorText = errorText; reportChange(breakpoint, Breakpoint::StateColumn); } if (!errorText.isEmpty()) { emit error(row, errorText); } } void BreakpointModel::notifyHit(int row) { emit hit(row); } void BreakpointModel::markChanged( KTextEditor::Document *document, KTextEditor::Mark mark, KTextEditor::MarkInterface::MarkChangeAction action) { int type = mark.type; /* Is this a breakpoint mark, to begin with? */ if (!(type & AllBreakpointMarks)) return; if (action == KTextEditor::MarkInterface::MarkAdded) { Breakpoint *b = breakpoint(document->url(), mark.line); if (b) { //there was already a breakpoint, so delete instead of adding b->setDeleted(); return; } Breakpoint *breakpoint = addCodeBreakpoint(document->url(), mark.line); KTextEditor::MovingInterface *moving = qobject_cast(document); if (moving) { KTextEditor::MovingCursor* cursor = moving->newMovingCursor(KTextEditor::Cursor(mark.line, 0)); // can't use new signal/slot syntax here, MovingInterface is not a QObject connect(document, SIGNAL(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)), this, SLOT(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)), Qt::UniqueConnection); breakpoint->setMovingCursor(cursor); } } else { // Find this breakpoint and delete it Breakpoint *b = breakpoint(document->url(), mark.line); if (b) { b->setDeleted(); } } #if 0 if ( KDevelop::ICore::self()->documentController()->activeDocument() && KDevelop::ICore::self()->documentController()->activeDocument()->textDocument() == document ) { //bring focus back to the editor // TODO probably want a different command here KDevelop::ICore::self()->documentController()->activateDocument(KDevelop::ICore::self()->documentController()->activeDocument()); } #endif } const QPixmap* BreakpointModel::breakpointPixmap() { static QPixmap pixmap=QIcon::fromTheme("script-error").pixmap(QSize(22,22), QIcon::Active, QIcon::Off); return &pixmap; } const QPixmap* BreakpointModel::pendingBreakpointPixmap() { static QPixmap pixmap=QIcon::fromTheme("script-error").pixmap(QSize(22,22), QIcon::Normal, QIcon::Off); return &pixmap; } const QPixmap* BreakpointModel::reachedBreakpointPixmap() { static QPixmap pixmap=QIcon::fromTheme("script-error").pixmap(QSize(22,22), QIcon::Selected, QIcon::Off); return &pixmap; } const QPixmap* BreakpointModel::disabledBreakpointPixmap() { static QPixmap pixmap=QIcon::fromTheme("script-error").pixmap(QSize(22,22), QIcon::Disabled, QIcon::Off); return &pixmap; } void BreakpointModel::toggleBreakpoint(const QUrl& url, const KTextEditor::Cursor& cursor) { Breakpoint *b = breakpoint(url, cursor.line()); if (b) { b->setDeleted(); } else { addCodeBreakpoint(url, cursor.line()); } } void BreakpointModel::reportChange(Breakpoint* breakpoint, Breakpoint::Column column) { // note: just a portion of Breakpoint::Column is displayed in this model! if (column >= 0 && column < columnCount()) { QModelIndex idx = breakpointIndex(breakpoint, column); Q_ASSERT(idx.isValid()); // make sure we don't pass invalid indices to dataChanged() emit dataChanged(idx, idx); } if (IBreakpointController* controller = breakpointController()) { int row = m_breakpoints.indexOf(breakpoint); Q_ASSERT(row != -1); controller->breakpointModelChanged(row, ColumnFlags(1 << column)); } scheduleSave(); } uint BreakpointModel::breakpointType(Breakpoint *breakpoint) { uint type = BreakpointMark; if (!breakpoint->enabled()) { type = DisabledBreakpointMark; } else if (breakpoint->hitCount() > 0) { type = ReachedBreakpointMark; } else if (breakpoint->state() == Breakpoint::PendingState) { type = PendingBreakpointMark; } return type; } void KDevelop::BreakpointModel::updateMarks() { if (m_dontUpdateMarks) return; //add marks foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->kind() != Breakpoint::CodeBreakpoint) continue; if (breakpoint->line() == -1) continue; IDocument *doc = ICore::self()->documentController()->documentForUrl(breakpoint->url()); if (!doc) continue; KTextEditor::MarkInterface *mark = qobject_cast(doc->textDocument()); if (!mark) continue; uint type = breakpointType(breakpoint); IF_DEBUG( qCDebug(DEBUGGER) << type << breakpoint->url() << mark->mark(breakpoint->line()); ) doc->textDocument()->blockSignals(true); if (mark->mark(breakpoint->line()) & AllBreakpointMarks) { if (!(mark->mark(breakpoint->line()) & type)) { mark->removeMark(breakpoint->line(), AllBreakpointMarks); mark->addMark(breakpoint->line(), type); } } else { mark->addMark(breakpoint->line(), type); } doc->textDocument()->blockSignals(false); } //remove marks foreach (IDocument *doc, ICore::self()->documentController()->openDocuments()) { KTextEditor::MarkInterface *mark = qobject_cast(doc->textDocument()); if (!mark) continue; doc->textDocument()->blockSignals(true); foreach (KTextEditor::Mark *m, mark->marks()) { if (!(m->type & AllBreakpointMarks)) continue; IF_DEBUG( qCDebug(DEBUGGER) << m->line << m->type; ) foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->kind() != Breakpoint::CodeBreakpoint) continue; if (doc->url() == breakpoint->url() && m->line == breakpoint->line()) { goto continueNextMark; } } mark->removeMark(m->line, AllBreakpointMarks); continueNextMark:; } doc->textDocument()->blockSignals(false); } } void BreakpointModel::documentSaved(KDevelop::IDocument* doc) { IF_DEBUG( qCDebug(DEBUGGER); ) foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->movingCursor()) { if (breakpoint->movingCursor()->document() != doc->textDocument()) continue; if (breakpoint->movingCursor()->line() == breakpoint->line()) continue; m_dontUpdateMarks = true; breakpoint->setLine(breakpoint->movingCursor()->line()); m_dontUpdateMarks = false; } } } void BreakpointModel::aboutToDeleteMovingInterfaceContent(KTextEditor::Document* document) { foreach (Breakpoint *breakpoint, m_breakpoints) { if (breakpoint->movingCursor() && breakpoint->movingCursor()->document() == document) { breakpoint->setMovingCursor(0); } } } void BreakpointModel::load() { KConfigGroup breakpoints = ICore::self()->activeSession()->config()->group("Breakpoints"); int count = breakpoints.readEntry("number", 0); if (count == 0) return; beginInsertRows(QModelIndex(), 0, count - 1); for (int i = 0; i < count; ++i) { if (!breakpoints.group(QString::number(i)).readEntry("kind", "").isEmpty()) { new Breakpoint(this, breakpoints.group(QString::number(i))); } } endInsertRows(); } void BreakpointModel::save() { m_dirty = false; KConfigGroup breakpoints = ICore::self()->activeSession()->config()->group("Breakpoints"); breakpoints.writeEntry("number", m_breakpoints.count()); int i = 0; foreach (Breakpoint *b, m_breakpoints) { KConfigGroup g = breakpoints.group(QString::number(i)); b->save(g); ++i; } breakpoints.sync(); } void BreakpointModel::scheduleSave() { if (m_dirty) return; m_dirty = true; QTimer::singleShot(0, this, SLOT(save())); } QList KDevelop::BreakpointModel::breakpoints() const { return m_breakpoints; } Breakpoint* BreakpointModel::breakpoint(int row) { if (row >= m_breakpoints.count()) return 0; return m_breakpoints.at(row); } Breakpoint* BreakpointModel::addCodeBreakpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::CodeBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addCodeBreakpoint(const QUrl& url, int line) { Breakpoint* n = addCodeBreakpoint(); n->setLocation(url, line); return n; } Breakpoint* BreakpointModel::addCodeBreakpoint(const QString& expression) { Breakpoint* n = addCodeBreakpoint(); n->setExpression(expression); return n; } Breakpoint* BreakpointModel::addWatchpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::WriteBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addWatchpoint(const QString& expression) { Breakpoint* n = addWatchpoint(); n->setExpression(expression); return n; } Breakpoint* BreakpointModel::addReadWatchpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::ReadBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addReadWatchpoint(const QString& expression) { Breakpoint* n = addReadWatchpoint(); n->setExpression(expression); return n; } Breakpoint* BreakpointModel::addAccessWatchpoint() { beginInsertRows(QModelIndex(), m_breakpoints.count(), m_breakpoints.count()); Breakpoint* n = new Breakpoint(this, Breakpoint::AccessBreakpoint); endInsertRows(); return n; } Breakpoint* BreakpointModel::addAccessWatchpoint(const QString& expression) { Breakpoint* n = addAccessWatchpoint(); n->setExpression(expression); return n; } void BreakpointModel::registerBreakpoint(Breakpoint* breakpoint) { Q_ASSERT(!m_breakpoints.contains(breakpoint)); int row = m_breakpoints.size(); m_breakpoints << breakpoint; if (IBreakpointController* controller = breakpointController()) { controller->breakpointAdded(row); } scheduleSave(); } Breakpoint* BreakpointModel::breakpoint(const QUrl& url, int line) { foreach (Breakpoint *b, m_breakpoints) { if (b->url() == url && b->line() == line) { return b; } } return 0; } diff --git a/documentation/standarddocumentationview.cpp b/documentation/standarddocumentationview.cpp index c6fddfe762..a9185fd592 100644 --- a/documentation/standarddocumentationview.cpp +++ b/documentation/standarddocumentationview.cpp @@ -1,65 +1,65 @@ /* * This file is part of KDevelop * Copyright 2010 Aleix Pol Gonzalez * * 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" using namespace KDevelop; StandardDocumentationView::StandardDocumentationView(DocumentationFindWidget* findWidget, QWidget* parent) : QWebView (parent) { findWidget->setEnabled(true); connect(findWidget, &DocumentationFindWidget::newSearch, this, &StandardDocumentationView::search); } void StandardDocumentationView::search ( const QString& text, DocumentationFindWidget::FindOptions options ) { //Highlighting has been commented because it doesn't let me jump around all occurrences // page()->findText(QString(), QWebPage::HighlightAllOccurrences); QWebPage::FindFlags ff=QWebPage::FindWrapsAroundDocument /*| QWebPage::HighlightAllOccurrences*/; if(options & DocumentationFindWidget::Previous) ff |= QWebPage::FindBackward; if(options & DocumentationFindWidget::MatchCase) ff |= QWebPage::FindCaseSensitively; page()->findText(text, ff); } void StandardDocumentationView::setDocumentation(const IDocumentation::Ptr& doc) { if(m_doc) disconnect(m_doc.data()); m_doc = doc; update(); if(m_doc) connect(m_doc.data(), &IDocumentation::descriptionChanged, this, &StandardDocumentationView::update); } void StandardDocumentationView::update() { if(m_doc) setHtml(m_doc->description()); else - qCDebug(DOCUMENTATION) << "calling StandardDocumentationView::update() on an unitialized view"; + qCDebug(DOCUMENTATION) << "calling StandardDocumentationView::update() on an uninitialized view"; } diff --git a/language/assistant/staticassistantsmanager.h b/language/assistant/staticassistantsmanager.h index 89fcce844d..ab5430ea81 100644 --- a/language/assistant/staticassistantsmanager.h +++ b/language/assistant/staticassistantsmanager.h @@ -1,77 +1,77 @@ /* Copyright 2009 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 KDEVPLATFORM_STATICASSISTANTSMANAGER_H #define KDEVPLATFORM_STATICASSISTANTSMANAGER_H #include #include #include "staticassistant.h" #include #include #include #include class QTimer; typedef QPointer SafeDocumentPointer; namespace KDevelop { class IDocument; class ParseJob; class DUContext; class TopDUContext; /** * @brief Class managing instances of StaticAssistant * - * Invokes the appropiate methods on registered StaticAssistant instances, such as StaticAssistant::textChanged + * Invokes the appropriate methods on registered StaticAssistant instances, such as StaticAssistant::textChanged * * @sa StaticAssistant::textChanged */ class KDEVPLATFORMLANGUAGE_EXPORT StaticAssistantsManager : public QObject { Q_OBJECT public: StaticAssistantsManager(QObject* parent = 0); virtual ~StaticAssistantsManager(); QExplicitlySharedDataPointer activeAssistant(); void registerAssistant(const StaticAssistant::Ptr assistant); void unregisterAssistant(const StaticAssistant::Ptr assistant); QList registeredAssistants() const; public slots: void hideAssistant(); private: struct Private; QScopedPointer const d; Q_PRIVATE_SLOT(d, void eventuallyStartAssistant()) }; } #endif // KDEVPLATFORM_STATICASSISTANTSMANAGER_H diff --git a/language/backgroundparser/documentchangetracker.h b/language/backgroundparser/documentchangetracker.h index f1f9c045b6..bacd0b5b65 100644 --- a/language/backgroundparser/documentchangetracker.h +++ b/language/backgroundparser/documentchangetracker.h @@ -1,270 +1,269 @@ /* * This file is part of KDevelop * * Copyright 2010 David Nolden * * 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. */ #ifndef KDEVPLATFORM_DOCUMENTCHANGETRACKER_H #define KDEVPLATFORM_DOCUMENTCHANGETRACKER_H #include #include #include #include -#include #include #include #include #include namespace KTextEditor { class Document; class MovingRange; class MovingInterface; } namespace KDevelop { class DocumentChangeTracker; /** * These objects belongs to the foreground, and thus can only be accessed from background threads if the foreground lock is held. * */ class RevisionLockerAndClearerPrivate; /** * Helper class that locks a revision, and clears it on its destruction within the foreground thread. * Just delete it using deleteLater(). * */ class KDEVPLATFORMLANGUAGE_EXPORT RevisionLockerAndClearer : public QSharedData { public: typedef QExplicitlySharedDataPointer Ptr; ~RevisionLockerAndClearer(); /** * Returns the revision number * */ qint64 revision() const; /** * Whether the revision is still being held. It may have been lost due to document-reloads, * in which case the revision must not be used. * */ bool valid() const; /** * Transform a range from this document revision to the given @p to. * */ RangeInRevision transformToRevision(const RangeInRevision& range, const Ptr& to) const; /** * Transform a cursor from this document revision to the given @p to. * If a zero target revision is given, the transformation is done to the current document revision. * */ CursorInRevision transformToRevision(const CursorInRevision& cursor, const Ptr& to, KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; /** * Transforms the given range from this revision into the current revision. */ KTextEditor::Range transformToCurrentRevision(const RangeInRevision& range) const; /** * Transforms the given cursor from this revision into the current revision. */ KTextEditor::Cursor transformToCurrentRevision(const CursorInRevision& cursor, KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; /** * Transform ranges from the given document revision @p from to the this one. * If a zero @p from revision is given, the transformation is done from the current document revision. * */ RangeInRevision transformFromRevision(const RangeInRevision& range, const Ptr& from = Ptr()) const; /** * Transform ranges from the given document revision @p from to the this one. * If a zero @p from revision is given, the transformation is done from the current document revision. * */ CursorInRevision transformFromRevision(const CursorInRevision& cursor, const Ptr& from = Ptr(), KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; /** * Transforms the given range from the current revision into this revision. */ RangeInRevision transformFromCurrentRevision(const KTextEditor::Range& range) const; /** * Transforms the given cursor from the current revision into this revision. */ CursorInRevision transformFromCurrentRevision(const KTextEditor::Cursor& cursor, KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; private: friend class DocumentChangeTracker; RevisionLockerAndClearerPrivate* m_p; }; typedef RevisionLockerAndClearer::Ptr RevisionReference; /** * Internal helper class for RevisionLockerAndClearer * */ class KDEVPLATFORMLANGUAGE_EXPORT RevisionLockerAndClearerPrivate : public QObject { Q_OBJECT public: RevisionLockerAndClearerPrivate(DocumentChangeTracker* tracker, qint64 revision); ~RevisionLockerAndClearerPrivate(); inline qint64 revision() const { return m_revision; } private: friend class RevisionLockerAndClearer; QPointer m_tracker; qint64 m_revision; }; class KDEVPLATFORMLANGUAGE_EXPORT DocumentChangeTracker : public QObject { Q_OBJECT public: DocumentChangeTracker( KTextEditor::Document* document ); virtual ~DocumentChangeTracker(); /** * Completions of the users current edits that are supposed to complete * not-yet-finished statements, like for example for-loops for parsing. * */ virtual QList > completions() const; /** * Resets the tracking to the current revision. * */ virtual void reset(); /** * Returns the document revision at which reset() was called last. * * The revision is being locked by the tracker in MovingInterface, * it will be unlocked as soon as reset() is called, so if you want to use * the revision afterwards, you have to lock it before calling reset. * * zero is returned if the revisions were invalidated after the last call. * */ RevisionReference revisionAtLastReset() const; /** * Returns the document text at the last reset * */ QString textAtLastReset() const; /** * Returns the current revision (which is not locked by the tracker) * */ RevisionReference currentRevision(); /** * Returns the range that was changed since the last reset * */ virtual KTextEditor::Range changedRange() const; /** * Whether the changes that happened since the last reset are significant enough to require an update * */ virtual bool needUpdate() const; /** * Returns the tracked document **/ KTextEditor::Document* document() const; KTextEditor::MovingInterface* documentMovingInterface() const; /** * Returns the revision object which locks the revision representing the on-disk state. * Returns a zero object if the file is not on disk. * */ RevisionReference diskRevision() const; /** * Returns whether the given revision is being current held, so that it can be used * for transformations in MovingInterface * */ bool holdingRevision(qint64 revision) const; /** * Use this function to acquire a revision. As long as the returned object is stored somewhere, * the revision can be used for transformations in MovingInterface, and especially for * DocumentChangeTracker::transformBetweenRevisions. * * Returns a zero revision object if the revision could not be acquired (it wasn't held). * */ RevisionReference acquireRevision(qint64 revision); /** * Safely maps the given range between the two given revisions. * The mapping is only done if both the from- and to- revision are held, * else the original range is returned. * * @warning: Make sure that you actually hold the referenced revisions, else no transformation will be done. * @note It is much less error-prone to use RevisionReference->transformToRevision() and RevisionReference->transformFromRevision() directly. * */ RangeInRevision transformBetweenRevisions(RangeInRevision range, qint64 fromRevision, qint64 toRevision) const; CursorInRevision transformBetweenRevisions(CursorInRevision cursor, qint64 fromRevision, qint64 toRevision, KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; KTextEditor::Range transformToCurrentRevision(RangeInRevision range, qint64 fromRevision) const; KTextEditor::Cursor transformToCurrentRevision(CursorInRevision cursor, qint64 fromRevision, KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; /// Transform the range from the current revision into the given one RangeInRevision transformToRevision(KTextEditor::Range range, qint64 toRevision) const; /// Transform the cursor from the current revision into the given one CursorInRevision transformToRevision(KTextEditor::Cursor cursor, qint64 toRevision, KTextEditor::MovingCursor::InsertBehavior behavior = KTextEditor::MovingCursor::StayOnInsert) const; protected: QString m_textAtLastReset; RevisionReference m_revisionAtLastReset; bool m_needUpdate; QString m_currentCleanedInsertion; KTextEditor::Cursor m_lastInsertionPosition; KTextEditor::MovingRange* m_changedRange; KTextEditor::Document* m_document; KTextEditor::MovingInterface* m_moving; KDevelop::IndexedString m_url; void updateChangedRange(KTextEditor::Range changed); public slots: virtual void textInserted( KTextEditor::Document* document, const KTextEditor::Cursor& position, const QString& inserted ); virtual void textRemoved( KTextEditor::Document* document, const KTextEditor::Range& range, const QString& oldText ); void documentDestroyed( QObject* ); void aboutToInvalidateMovingInterfaceContent ( KTextEditor::Document* document ); void documentSavedOrUploaded(KTextEditor::Document*,bool); private: bool checkMergeTokens(const KTextEditor::Range& range); friend class RevisionLockerAndClearerPrivate; void lockRevision(qint64 revision); void unlockRevision(qint64 revision); QMap m_revisionLocks; ILanguageSupport::WhitespaceSensitivity m_whitespaceSensitivity; }; } #endif diff --git a/language/duchain/types/constantintegraltype.cpp b/language/duchain/types/constantintegraltype.cpp index 97b650b3e7..1b753710df 100644 --- a/language/duchain/types/constantintegraltype.cpp +++ b/language/duchain/types/constantintegraltype.cpp @@ -1,190 +1,188 @@ /* This file is part of KDevelop Copyright 2002-2005 Roberto Raggi Copyright 2006 Adam Treat Copyright 2006-2008 Hamish Rodda Copyright 2007-2008 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. */ #include "constantintegraltype.h" #include #include "util/debug.h" #include "typesystemdata.h" #include "typeregister.h" -#include - namespace KDevelop { REGISTER_TYPE(ConstantIntegralType); ConstantIntegralType::ConstantIntegralType(const ConstantIntegralType& rhs) : IntegralType(copyData(*rhs.d_func())) { } ConstantIntegralType::ConstantIntegralType(ConstantIntegralTypeData& data) : IntegralType(data) { } ConstantIntegralType::ConstantIntegralType(uint type) : IntegralType(createData()) { setDataType(type); setModifiers(ConstModifier); } qint64 ConstantIntegralType::plainValue() const { return d_func()->m_value; } AbstractType* ConstantIntegralType::clone() const { return new ConstantIntegralType(*this); } bool ConstantIntegralType::equals(const AbstractType* _rhs) const { if( this == _rhs ) return true; if (!IntegralType::equals(_rhs)) return false; Q_ASSERT(fastCast(_rhs)); const ConstantIntegralType* rhs = static_cast(_rhs); return d_func()->m_value == rhs->d_func()->m_value; } QString ConstantIntegralType::toString() const { QString ret; switch(dataType()) { case TypeNone: ret += "none"; break; case TypeChar: ret += QStringLiteral("char"); break; case TypeWchar_t: ret += QStringLiteral("wchar_t"); break; case TypeChar16_t: ret += QStringLiteral("char16_t"); break; case TypeChar32_t: ret += QStringLiteral("char32_t"); break; case TypeBoolean: ret += d_func()->m_value ? "true" : "false"; break; case TypeInt: ret += (modifiers() & UnsignedModifier) ? QStringLiteral("unsigned") : QStringLiteral("int"); break; case TypeFloat: ret += QStringLiteral("float"); break; case TypeDouble: ret += QStringLiteral("double"); break; case TypeVoid: ret += "void"; break; default: ret += ""; break; } return ret; } QString ConstantIntegralType::valueAsString() const { switch(dataType()) { case TypeNone: return "none"; case TypeChar: return QString::number((char)d_func()->m_value); case TypeWchar_t: return QString::number((wchar_t)d_func()->m_value); case TypeChar16_t: return QString::number((char16_t)d_func()->m_value); case TypeChar32_t: return QString::number((char32_t)d_func()->m_value); case TypeBoolean: return d_func()->m_value ? "true" : "false"; case TypeInt: return (modifiers() & UnsignedModifier) ? QString::number((uint)d_func()->m_value) : QString::number((int)d_func()->m_value); case TypeFloat: return QString::number(value()); case TypeDouble: return QString::number(value()); default: return QString(); } } uint ConstantIntegralType::hash() const { return KDevHash(IntegralType::hash()) << d_func()->m_value; } template<> KDEVPLATFORMLANGUAGE_EXPORT void ConstantIntegralType::setValueInternal(qint64 value) { if((modifiers() & UnsignedModifier)) { qCWarning(LANGUAGE) << "setValue(signed) called on unsigned type"; } d_func_dynamic()->m_value = value; } template<> KDEVPLATFORMLANGUAGE_EXPORT void ConstantIntegralType::setValueInternal(quint64 value) { if(!(modifiers() & UnsignedModifier)) { qCWarning(LANGUAGE) << "setValue(unsigned) called on not unsigned type"; } d_func_dynamic()->m_value = (qint64)value; } template<> KDEVPLATFORMLANGUAGE_EXPORT void ConstantIntegralType::setValueInternal(float value) { if(dataType() != TypeFloat) { qCWarning(LANGUAGE) << "setValue(float) called on non-float type"; } memcpy(&d_func_dynamic()->m_value, &value, sizeof(float)); } template<> KDEVPLATFORMLANGUAGE_EXPORT void ConstantIntegralType::setValueInternal(double value) { if(dataType() != TypeDouble) { qCWarning(LANGUAGE) << "setValue(double) called on non-double type"; } memcpy(&d_func_dynamic()->m_value, &value, sizeof(double)); } } diff --git a/plugins/bazaar/bazaarplugin.cpp b/plugins/bazaar/bazaarplugin.cpp index f6954bb5d4..a1f18af155 100644 --- a/plugins/bazaar/bazaarplugin.cpp +++ b/plugins/bazaar/bazaarplugin.cpp @@ -1,350 +1,350 @@ /*************************************************************************** * Copyright 2013-2014 Maciej Poleski * * * * 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 "bazaarplugin.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "bazaarutils.h" #include "bzrannotatejob.h" #include "copyjob.h" #include "diffjob.h" using namespace KDevelop; BazaarPlugin::BazaarPlugin(QObject* parent, const QVariantList& args) : IPlugin("kdevbazaar", parent), m_vcsPluginHelper(new KDevelop::VcsPluginHelper(this, this)), m_hasError(false) { Q_UNUSED(args); // What is this? if (QStandardPaths::findExecutable("bzr").isEmpty()) { m_hasError = true; m_errorDescription = i18n("Bazaar is not installed (bzr executable not" " found)"); return; } KDEV_USE_EXTENSION_INTERFACE(KDevelop::IBasicVersionControl) KDEV_USE_EXTENSION_INTERFACE(KDevelop::IDistributedVersionControl) setObjectName("Bazaar"); } BazaarPlugin::~BazaarPlugin() { } QString BazaarPlugin::name() const { return QString::fromUtf8("Bazaar"); } VcsJob* BazaarPlugin::add(const QList& localLocations, IBasicVersionControl::RecursionMode recursion) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocations[0]), this); job->setType(VcsJob::Add); *job << "bzr" << "add"; if(recursion == NonRecursive) *job << "--no-recurse"; *job << localLocations; return job; } VcsJob* BazaarPlugin::annotate(const QUrl& localLocation, const VcsRevision& rev) { VcsJob* job = new BzrAnnotateJob(BazaarUtils::workingCopy(localLocation), BazaarUtils::getRevisionSpec(rev), localLocation, this, KDevelop::OutputJob::Silent); return job; } VcsJob* BazaarPlugin::commit(const QString& message, const QList& localLocations, IBasicVersionControl::RecursionMode recursion) { QDir dir = BazaarUtils::workingCopy(localLocations[0]); DVcsJob* job = new DVcsJob(dir, this); job->setType(VcsJob::Commit); *job << "bzr" << "commit" << BazaarUtils::handleRecursion(localLocations, recursion) << "-m" << message; return job; } VcsJob* BazaarPlugin::copy(const QUrl& localLocationSrc, const QUrl& localLocationDstn) { return new CopyJob(localLocationSrc, localLocationDstn, this); } VcsImportMetadataWidget* BazaarPlugin::createImportMetadataWidget(QWidget* parent) { return new DvcsImportMetadataWidget(parent); } VcsJob* BazaarPlugin::createWorkingCopy(const VcsLocation& sourceRepository, const QUrl& destinationDirectory, IBasicVersionControl::RecursionMode recursion) { Q_UNUSED(recursion); // What is the purpose of recursion parameter? DVcsJob* job = new DVcsJob(BazaarUtils::toQDir(sourceRepository.localUrl()), this); job->setType(VcsJob::Import); *job << "bzr" << "branch" << sourceRepository.localUrl().url() << destinationDirectory; return job; } VcsJob* BazaarPlugin::diff(const QUrl& fileOrDirectory, const VcsRevision& srcRevision, const VcsRevision& dstRevision, VcsDiff::Type, IBasicVersionControl::RecursionMode recursion) { Q_UNUSED(recursion); VcsJob* job = new DiffJob(BazaarUtils::workingCopy(fileOrDirectory), BazaarUtils::getRevisionSpecRange(srcRevision, dstRevision), fileOrDirectory, this); return job; } VcsJob* BazaarPlugin::init(const QUrl& localRepositoryRoot) { DVcsJob* job = new DVcsJob(BazaarUtils::toQDir(localRepositoryRoot), this); job->setType(VcsJob::Import); *job << "bzr" << "init"; return job; } bool BazaarPlugin::isVersionControlled(const QUrl& localLocation) { QDir workCopy = BazaarUtils::workingCopy(localLocation); DVcsJob* job = new DVcsJob(workCopy, this, OutputJob::Silent); job->setType(VcsJob::Unknown); job->setIgnoreError(true); *job << "bzr" << "ls" << "--from-root" << "-R" << "-V"; job->exec(); if (job->status() == VcsJob::JobSucceeded) { QList filesAndDirectoriesList; for (QString fod : job->output().split('\n')) { filesAndDirectoriesList.append(QFileInfo(workCopy.absolutePath() + QDir::separator() + fod)); } QFileInfo fi(localLocation.toLocalFile()); if (fi.isDir() || fi.isFile()) { QFileInfo file(localLocation.toLocalFile()); return filesAndDirectoriesList.contains(file); } } return false; } VcsJob* BazaarPlugin::log(const QUrl& localLocation, const VcsRevision& rev, long unsigned int limit) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocation), this); job->setType(VcsJob::Log); *job << "bzr" << "log" << "--long" << "-v" << localLocation << BazaarUtils::getRevisionSpecRange(rev) << "-l" << QString::number(limit); connect(job, &DVcsJob::readyForParsing, this, &BazaarPlugin::parseBzrLog); return job; } VcsJob* BazaarPlugin::log(const QUrl& localLocation, const VcsRevision& rev, const VcsRevision& limit) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocation), this); job->setType(VcsJob::Log); *job << "bzr" << "log" << "--long" << "-v" << localLocation << BazaarUtils::getRevisionSpecRange(limit, rev); connect(job, &DVcsJob::readyForParsing, this, &BazaarPlugin::parseBzrLog); return job; } void BazaarPlugin::parseBzrLog(DVcsJob* job) { QVariantList result; for (QString part : job->output().split("------------------------------------------------------------", QString::SkipEmptyParts)) { auto event = BazaarUtils::parseBzrLogPart(part); if (event.revision().revisionType() != VcsRevision::Invalid) result.append(QVariant::fromValue(event)); } job->setResults(result); } VcsJob* BazaarPlugin::move(const QUrl& localLocationSrc, const QUrl& localLocationDst) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocationSrc), this); job->setType(VcsJob::JobType::Move); *job << "bzr" << "move" << localLocationSrc << localLocationDst; return job; } VcsJob* BazaarPlugin::pull(const VcsLocation& localOrRepoLocationSrc, const QUrl& localRepositoryLocation) { // API describes hg pull which is git fetch equivalent - // bzr has pull, but it succeds only if fast-forward is possible + // bzr has pull, but it succeeds only if fast-forward is possible // in other cases bzr merge should be used instead (bzr pull would fail) // Information about repository must be provided at least once. DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localRepositoryLocation), this); job->setType(VcsJob::JobType::Pull); *job << "bzr" << "pull"; if (!localOrRepoLocationSrc.localUrl().isEmpty()) { *job << localOrRepoLocationSrc.localUrl(); } // localUrl always makes sense. Even on remote repositores which are handled // transparently. return job; } VcsJob* BazaarPlugin::push(const QUrl& localRepositoryLocation, const VcsLocation& localOrRepoLocationDst) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localRepositoryLocation), this); job->setType(VcsJob::JobType::Push); *job << "bzr" << "push" << localOrRepoLocationDst.localUrl(); // localUrl always makes sense. Even on remote repositores which are handled // transparently. return job; } VcsJob* BazaarPlugin::remove(const QList& localLocations) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocations[0]), this); job->setType(VcsJob::JobType::Remove); *job << "bzr" << "remove" << localLocations; return job; } VcsJob* BazaarPlugin::repositoryLocation(const QUrl& localLocation) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocation), this); job->setType(VcsJob::JobType::Unknown); *job << "bzr" << "root" << localLocation; // It is only to make sure connect(job, &DVcsJob::readyForParsing, this, &BazaarPlugin::parseBzrRoot); return job; } void BazaarPlugin::parseBzrRoot(DVcsJob* job) { QString filename = job->dvcsCommand()[2]; QString rootDirectory = job->output(); QString localFilename = QFileInfo(QUrl::fromLocalFile(filename).toLocalFile()).absoluteFilePath(); QString localRootDirectory = QFileInfo(rootDirectory).absolutePath(); QString result = localFilename.mid(localFilename.indexOf(rootDirectory) + rootDirectory.length()); job->setResults(QVariant::fromValue(result)); } VcsJob* BazaarPlugin::resolve(const QList& localLocations, IBasicVersionControl::RecursionMode recursion) { return add(localLocations, recursion); // How to provide "a conflict solving dialog to the user"? // In any case this plugin is unable to make any conflict. } VcsJob* BazaarPlugin::revert(const QList& localLocations, IBasicVersionControl::RecursionMode recursion) { DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocations[0]), this); job->setType(VcsJob::JobType::Revert); *job << "bzr" << "revert" << BazaarUtils::handleRecursion(localLocations, recursion); return job; } VcsJob* BazaarPlugin::status(const QList& localLocations, IBasicVersionControl::RecursionMode recursion) { Q_UNUSED(recursion); DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocations[0]), this); job->setType(VcsJob::Status); *job << "bzr" << "status" << "--short" << "--no-pending" << "--no-classify" << localLocations; connect(job, &DVcsJob::readyForParsing, this, &BazaarPlugin::parseBzrStatus); return job; } void BazaarPlugin::parseBzrStatus(DVcsJob* job) { QVariantList result; QSet filesWithStatus; QDir workingCopy = job->directory(); for (QString line : job->output().split('\n')) { auto status = BazaarUtils::parseVcsStatusInfoLine(line); result.append(QVariant::fromValue(status)); filesWithStatus.insert(BazaarUtils::concatenatePath(workingCopy, status.url())); } QStringList command = job->dvcsCommand(); for (auto it = command.constBegin() + command.indexOf("--no-classify") + 1, itEnd = command.constEnd(); it != itEnd; ++it) { QString path = QFileInfo(*it).absoluteFilePath(); if (!filesWithStatus.contains(path)) { filesWithStatus.insert(path); KDevelop::VcsStatusInfo status; status.setState(VcsStatusInfo::ItemUpToDate); status.setUrl(QUrl::fromLocalFile(*it)); result.append(QVariant::fromValue(status)); } } job->setResults(result); } VcsJob* BazaarPlugin::update(const QList& localLocations, const VcsRevision& rev, IBasicVersionControl::RecursionMode recursion) { // bzr update is stronger than API (it's effectively merge) // the best approximation is bzr pull DVcsJob* job = new DVcsJob(BazaarUtils::workingCopy(localLocations[0]), this); Q_UNUSED(recursion); // recursion and file locations are ignored - we can update only whole // working copy job->setType(VcsJob::JobType::Update); *job << "bzr" << "pull" << BazaarUtils::getRevisionSpec(rev); return job; } VcsLocationWidget* BazaarPlugin::vcsLocation(QWidget* parent) const { return new KDevelop::StandardVcsLocationWidget(parent); } ContextMenuExtension BazaarPlugin::contextMenuExtension(Context* context) { m_vcsPluginHelper->setupFromContext(context); QList const& ctxUrlList = m_vcsPluginHelper->contextUrlList(); bool isWorkingDirectory = false; for (const QUrl & url : ctxUrlList) { if (BazaarUtils::isValidDirectory(url)) { isWorkingDirectory = true; break; } } if (!isWorkingDirectory) { // Not part of a repository return ContextMenuExtension(); } QMenu* menu = m_vcsPluginHelper->commonActions(); ContextMenuExtension menuExt; menuExt.addAction(ContextMenuExtension::VcsGroup, menu->menuAction()); return menuExt; } bool BazaarPlugin::hasError() const { return m_hasError; } QString BazaarPlugin::errorDescription() const { return m_errorDescription; } diff --git a/plugins/cvs/cvsplugin.cpp b/plugins/cvs/cvsplugin.cpp index 519f20bf47..5e3b28d802 100644 --- a/plugins/cvs/cvsplugin.cpp +++ b/plugins/cvs/cvsplugin.cpp @@ -1,490 +1,489 @@ /*************************************************************************** * 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 "cvsplugin.h" #include #include #include #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include "cvsmainview.h" #include "cvsproxy.h" #include "cvsjob.h" #include "editorsview.h" #include "commitdialog.h" #include "cvsgenericoutputview.h" #include "checkoutdialog.h" #include "importdialog.h" #include "importmetadatawidget.h" #include "debug.h" #include #include #include Q_LOGGING_CATEGORY(PLUGIN_CVS, "kdevplatform.plugins.cvs") K_PLUGIN_FACTORY(KDevCvsFactory, registerPlugin();) // K_EXPORT_PLUGIN(KDevCvsFactory(KAboutData("kdevcvs", "kdevcvs", ki18n("CVS"), "0.1", ki18n("Support for CVS version control system"), KAboutData::License_GPL))) class KDevCvsViewFactory: public KDevelop::IToolViewFactory { public: KDevCvsViewFactory(CvsPlugin *plugin): m_plugin(plugin) {} virtual QWidget* create(QWidget *parent = 0) override { return new CvsMainView(m_plugin, parent); } virtual Qt::DockWidgetArea defaultPosition() override { return Qt::BottomDockWidgetArea; } virtual QString id() const override { return "org.kdevelop.CVSView"; } private: CvsPlugin *m_plugin; }; class CvsPluginPrivate { public: explicit CvsPluginPrivate(CvsPlugin *pThis) : m_factory(new KDevCvsViewFactory(pThis)) , m_proxy(new CvsProxy(pThis)) , m_common(new KDevelop::VcsPluginHelper(pThis, pThis)) {} KDevCvsViewFactory* m_factory; QPointer m_proxy; QScopedPointer m_common; }; CvsPlugin::CvsPlugin(QObject *parent, const QVariantList &) : KDevelop::IPlugin("kdevcvs", parent) , d(new CvsPluginPrivate(this)) { KDEV_USE_EXTENSION_INTERFACE(KDevelop::IBasicVersionControl) KDEV_USE_EXTENSION_INTERFACE(KDevelop::ICentralizedVersionControl) core()->uiController()->addToolView(i18n("CVS"), d->m_factory); setXMLFile("kdevcvs.rc"); setupActions(); } CvsPlugin::~CvsPlugin() { } void CvsPlugin::unload() { core()->uiController()->removeToolView( d->m_factory ); } CvsProxy* CvsPlugin::proxy() { return d->m_proxy; } void CvsPlugin::setupActions() { QAction *action; action = actionCollection()->addAction("cvs_import"); action->setText(i18n("Import Directory...")); connect(action, &QAction::triggered, this, &CvsPlugin::slotImport); action = actionCollection()->addAction("cvs_checkout"); action->setText(i18n("Checkout...")); connect(action, &QAction::triggered, this, &CvsPlugin::slotCheckout); action = actionCollection()->addAction("cvs_status"); action->setText(i18n("Status...")); connect(action, &QAction::triggered, this, &CvsPlugin::slotStatus); } const QUrl CvsPlugin::urlFocusedDocument() const { KParts::ReadOnlyPart *plugin = dynamic_cast(core()->partController()->activePart()); if (plugin) { if (plugin->url().isLocalFile()) { return plugin->url(); } } return QUrl(); } void CvsPlugin::slotImport() { QUrl url = urlFocusedDocument(); ImportDialog dlg(this, url); dlg.exec(); } void CvsPlugin::slotCheckout() { ///@todo don't use proxy directly; use interface instead CheckoutDialog dlg(this); dlg.exec(); } void CvsPlugin::slotStatus() { QUrl url = urlFocusedDocument(); QList urls; urls << url; KDevelop::VcsJob* j = status(urls, KDevelop::IBasicVersionControl::Recursive); CvsJob* job = dynamic_cast(j); if (job) { CvsGenericOutputView* view = new CvsGenericOutputView(job); emit addNewTabToMainView(view, i18n("Status")); KDevelop::ICore::self()->runController()->registerJob(job); } } KDevelop::ContextMenuExtension CvsPlugin::contextMenuExtension(KDevelop::Context* context) { d->m_common->setupFromContext(context); QList const & ctxUrlList = d->m_common->contextUrlList(); bool hasVersionControlledEntries = false; foreach(const QUrl &url, ctxUrlList) { if (d->m_proxy->isValidDirectory(url)) { hasVersionControlledEntries = true; break; } } qCDebug(PLUGIN_CVS) << "version controlled?" << hasVersionControlledEntries; if (!hasVersionControlledEntries) return IPlugin::contextMenuExtension(context); QMenu* menu = d->m_common->commonActions(); menu->addSeparator(); QAction *action; // Just add actions which are not covered by the cvscommon plugin action = new QAction(i18n("Edit"), this); connect(action, &QAction::triggered, this, &CvsPlugin::ctxEdit); menu->addAction(action); action = new QAction(i18n("Unedit"), this); connect(action, &QAction::triggered, this, &CvsPlugin::ctxUnEdit); menu->addAction(action); action = new QAction(i18n("Show Editors"), this); connect(action, &QAction::triggered, this, &CvsPlugin::ctxEditors); menu->addAction(action); KDevelop::ContextMenuExtension menuExt; menuExt.addAction(KDevelop::ContextMenuExtension::VcsGroup, menu->menuAction()); return menuExt; } void CvsPlugin::ctxEdit() { QList const & urls = d->m_common->contextUrlList(); Q_ASSERT(!urls.empty()); KDevelop::VcsJob* j = edit(urls.front()); CvsJob* job = dynamic_cast(j); if (job) { connect(job, &CvsJob::result, this, &CvsPlugin::jobFinished); KDevelop::ICore::self()->runController()->registerJob(job); } } void CvsPlugin::ctxUnEdit() { QList const & urls = d->m_common->contextUrlList(); Q_ASSERT(!urls.empty()); KDevelop::VcsJob* j = unedit(urls.front()); CvsJob* job = dynamic_cast(j); if (job) { connect(job, &CvsJob::result, this, &CvsPlugin::jobFinished); KDevelop::ICore::self()->runController()->registerJob(job); } } void CvsPlugin::ctxEditors() { QList const & urls = d->m_common->contextUrlList(); Q_ASSERT(!urls.empty()); CvsJob* job = d->m_proxy->editors(findWorkingDir(urls.front()), urls); if (job) { KDevelop::ICore::self()->runController()->registerJob(job); EditorsView* view = new EditorsView(job); emit addNewTabToMainView(view, i18n("Editors")); } } QString CvsPlugin::findWorkingDir(const QUrl& location) { QFileInfo fileInfo(location.toLocalFile()); // find out correct working directory if (fileInfo.isFile()) { return fileInfo.absolutePath(); } else { return fileInfo.absoluteFilePath(); } } // Begin: KDevelop::IBasicVersionControl bool CvsPlugin::isVersionControlled(const QUrl & localLocation) { return d->m_proxy->isVersionControlled(localLocation); } KDevelop::VcsJob * CvsPlugin::repositoryLocation(const QUrl & localLocation) { Q_UNUSED(localLocation); return NULL; } KDevelop::VcsJob * CvsPlugin::add(const QList & localLocations, KDevelop::IBasicVersionControl::RecursionMode recursion) { CvsJob* job = d->m_proxy->add(findWorkingDir(localLocations[0]), localLocations, (recursion == KDevelop::IBasicVersionControl::Recursive) ? true : false); return job; } KDevelop::VcsJob * CvsPlugin::remove(const QList & localLocations) { CvsJob* job = d->m_proxy->remove(findWorkingDir(localLocations[0]), localLocations); return job; } KDevelop::VcsJob * CvsPlugin::localRevision(const QUrl & localLocation, KDevelop::VcsRevision::RevisionType) { Q_UNUSED(localLocation) return NULL; } KDevelop::VcsJob * CvsPlugin::status(const QList & localLocations, KDevelop::IBasicVersionControl::RecursionMode recursion) { CvsJob* job = d->m_proxy->status(findWorkingDir(localLocations[0]), localLocations, (recursion == KDevelop::IBasicVersionControl::Recursive) ? true : false); return job; } KDevelop::VcsJob * CvsPlugin::unedit(const QUrl& localLocation) { CvsJob* job = d->m_proxy->unedit(findWorkingDir(localLocation), QList() << localLocation); return job; } KDevelop::VcsJob * CvsPlugin::edit(const QUrl& localLocation) { CvsJob* job = d->m_proxy->edit(findWorkingDir(localLocation), QList() << localLocation); return job; } KDevelop::VcsJob * CvsPlugin::copy(const QUrl & localLocationSrc, const QUrl & localLocationDstn) { bool ok = QFile::copy(localLocationSrc.toLocalFile(), localLocationDstn.path()); if (!ok) { return NULL; } QList listDstn; listDstn << localLocationDstn; CvsJob* job = d->m_proxy->add(findWorkingDir(localLocationDstn), listDstn, true); return job; } KDevelop::VcsJob * CvsPlugin::move(const QUrl &, const QUrl &) { return NULL; } KDevelop::VcsJob * CvsPlugin::revert(const QList & localLocations, KDevelop::IBasicVersionControl::RecursionMode recursion) { KDevelop::VcsRevision rev; CvsJob* job = d->m_proxy->update(findWorkingDir(localLocations[0]), localLocations, rev, "-C", (recursion == KDevelop::IBasicVersionControl::Recursive) ? true : false, false, false); return job; } KDevelop::VcsJob * CvsPlugin::update(const QList & localLocations, const KDevelop::VcsRevision & rev, KDevelop::IBasicVersionControl::RecursionMode recursion) { CvsJob* job = d->m_proxy->update(findWorkingDir(localLocations[0]), localLocations, rev, "", (recursion == KDevelop::IBasicVersionControl::Recursive) ? true : false, false, false); return job; } KDevelop::VcsJob * CvsPlugin::commit(const QString & message, const QList & localLocations, KDevelop::IBasicVersionControl::RecursionMode recursion) { Q_UNUSED(recursion); QString msg = message; if (msg.isEmpty()) { CommitDialog dlg; if (dlg.exec() == QDialog::Accepted) { msg = dlg.message(); } } CvsJob* job = d->m_proxy->commit(findWorkingDir(localLocations[0]), localLocations, msg); return job; } KDevelop::VcsJob * CvsPlugin::diff(const QUrl & fileOrDirectory, const KDevelop::VcsRevision & srcRevision, const KDevelop::VcsRevision & dstRevision, KDevelop::VcsDiff::Type, KDevelop::IBasicVersionControl::RecursionMode) { CvsJob* job = d->m_proxy->diff(fileOrDirectory, srcRevision, dstRevision, "-uN"/*always unified*/); return job; } KDevelop::VcsJob * CvsPlugin::log(const QUrl & localLocation, const KDevelop::VcsRevision & rev, unsigned long limit) { Q_UNUSED(limit) CvsJob* job = d->m_proxy->log(localLocation, rev); return job; } KDevelop::VcsJob * CvsPlugin::log(const QUrl & localLocation, const KDevelop::VcsRevision & rev, const KDevelop::VcsRevision & limit) { Q_UNUSED(limit) return log(localLocation, rev, 0); } KDevelop::VcsJob * CvsPlugin::annotate(const QUrl & localLocation, const KDevelop::VcsRevision & rev) { CvsJob* job = d->m_proxy->annotate(localLocation, rev); return job; } KDevelop::VcsJob * CvsPlugin::resolve(const QList & localLocations, KDevelop::IBasicVersionControl::RecursionMode recursion) { Q_UNUSED(localLocations); Q_UNUSED(recursion); return NULL; } KDevelop::VcsJob * CvsPlugin::import(const QString& commitMessage, const QUrl& sourceDirectory, const KDevelop::VcsLocation& destinationRepository) { if (commitMessage.isEmpty() || !sourceDirectory.isLocalFile() || !destinationRepository.isValid() || destinationRepository.type() != KDevelop::VcsLocation::RepositoryLocation) { return 0; } qCDebug(PLUGIN_CVS) << "CVS Import requested " << "src:" << sourceDirectory.toLocalFile() << "srv:" << destinationRepository.repositoryServer() << "module:" << destinationRepository.repositoryModule(); CvsJob* job = d->m_proxy->import(sourceDirectory, destinationRepository.repositoryServer(), destinationRepository.repositoryModule(), destinationRepository.userData().toString(), destinationRepository.repositoryTag(), commitMessage); return job; } KDevelop::VcsJob * CvsPlugin::createWorkingCopy(const KDevelop::VcsLocation & sourceRepository, const QUrl & destinationDirectory, KDevelop::IBasicVersionControl::RecursionMode recursion) { Q_UNUSED(recursion); if (!destinationDirectory.isLocalFile() || !sourceRepository.isValid() || sourceRepository.type() != KDevelop::VcsLocation::RepositoryLocation) { return 0; } qCDebug(PLUGIN_CVS) << "CVS Checkout requested " << "dest:" << destinationDirectory.toLocalFile() << "srv:" << sourceRepository.repositoryServer() << "module:" << sourceRepository.repositoryModule() << "branch:" << sourceRepository.repositoryBranch() << endl; CvsJob* job = d->m_proxy->checkout(destinationDirectory, sourceRepository.repositoryServer(), sourceRepository.repositoryModule(), "", sourceRepository.repositoryBranch(), true, true); return job; } QString CvsPlugin::name() const { return i18n("CVS"); } KDevelop::VcsImportMetadataWidget* CvsPlugin::createImportMetadataWidget(QWidget* parent) { return new ImportMetadataWidget(parent); } KDevelop::VcsLocationWidget* CvsPlugin::vcsLocation(QWidget* parent) const { return new KDevelop::StandardVcsLocationWidget(parent); } // End: KDevelop::IBasicVersionControl #include "cvsplugin.moc" diff --git a/plugins/quickopen/expandingtree/expandingdelegate.h b/plugins/quickopen/expandingtree/expandingdelegate.h index d8138a4557..e5d31590af 100644 --- a/plugins/quickopen/expandingtree/expandingdelegate.h +++ b/plugins/quickopen/expandingtree/expandingdelegate.h @@ -1,94 +1,93 @@ /* This file is part of the KDE libraries and the Kate part. * * Copyright (C) 2006 Hamish Rodda * Copyright (C) 2007 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 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 KDEVPLATFORM_PLUGIN_EXPANDINGDELEGATE_H #define KDEVPLATFORM_PLUGIN_EXPANDINGDELEGATE_H -#include #include #include #include #include class KateRenderer; class KateCompletionWidget; class KateDocument; class KateTextLine; class ExpandingWidgetModel; class QVariant; class QStyleOptionViewItem; /** * This is a delegate that cares, together with ExpandingWidgetModel, about embedded widgets in tree-view. * */ class ExpandingDelegate : public QItemDelegate { Q_OBJECT public: explicit ExpandingDelegate(ExpandingWidgetModel* model, QObject* parent = 0L); // Overridden to create highlighting for current index virtual void paint ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const override; // Returns the basic size-hint as reported by QItemDelegate QSize basicSizeHint( const QModelIndex& index ) const; ExpandingWidgetModel* model() const; protected: //Called right before paint to allow last-minute changes to the style virtual void adjustStyle( const QModelIndex& index, QStyleOptionViewItem & option ) const; virtual void drawDisplay ( QPainter * painter, const QStyleOptionViewItem & option, const QRect & rect, const QString & text ) const override; virtual QSize sizeHint ( const QStyleOptionViewItem & option, const QModelIndex & index ) const override; virtual bool editorEvent ( QEvent * event, QAbstractItemModel * model, const QStyleOptionViewItem & option, const QModelIndex & index ) override; virtual void drawBackground ( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const; virtual void drawDecoration(QPainter* painter, const QStyleOptionViewItem& option, const QRect& rect, const QPixmap& pixmap) const override; //option can be changed virtual QList createHighlighting(const QModelIndex& index, QStyleOptionViewItem& option) const; void adjustRect(QRect& rect) const; /** * Creates a list of FormatRanges as should be returned by createHighlighting from a list of QVariants as described in the kde header ktexteditor/codecompletionmodel.h * */ QList highlightingFromVariantList(const QList& customHighlights) const; //Called when an item was expanded/unexpanded and the height changed virtual void heightChanged() const; //Initializes the style options from the index void initStyleOption(QStyleOptionViewItem *option, const QModelIndex &index) const; mutable int m_currentColumnStart; //Text-offset for custom highlighting, will be applied to m_cachedHighlights(Only highlights starting after this will be used). Shoult be zero of the highlighting is not taken from kate. mutable QList m_currentColumnStarts; mutable QList m_cachedHighlights; mutable Qt::Alignment m_cachedAlignment; mutable QColor m_backgroundColor; mutable QModelIndex m_currentIndex; private: ExpandingWidgetModel* m_model; }; #endif // KDEVPLATFORM_PLUGIN_EXPANDINGDELEGATE_H diff --git a/plugins/welcomepage/welcomepagedocument.cpp b/plugins/welcomepage/welcomepagedocument.cpp index fb4d573e33..9208cb13fa 100644 --- a/plugins/welcomepage/welcomepagedocument.cpp +++ b/plugins/welcomepage/welcomepagedocument.cpp @@ -1,107 +1,106 @@ /* This file is part of KDevelop * Copyright 2010 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 "welcomepagedocument.h" #include #include #include #include #include -#include "welcomepagedocument.h" #include "welcomepageview.h" #include using namespace KDevelop; Q_GLOBAL_STATIC_WITH_ARGS(QUrl, s_welcomePageUrl, (QUrl("kdev:///awesome.kdevinternal"))); WelcomePageDocument::WelcomePageDocument() : Sublime::UrlDocument(ICore::self()->uiController()->controller(), *s_welcomePageUrl), IDocument(ICore::self()) { setTitle(i18n("Dashboard")); } void WelcomePageDocument::activate(Sublime::View* /*activeView*/, KParts::MainWindow* /*mainWindow*/) {} void WelcomePageDocument::setTextSelection(const KTextEditor::Range& /*range*/) {} void WelcomePageDocument::setCursorPosition(const KTextEditor::Cursor& /*cursor*/) {} KTextEditor::Cursor WelcomePageDocument::cursorPosition() const { return KTextEditor::Cursor(); } IDocument::DocumentState WelcomePageDocument::state() const { return IDocument::Clean; } bool WelcomePageDocument::isActive() const { return true; } bool WelcomePageDocument::close(KDevelop::IDocument::DocumentSaveMode /*mode*/) { return true; } void WelcomePageDocument::reload() {} bool WelcomePageDocument::save(KDevelop::IDocument::DocumentSaveMode /*mode*/) { return true; } KTextEditor::Document* WelcomePageDocument::textDocument() const { return 0; } KParts::Part* WelcomePageDocument::partForView(QWidget* /*view*/) const { return 0; } QMimeType WelcomePageDocument::mimeType() const { return QMimeDatabase().mimeTypeForName("text/x-kdevelopinternal"); } Sublime::View* WelcomePageDocument::newView(Sublime::Document* doc) { if( dynamic_cast( doc ) ) return new WelcomePageView(doc, Sublime::View::TakeOwnership); return 0; } QUrl WelcomePageDocument::url() const { return *s_welcomePageUrl; } QUrl WelcomePageDocument::welcomePageUrl() { return *s_welcomePageUrl; } diff --git a/project/projectutils.cpp b/project/projectutils.cpp index 4f1c9d1213..381cf7d8e1 100644 --- a/project/projectutils.cpp +++ b/project/projectutils.cpp @@ -1,153 +1,152 @@ /* Copyright (C) 2011 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. 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 "projectutils.h" #include #include "path.h" #include #include #include -#include #include #include #include #include #include namespace KDevelop { ProjectItemContextImpl::ProjectItemContextImpl(const QList& items) : ProjectItemContext(items) { } QList ProjectItemContextImpl::urls() const { QList urls; foreach (auto item, items()) { const auto url = item->path().toUrl(); if (url.isValid()) { urls << url; } } return urls; } class Populator : public QObject { Q_OBJECT public: Populator(KDevelop::ProjectBaseItem* item, QAction* action, const QPoint& pos, const QString& text) : m_item(item) , m_pos(pos) , m_text(text) { connect(action, &QAction::destroyed, this, &Populator::deleteLater); connect(action, &QAction::triggered, this, &Populator::populate); } public Q_SLOTS: void populate() { QMenu* menu = new QMenu(m_text); connect(menu, &QMenu::aboutToHide, menu, &QMenu::deleteLater); menu->addAction(QIcon::fromTheme(m_item->iconName()), m_text)->setEnabled(false); ProjectItemContextImpl context({m_item}); QList extensions = ICore::self()->pluginController()->queryPluginsForContextMenuExtensions( &context ); ContextMenuExtension::populateMenu(menu, extensions); menu->popup(m_pos); } private: KDevelop::ProjectBaseItem* m_item; QPoint m_pos; QString m_text; }; void populateParentItemsMenu( ProjectBaseItem* item, QMenu* menu ) { if(!item) return; ProjectBaseItem* parent = item->parent(); bool hasSeparator = false; while(parent) { if(!parent->path().isValid()) { if(!hasSeparator) { hasSeparator = true; menu->addSeparator(); } QString prettyName = ICore::self()->projectController()->prettyFileName(parent->path().toUrl(), IProjectController::FormatPlain); QString text; if(parent->parent()) text = i18n("Folder %1", prettyName); else text = i18n("Project %1", prettyName); QAction* action = menu->addAction(text); action->setIcon(QIcon::fromTheme(parent->iconName())); // The populator will either spawn a menu when the action is triggered, or it will delete itself new Populator(parent, action, QCursor::pos(), text); } parent = parent->parent(); } } QList allFiles(ProjectBaseItem* projectItem) { QList files; if ( ProjectFolderItem * folder = projectItem->folder() ) { QList folder_list = folder->folderList(); for ( QList::Iterator it = folder_list.begin(); it != folder_list.end(); ++it ) { files += allFiles( ( *it ) ); } QList target_list = folder->targetList(); for ( QList::Iterator it = target_list.begin(); it != target_list.end(); ++it ) { files += allFiles( ( *it ) ); } files += folder->fileList(); } else if ( ProjectTargetItem * target = projectItem->target() ) { files += target->fileList(); } else if ( ProjectFileItem * file = projectItem->file() ) { files.append( file ); } return files; } } #include "projectutils.moc" diff --git a/project/tests/test_projectmodel.cpp b/project/tests/test_projectmodel.cpp index 45df207ca3..d73f4fd41e 100644 --- a/project/tests/test_projectmodel.cpp +++ b/project/tests/test_projectmodel.cpp @@ -1,547 +1,546 @@ /*************************************************************************** * Copyright 2010 Andreas Pakulat * * * * 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 "test_projectmodel.h" #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include using namespace KDevelop; void debugItemModel(QAbstractItemModel* m, const QModelIndex& parent=QModelIndex(), int depth=0) { Q_ASSERT(m); qDebug() << QByteArray(depth*2, '-') << m->data(parent).toString(); for(int i=0; irowCount(parent); i++) { debugItemModel(m, m->index(i, 0, parent), depth+1); } } void TestProjectModel::initTestCase() { AutoTestShell::init(); TestCore::initialize(Core::NoUi); qRegisterMetaType("QModelIndex"); model = ICore::self()->projectController()->projectModel(); new ModelTest( model, this ); proxy = new ProjectProxyModel( model ); new ModelTest(proxy, proxy); proxy->setSourceModel(model); } void TestProjectModel::init() { model->clear(); } void TestProjectModel::cleanupTestCase() { TestCore::shutdown(); } void TestProjectModel::testCreateFileSystemItems() { QFETCH( int, itemType ); QFETCH( Path, itemPath ); QFETCH( Path, expectedItemPath ); QFETCH( QString, expectedItemText ); QFETCH( QStringList, expectedRelativeItemPath ); QFETCH( int, expectedItemRow ); ProjectBaseItem* newitem = 0; switch( itemType ) { case ProjectBaseItem::Folder: newitem = new ProjectFolderItem( 0, itemPath ); break; case ProjectBaseItem::BuildFolder: newitem = new ProjectBuildFolderItem( 0, itemPath ); break; case ProjectBaseItem::File: newitem = new ProjectFileItem( 0, itemPath ); break; } int origRowCount = model->rowCount(); model->appendRow( newitem ); QCOMPARE( model->rowCount(), origRowCount+1 ); QCOMPARE( newitem->row(), expectedItemRow ); QModelIndex idx = model->index( expectedItemRow, 0, QModelIndex() ); QVERIFY( model->itemFromIndex( idx ) ); QCOMPARE( model->itemFromIndex( idx ), newitem ); QCOMPARE( newitem->text(), expectedItemText ); QCOMPARE( newitem->path(), expectedItemPath ); if( itemType == ProjectBaseItem::File ) { QCOMPARE( dynamic_cast( newitem )->fileName(), expectedItemText ); } if( itemType == ProjectBaseItem::Folder || itemType == ProjectBaseItem::BuildFolder ) { QCOMPARE( dynamic_cast( newitem )->folderName(), expectedItemText ); } QCOMPARE( newitem->type(), itemType ); QCOMPARE( model->data( idx ).toString(), expectedItemText ); QCOMPARE( model->indexFromItem( newitem ), idx ); QCOMPARE( model->pathFromIndex( idx ), expectedRelativeItemPath ); QCOMPARE( model->pathToIndex( expectedRelativeItemPath ), idx ); } void TestProjectModel::testCreateFileSystemItems_data() { QTest::addColumn( "itemType" ); QTest::addColumn( "itemPath" ); QTest::addColumn( "expectedItemPath" ); QTest::addColumn( "expectedItemText" ); QTest::addColumn( "expectedRelativeItemPath" ); QTest::addColumn( "expectedItemRow" ); QTest::newRow("RootFolder") << (int)ProjectBaseItem::Folder << Path(QUrl::fromLocalFile("/rootdir")) << Path(QUrl::fromLocalFile("/rootdir/")) << QString::fromLatin1("rootdir") << ( QStringList() << "rootdir" ) << 0; QTest::newRow("RootBuildFolder") << (int)ProjectBaseItem::BuildFolder << Path(QUrl::fromLocalFile("/rootdir")) << Path(QUrl::fromLocalFile("/rootdir/")) << QString::fromLatin1("rootdir") << ( QStringList() << "rootdir" ) << 0; QTest::newRow("RootFile") << (int)ProjectBaseItem::File << Path(QUrl::fromLocalFile("/rootfile")) << Path(QUrl::fromLocalFile("/rootfile")) << QString::fromLatin1("rootfile") << ( QStringList() << "rootfile" ) << 0; } void TestProjectModel::testCreateTargetItems() { QFETCH( int, itemType ); QFETCH( QString, itemText ); QFETCH( QString, expectedItemText ); QFETCH( QStringList, expectedItemPath ); QFETCH( int, expectedItemRow ); ProjectBaseItem* newitem = 0; switch( itemType ) { case ProjectBaseItem::Target: newitem = new ProjectTargetItem( 0, itemText ); break; case ProjectBaseItem::LibraryTarget: newitem = new ProjectLibraryTargetItem( 0, itemText ); break; } int origRowCount = model->rowCount(); model->appendRow( newitem ); QCOMPARE( model->rowCount(), origRowCount+1 ); QCOMPARE( newitem->row(), expectedItemRow ); QModelIndex idx = model->index( expectedItemRow, 0, QModelIndex() ); QVERIFY( model->itemFromIndex( idx ) ); QCOMPARE( model->itemFromIndex( idx ), newitem ); QCOMPARE( newitem->text(), expectedItemText ); QCOMPARE( newitem->type(), itemType ); QCOMPARE( model->data( idx ).toString(), expectedItemText ); QCOMPARE( model->indexFromItem( newitem ), idx ); QCOMPARE( model->pathFromIndex( idx ), expectedItemPath ); QCOMPARE( model->pathToIndex( expectedItemPath ), idx ); } void TestProjectModel::testCreateTargetItems_data() { QTest::addColumn( "itemType" ); QTest::addColumn( "itemText" ); QTest::addColumn( "expectedItemText" ); QTest::addColumn( "expectedItemPath" ); QTest::addColumn( "expectedItemRow" ); QTest::newRow("RootTarget") << (int)ProjectBaseItem::Target << "target" << QString::fromLatin1("target") << ( QStringList() << "target" ) << 0; QTest::newRow("RootLibraryTarget") << (int)ProjectBaseItem::LibraryTarget << "libtarget" << QString::fromLatin1("libtarget") << ( QStringList() << "libtarget" ) << 0; } void TestProjectModel::testChangeWithProxyModel() { QSortFilterProxyModel* proxy = new QSortFilterProxyModel( this ); proxy->setSourceModel( model ); ProjectFolderItem* root = new ProjectFolderItem( 0, Path(QUrl::fromLocalFile("/folder1")) ); root->appendRow( new ProjectFileItem( 0, Path(QUrl::fromLocalFile("/folder1/file1")) ) ); model->appendRow( root ); QCOMPARE( model->rowCount(), 1 ); QCOMPARE( proxy->rowCount(), 1 ); model->removeRow( 0 ); QCOMPARE( model->rowCount(), 0 ); QCOMPARE( proxy->rowCount(), 0 ); } void TestProjectModel::testCreateSimpleHierarchy() { QString folderName = "rootfolder"; QString fileName = "file"; QString targetName = "testtarged"; QString cppFileName = "file.cpp"; ProjectFolderItem* rootFolder = new ProjectFolderItem( 0, Path(QUrl::fromLocalFile("/"+folderName)) ); QCOMPARE(rootFolder->baseName(), folderName); ProjectFileItem* file = new ProjectFileItem( fileName, rootFolder ); QCOMPARE(file->baseName(), fileName); ProjectTargetItem* target = new ProjectTargetItem( 0, targetName ); rootFolder->appendRow( target ); ProjectFileItem* targetfile = new ProjectFileItem( 0, Path(rootFolder->path(), cppFileName), target ); model->appendRow( rootFolder ); QCOMPARE( model->rowCount(), 1 ); QModelIndex folderIdx = model->index( 0, 0, QModelIndex() ); QCOMPARE( model->data( folderIdx ).toString(), folderName ); QCOMPARE( model->rowCount( folderIdx ), 2 ); QCOMPARE( model->itemFromIndex( folderIdx ), rootFolder ); QVERIFY( rootFolder->hasFileOrFolder( fileName ) ); QModelIndex fileIdx = model->index( 0, 0, folderIdx ); QCOMPARE( model->data( fileIdx ).toString(), fileName ); QCOMPARE( model->rowCount( fileIdx ), 0 ); QCOMPARE( model->itemFromIndex( fileIdx ), file ); QModelIndex targetIdx = model->index( 1, 0, folderIdx ); QCOMPARE( model->data( targetIdx ).toString(), targetName ); QCOMPARE( model->rowCount( targetIdx ), 1 ); QCOMPARE( model->itemFromIndex( targetIdx ), target ); QModelIndex targetFileIdx = model->index( 0, 0, targetIdx ); QCOMPARE( model->data( targetFileIdx ).toString(), cppFileName ); QCOMPARE( model->rowCount( targetFileIdx ), 0 ); QCOMPARE( model->itemFromIndex( targetFileIdx ), targetfile ); rootFolder->removeRow( 1 ); QCOMPARE( model->rowCount( folderIdx ), 1 ); delete file; file = 0; // Check that we also find a folder with the fileName new ProjectFolderItem( fileName, rootFolder ); QVERIFY( rootFolder->hasFileOrFolder( fileName ) ); delete rootFolder; QCOMPARE( model->rowCount(), 0 ); } void TestProjectModel::testItemSanity() { ProjectBaseItem* parent = new ProjectBaseItem( 0, "test" ); ProjectBaseItem* child = new ProjectBaseItem( 0, "test", parent ); ProjectBaseItem* child2 = new ProjectBaseItem( 0, "ztest", parent ); ProjectFileItem* child3 = new ProjectFileItem( 0, Path(QUrl("file:///bcd")), parent ); ProjectFileItem* child4 = new ProjectFileItem( 0, Path(QUrl("file:///abcd")), parent ); // Just some basic santiy checks on the API QCOMPARE( parent->child( 0 ), child ); QCOMPARE( parent->row(), -1 ); QVERIFY( !parent->child( -1 ) ); QVERIFY( !parent->file() ); QVERIFY( !parent->folder() ); QVERIFY( !parent->project() ); QVERIFY( !parent->child( parent->rowCount() ) ); QCOMPARE( parent->iconName(), QString() ); QCOMPARE( parent->index(), QModelIndex() ); QCOMPARE( child->type(), (int)ProjectBaseItem::BaseItem ); QCOMPARE( child->lessThan( child2 ), true ); QCOMPARE( child3->lessThan( child4 ), false ); // Check that model is properly emitting data-changes model->appendRow( parent ); QCOMPARE( parent->index(), model->index(0, 0, QModelIndex()) ); QSignalSpy s( model, SIGNAL(dataChanged(QModelIndex,QModelIndex)) ); parent->setPath( Path("/newtest") ); QCOMPARE( s.count(), 1 ); QCOMPARE( model->data( parent->index() ).toString(), QStringLiteral("newtest") ); parent->removeRow( child->row() ); } void TestProjectModel::testTakeRow() { ProjectBaseItem* parent = new ProjectBaseItem( 0, "test" ); ProjectBaseItem* child = new ProjectBaseItem( 0, "test", parent ); ProjectBaseItem* subchild = new ProjectBaseItem( 0, "subtest", child ); model->appendRow( parent ); QCOMPARE( parent->model(), model ); QCOMPARE( child->model(), model ); QCOMPARE( subchild->model(), model ); parent->takeRow( child->row() ); QCOMPARE( child->model(), static_cast(0) ); QCOMPARE( subchild->model(), static_cast(0) ); } void TestProjectModel::testRename() { QFETCH( int, itemType ); QFETCH( QString, itemText ); QFETCH( QString, newName ); QFETCH( bool, datachangesignal ); QFETCH( QString, expectedItemText ); QFETCH( int, expectedRenameCode ); const Path projectFolder = Path(QUrl::fromLocalFile("/dummyprojectfolder")); TestProject* proj = new TestProject; ProjectFolderItem* rootItem = new ProjectFolderItem( proj, projectFolder, 0); proj->setProjectItem( rootItem ); new ProjectFileItem("existing", rootItem); ProjectBaseItem* item = 0; if( itemType == ProjectBaseItem::Target ) { item = new ProjectTargetItem( proj, itemText, rootItem ); } else if( itemType == ProjectBaseItem::File ) { item = new ProjectFileItem( itemText, rootItem ); } else if( itemType == ProjectBaseItem::Folder ) { item = new ProjectFolderItem( itemText, rootItem ); } else if( itemType == ProjectBaseItem::BuildFolder ) { item = new ProjectBuildFolderItem( itemText, rootItem ); } Q_ASSERT( item ); QCOMPARE(item->model(), model); QSignalSpy s( model, SIGNAL(dataChanged(QModelIndex,QModelIndex)) ); ProjectBaseItem::RenameStatus stat = item->rename( newName ); QCOMPARE( (int)stat, expectedRenameCode ); if( datachangesignal ) { QCOMPARE( s.count(), 1 ); QCOMPARE( qvariant_cast( s.takeFirst().at(0) ), item->index() ); } else { QCOMPARE( s.count(), 0 ); } QCOMPARE( item->text(), expectedItemText ); } void TestProjectModel::testRename_data() { QTest::addColumn( "itemType" ); QTest::addColumn( "itemText" ); QTest::addColumn( "newName" ); QTest::addColumn( "datachangesignal" ); QTest::addColumn( "expectedItemText" ); QTest::addColumn( "expectedRenameCode" ); QTest::newRow("RenameableTarget") << (int)ProjectBaseItem::Target << QString::fromLatin1("target") << QString::fromLatin1("othertarget") << true << QString::fromLatin1("othertarget") << (int)ProjectBaseItem::RenameOk; QTest::newRow("RenameableFile") << (int)ProjectBaseItem::File << QString::fromLatin1("newfile.cpp") << QString::fromLatin1("otherfile.cpp") << true << QString::fromLatin1("otherfile.cpp") << (int)ProjectBaseItem::RenameOk; QTest::newRow("SourceAndDestinationFileEqual") << (int)ProjectBaseItem::File << QString::fromLatin1("newfile.cpp") << QString::fromLatin1("newfile.cpp") << false << QString::fromLatin1("newfile.cpp") << (int)ProjectBaseItem::RenameOk; QTest::newRow("RenameableFolder") << (int)ProjectBaseItem::Folder << QString::fromLatin1("newfolder") << QString::fromLatin1("otherfolder") << true << QString::fromLatin1("otherfolder") << (int)ProjectBaseItem::RenameOk; QTest::newRow("SourceAndDestinationFolderEqual") << (int)ProjectBaseItem::Folder << QString::fromLatin1("newfolder") << QString::fromLatin1("newfolder") << false << QString::fromLatin1("newfolder") << (int)ProjectBaseItem::RenameOk; QTest::newRow("RenameableBuildFolder") << (int)ProjectBaseItem::BuildFolder << QString::fromLatin1("newbfolder") << QString::fromLatin1("otherbfolder") << true << QString::fromLatin1("otherbfolder") << (int)ProjectBaseItem::RenameOk; QTest::newRow("SourceAndDestinationBuildFolderEqual") << (int)ProjectBaseItem::BuildFolder << QString::fromLatin1("newbfolder") << QString::fromLatin1("newbfolder") << false << QString::fromLatin1("newbfolder") << (int)ProjectBaseItem::RenameOk; QTest::newRow("ExistingFileError") << (int)ProjectBaseItem::Folder << QString::fromLatin1("mynew") << QString::fromLatin1("existing") << false << QString::fromLatin1("mynew") << (int)ProjectBaseItem::ExistingItemSameName; QTest::newRow("InvalidNameError") << (int)ProjectBaseItem::File << QString::fromLatin1("mynew") << QString::fromLatin1("other/bash") << false << QString::fromLatin1("mynew") << (int)ProjectBaseItem::InvalidNewName; } void TestProjectModel::testWithProject() { TestProject* proj = new TestProject(); ProjectFolderItem* rootItem = new ProjectFolderItem( proj, Path(QUrl::fromLocalFile("/dummyprojectfolder")), 0); proj->setProjectItem( rootItem ); ProjectBaseItem* item = model->itemFromIndex( model->index( 0, 0 ) ); QCOMPARE( item, rootItem ); QCOMPARE( item->text(), proj->name() ); QCOMPARE( item->path(), proj->path() ); } void TestProjectModel::testItemsForPath() { QFETCH(Path, path); QFETCH(ProjectBaseItem*, root); QFETCH(int, matches); model->appendRow(root); auto items = model->itemsForPath(IndexedString(path.pathOrUrl())); QCOMPARE(items.size(), matches); foreach(ProjectBaseItem* item, items) { QVERIFY(item->path() == path); } model->clear(); } void TestProjectModel::testItemsForPath_data() { QTest::addColumn("path"); QTest::addColumn("root"); QTest::addColumn("matches"); { ProjectFolderItem* root = new ProjectFolderItem(0, Path(QUrl::fromLocalFile("/tmp/"))); ProjectFileItem* file = new ProjectFileItem("a", root); QTest::newRow("find one") << file->path() << static_cast(root) << 1; } { ProjectFolderItem* root = new ProjectFolderItem(0, Path(QUrl::fromLocalFile("/tmp/"))); ProjectFolderItem* folder = new ProjectFolderItem("a", root); ProjectFileItem* file = new ProjectFileItem("foo", folder); ProjectTargetItem* target = new ProjectTargetItem(0, "b", root); ProjectFileItem* file2 = new ProjectFileItem(0, file->path(), target); Q_UNUSED(file2); QTest::newRow("find two") << file->path() << static_cast(root) << 2; } } void TestProjectModel::testProjectProxyModel() { ProjectFolderItem* root = new ProjectFolderItem(0, Path(QUrl::fromLocalFile("/tmp/"))); new ProjectFileItem("b1", root); new ProjectFileItem("a1", root); new ProjectFileItem("d1", root); new ProjectFileItem("c1", root); model->appendRow(root); QModelIndex proxyRoot = proxy->mapFromSource(root->index()); QCOMPARE(model->rowCount(root->index()), 4); QCOMPARE(proxy->rowCount(proxyRoot), 4); QCOMPARE(proxy->index(0, 0, proxy->index(0, 0)).data().toString(), QStringLiteral("a1")); QCOMPARE(proxy->index(1, 0, proxy->index(0, 0)).data().toString(), QStringLiteral("b1")); QCOMPARE(proxy->index(2, 0, proxy->index(0, 0)).data().toString(), QStringLiteral("c1")); QCOMPARE(proxy->index(3, 0, proxy->index(0, 0)).data().toString(), QStringLiteral("d1")); model->clear(); } void TestProjectModel::testProjectFileSet() { TestProject* project = new TestProject; QVERIFY(project->fileSet().isEmpty()); Path path(QUrl::fromLocalFile("/tmp/a")); ProjectFileItem* item = new ProjectFileItem(project, path, project->projectItem()); QCOMPARE(project->fileSet().size(), 1); qDebug() << path << project->fileSet().begin()->toUrl(); QCOMPARE(Path(project->fileSet().begin()->toUrl()), path); delete item; QVERIFY(project->fileSet().isEmpty()); } void TestProjectModel::testProjectFileIcon() { QMimeDatabase db; ProjectFileItem* item = new ProjectFileItem(0, Path("/tmp/foo.txt")); const QString txtIcon = db.mimeTypeForUrl(item->path().toUrl()).iconName(); QCOMPARE(item->iconName(), txtIcon); item->setPath(Path("/tmp/bar.cpp")); QCOMPARE(item->iconName(), db.mimeTypeForUrl(item->path().toUrl()).iconName()); QVERIFY(item->iconName() != txtIcon); } QTEST_MAIN( TestProjectModel) diff --git a/shell/assistantpopup.cpp b/shell/assistantpopup.cpp index cb0b375701..9daa696e62 100644 --- a/shell/assistantpopup.cpp +++ b/shell/assistantpopup.cpp @@ -1,416 +1,415 @@ /* Copyright 2009 David Nolden Copyright 2012 Milian Wolff Copyright 2014 Sven Brauch 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 "assistantpopup.h" #include "sublime/holdupdates.h" #include "util/kdevstringhandler.h" #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include using namespace KDevelop; namespace { /// Interval after which the state of the popup is re-evaluated /// Used to avoid flickering caused when user is quickly inserting code const int UPDATE_STATE_INTERVAL = 300; // ms const int ASSISTANT_MODIFIER = #ifdef Q_OS_MAC Qt::CTRL; #else Qt::ALT; #endif const int ASSISTANT_MOD_KEY = #ifdef Q_OS_MAC Qt::Key_Control; #else Qt::Key_Alt; #endif QWidget* findByClassname(const KTextEditor::View* view, const QString& klass) { auto children = view->findChildren(); for ( auto child: children ) { if ( child->metaObject()->className() == klass ) { return child; } } return nullptr; }; /** * @brief Get the geometry of the inner part (with the text) of the KTextEditor::View being used. */ QRect textWidgetGeometry(const KTextEditor::View *view) { // Subtract the width of the right scrollbar int scrollbarWidth = 0; if ( auto scrollbar = findByClassname(view, "KateScrollBar") ) { scrollbarWidth = scrollbar->width(); } // Subtract the width of the bottom scrollbar int bottomScrollbarWidth = 0; if ( auto bottom = findByClassname(view, "QScrollBar") ) { bottomScrollbarWidth = bottom->height(); } auto geom = view->geometry(); geom.adjust(0, 0, -scrollbarWidth, -bottomScrollbarWidth); return geom; } } AssistantPopupConfig::AssistantPopupConfig(QObject *parent) : QObject(parent) , m_active(false) , m_useVerticalLayout(false) { } void AssistantPopupConfig::setColorsFromView(QObject *view) { auto iface = dynamic_cast(view); Q_ASSERT(iface); m_foreground = iface->configValue("line-number-color").value(); m_background = iface->configValue("icon-border-color").value(); m_highlight = iface->configValue("folding-marker-color").value(); if ( KColorUtils::luma(m_background) < 0.3 ) { m_foreground = KColorUtils::lighten(m_foreground, 0.7); } const float lumaDiff = KColorUtils::luma(m_highlight) - KColorUtils::luma(m_background); if ( qAbs(lumaDiff) < 0.5 ) { m_highlight = QColor::fromHsv(m_highlight.hue(), qMin(255, m_highlight.saturation() + 80), lumaDiff > 0 ? qMin(255, m_highlight.value() + 120) : qMax(80, m_highlight.value() - 40)); } emit colorsChanged(); } bool AssistantPopupConfig::isActive() const { return m_active; } void AssistantPopupConfig::setActive(bool active) { if (m_active == active) { return; } m_active = active; emit activeChanged(m_active); } void AssistantPopupConfig::setUseVerticalLayout(bool vertical) { if (m_useVerticalLayout == vertical) { return; } m_useVerticalLayout = vertical; emit useVerticalLayoutChanged(m_useVerticalLayout); } void AssistantPopupConfig::setTitle(const QString& title) { if (m_title == title) { return; } m_title = title; emit titleChanged(m_title); } void AssistantPopupConfig::setModel(const QList& model) { if (m_model == model) { return; } qDeleteAll( m_model ); m_model = model; emit modelChanged(model); } AssistantPopup::AssistantPopup() // main window as parent to use maximal space available in worst case : QDeclarativeView(ICore::self()->uiController()->activeMainWindow()) , m_config(new AssistantPopupConfig(this)) , m_shownAtBottom(false) , m_reopening(false) , m_updateTimer(new QTimer(this)) { QPalette p = palette(); p.setColor(QPalette::Window, Qt::transparent); setPalette(p); setBackgroundRole(QPalette::Window); setBackgroundBrush(QBrush(QColor(0, 0, 0, 0))); setResizeMode(QDeclarativeView::SizeViewToRootObject); setAttribute(Qt::WA_ShowWithoutActivating); rootContext()->setContextProperty("config", m_config); setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::GenericDataLocation, "kdevelop/assistantpopup.qml"))); if (!rootObject()) { qWarning() << "Failed to load assistant markup! The assistant will not work."; } m_updateTimer->setInterval(UPDATE_STATE_INTERVAL); m_updateTimer->setSingleShot(true); connect(m_updateTimer, &QTimer::timeout, this, &AssistantPopup::updateState); for (int i = Qt::Key_0; i <= Qt::Key_9; ++i) { m_shortcuts.append(new QShortcut(ASSISTANT_MODIFIER + i, this)); } setActive(false); } void AssistantPopup::reset(KTextEditor::View* view, const IAssistant::Ptr& assistant) { setView(view); setAssistant(assistant); updateLayoutType(); m_updateTimer->start(); } void AssistantPopup::setView(KTextEditor::View* view) { if (m_view == view) { return; } setActive(false); if (m_view) { m_view->removeEventFilter(this); disconnect(m_view.data(), &KTextEditor::View::verticalScrollPositionChanged, this, &AssistantPopup::updatePosition); } m_view = view; if (m_view) { m_view->installEventFilter(this); connect(m_view.data(), &KTextEditor::View::verticalScrollPositionChanged, this, &AssistantPopup::updatePosition); } } void AssistantPopup::setAssistant(const IAssistant::Ptr& assistant) { if (m_assistant == assistant) { return; } if (m_assistant) { disconnect(m_assistant.data(), &IAssistant::actionsChanged, m_updateTimer, static_cast(&QTimer::start)); disconnect(m_assistant.data(), &IAssistant::hide, this, &AssistantPopup::hideAssistant); } m_assistant = assistant; if (m_assistant) { connect(m_assistant.data(), &IAssistant::actionsChanged, m_updateTimer, static_cast(&QTimer::start)); connect(m_assistant.data(), &IAssistant::hide, this, &AssistantPopup::hideAssistant); } } void AssistantPopup::setActive(bool active) { m_config->setActive(active); for (auto shortcut : m_shortcuts) { shortcut->setEnabled(active); } } bool AssistantPopup::viewportEvent(QEvent *event) { // For some reason, QGraphicsView posts a WindowActivate event // when it is shown, even if disabled through setting the WA_ShowWithoutActivate // attribute. This causes all focus-driven popups (QuickOpen, tooltips, ...) // to hide when the assistant opens. Thus, prevent it from processing the Show event here. if ( event->type() == QEvent::Show ) { return true; } return QGraphicsView::viewportEvent(event); } bool AssistantPopup::eventFilter(QObject* object, QEvent* event) { Q_UNUSED(object); if (!m_view || (object != m_view.data())) return false; if (event->type() == QEvent::Resize) { updateLayoutType(); updatePosition(m_view.data(), KTextEditor::Cursor::invalid()); } else if (event->type() == QEvent::Hide) { executeHideAction(); } else if (event->type() == QEvent::KeyPress) { auto keyEvent = static_cast(event); if (keyEvent->modifiers() == ASSISTANT_MODIFIER) { setActive(true); } if (keyEvent->key() == Qt::Key_Escape) { executeHideAction(); } } else if (event->type() == QEvent::KeyRelease) { auto keyEvent = static_cast(event); if (keyEvent->modifiers() == ASSISTANT_MODIFIER || keyEvent->key() == ASSISTANT_MOD_KEY) { setActive(false); } } return false; } void AssistantPopup::updatePosition(KTextEditor::View* view, const KTextEditor::Cursor& newPos) { static const int MARGIN = 12; if (newPos.isValid() && newPos.line() == 0 && !m_shownAtBottom) { // the position is not going to change; don't waste time return; } auto editorGeometry = textWidgetGeometry(view); const auto startCursorCoordinate = view->cursorToCoordinate(KTextEditor::Cursor(0, 0)); // algorithm for popup positioning: // if we are scrolled to the top: show at bottom // else: // if: current cursor position is in upper half => show at bottom // else: show at top const bool showAtBottom = startCursorCoordinate.y() == 0 ? true : view->cursorPositionCoordinates().y() < view->height()/2; const QPoint targetLocation = showAtBottom ? parentWidget()->mapFromGlobal(view->mapToGlobal(editorGeometry.bottomRight() + QPoint(-width() - MARGIN, -MARGIN - height()))) : parentWidget()->mapFromGlobal(view->mapToGlobal(editorGeometry.topRight() + QPoint(-width() - MARGIN, MARGIN))); if (pos() == targetLocation) { return; } if ( m_reopening ) { // When the assistant is already visible, close to no flickering will occur anyways, // so we can avoid the full repaint of the window. move(targetLocation); } else { Sublime::HoldUpdates hold(ICore::self()->uiController()->activeMainWindow()); move(targetLocation); } } IAssistant::Ptr AssistantPopup::assistant() const { return m_assistant; } void AssistantPopup::executeHideAction() { if ( isVisible() ) { m_assistant->doHide(); } } void AssistantPopup::hideAssistant() { reset(nullptr, {}); // indirectly calls hide() } void AssistantPopup::updateLayoutType() { if ( !m_assistant || !m_view ) { return; } // Make a rough estimate of the width the assistant will need // and decide on whether to use vertical layout or not. const auto& metrics = fontMetrics(); auto textWidth = 0; textWidth += metrics.boundingRect(KDevelop::htmlToPlainText(assistant()->title())).width(); for ( const auto& action: assistant()->actions() ) { textWidth += metrics.boundingRect(KDevelop::htmlToPlainText(action->description())).width(); textWidth += 10; } m_config->setUseVerticalLayout(textWidth > textWidgetGeometry(m_view).width()*0.75); updateState(); } void AssistantPopup::updateState() { if (!m_assistant || m_assistant->actions().isEmpty() || !m_view) { hide(); return; } auto curShortcut = m_shortcuts.constBegin(); auto hideAction = new QAction(i18n("Hide"), this); connect(*curShortcut, &QShortcut::activated, hideAction, &QAction::trigger); connect(hideAction, &QAction::triggered, this, &AssistantPopup::executeHideAction); QList items; foreach (IAssistantAction::Ptr action, m_assistant->actions()) { QAction* asQAction = action->toKAction(); items << asQAction; asQAction->setParent(this); //For some reason, QAction's setShortcut does nothing, so we manage with QShortcut if (++curShortcut != m_shortcuts.constEnd()) { connect(*curShortcut, &QShortcut::activated, asQAction, &QAction::trigger); } } items << hideAction; auto view = ICore::self()->documentController()->activeTextDocumentView(); m_config->setColorsFromView(view); m_config->setModel(items); m_config->setTitle(m_assistant->title()); setActive(false); // both changed title or actions may change the appearance of the popup // force recomputing the size hint resize(sizeHint()); updatePosition(m_view, KTextEditor::Cursor::invalid()); show(); } diff --git a/shell/editorconfigpage.h b/shell/editorconfigpage.h index 01d1767019..593523bf95 100644 --- a/shell/editorconfigpage.h +++ b/shell/editorconfigpage.h @@ -1,53 +1,53 @@ /* * This file is part of KDevelop * Copyright 2014 Alex Richardson * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 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 6 of version 3 of the license. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef KDEVPLATFORM_EDITORCONFIGPAGE_H #define KDEVPLATFORM_EDITORCONFIGPAGE_H #include namespace KDevelop { /** - * This class makes all the KTextEditor config pages avaible for use + * This class makes all the KTextEditor config pages available for use * as a single KDevelop::ConfigPage */ class EditorConfigPage : public ConfigPage { Q_OBJECT public: EditorConfigPage(QWidget* parent); virtual ~EditorConfigPage(); virtual QString name() const override; virtual QIcon icon() const override; virtual QString fullName() const override; virtual int childPages() const override; virtual ConfigPage* childPage(int number) override; public Q_SLOTS: // nothing to edit on this page, only subpages have actual configuration virtual void apply() override {}; virtual void reset() override {}; virtual void defaults() override {}; }; } #endif // KDEVPLATFORM_EDITORCONFIGPAGE_H diff --git a/sublime/examples/example1main.cpp b/sublime/examples/example1main.cpp index 96e74a23a8..1dfcf6e6b9 100644 --- a/sublime/examples/example1main.cpp +++ b/sublime/examples/example1main.cpp @@ -1,113 +1,111 @@ /*************************************************************************** * Copyright 2006-2007 Alexander Dymo * * * * 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 "example1main.h" #include #include #include #include #include #include #include #include -#include - #include #include #include #include #include #include #include Example1Main::Example1Main() :KXmlGuiWindow(0) { //documents m_controller = new Sublime::Controller(this); Sublime::Document *doc1 = new Sublime::UrlDocument(m_controller, QUrl::fromLocalFile("~/foo.cpp")); Sublime::Document *doc2 = new Sublime::UrlDocument(m_controller, QUrl::fromLocalFile("~/boo.cpp")); Sublime::Document *doc3 = new Sublime::UrlDocument(m_controller, QUrl::fromLocalFile("~/moo.cpp")); //documents for toolviews Sublime::Document *tool1 = new Sublime::ToolDocument("ListView", m_controller, new Sublime::SimpleToolWidgetFactory("ListView")); Sublime::Document *tool2 = new Sublime::ToolDocument("TextEdit", m_controller, new Sublime::SimpleToolWidgetFactory("TextEdit")); //areas (aka perspectives) qDebug() << "constructing area 1"; m_area1 = new Sublime::Area(m_controller, "Area 1"); m_controller->addDefaultArea(m_area1); m_area1->addView(doc1->createView()); m_area1->addView(doc2->createView()); m_area1->addView(doc3->createView()); m_area1->addToolView(tool1->createView(), Sublime::Left); m_area1->addToolView(tool2->createView(), Sublime::Bottom); qDebug() << "constructing area 2"; m_area2 = new Sublime::Area(m_controller, "Area 2"); m_controller->addDefaultArea(m_area2); Sublime::View *view1 = doc1->createView(); m_area2->addView(view1); Sublime::View *view2 = doc2->createView(); m_area2->addView(view2, view1, Qt::Vertical); m_area2->addView(doc3->createView(), view2, Qt::Horizontal); m_area2->addToolView(tool1->createView(), Sublime::Bottom); m_area2->addToolView(tool2->createView(), Sublime::Right); //example main window stuff QWidget *w = new QWidget(this); setCentralWidget(w); QVBoxLayout *l = new QVBoxLayout(w); QMenu *areaMenu = menuBar()->addMenu("Areas"); areaMenu->addAction("Area 1", this, SLOT(selectArea1())); areaMenu->addAction("Area 2", this, SLOT(selectArea2())); QPushButton *b1 = new QPushButton("Area 1", this); connect(b1, &QPushButton::clicked, this, &Example1Main::selectArea1); l->addWidget(b1); QPushButton *b2 = new QPushButton("Area 2", this); connect(b2, &QPushButton::clicked, this, &Example1Main::selectArea2); l->addWidget(b2); } void Example1Main::selectArea1() { Sublime::MainWindow *main = new Sublime::MainWindow(m_controller); connect(main, &Sublime::MainWindow::areaChanged, this, &Example1Main::updateTitle); m_controller->showArea(m_area1, main); main->show(); } void Example1Main::selectArea2() { Sublime::MainWindow *main = new Sublime::MainWindow(m_controller); connect(main, &Sublime::MainWindow::areaChanged, this, &Example1Main::updateTitle); m_controller->showArea(m_area2, main); main->show(); } void Example1Main::updateTitle(Sublime::Area *area) { Sublime::MainWindow *main = qobject_cast(sender()); main->setWindowTitle(area->objectName()); } diff --git a/sublime/mainwindow_p.h b/sublime/mainwindow_p.h index d31e6ecb95..ed8f4931ae 100644 --- a/sublime/mainwindow_p.h +++ b/sublime/mainwindow_p.h @@ -1,169 +1,168 @@ /*************************************************************************** * Copyright 2006-2007 Alexander Dymo * * * * 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. * ***************************************************************************/ #ifndef KDEVPLATFORM_SUBLIMEMAINWINDOW_P_H #define KDEVPLATFORM_SUBLIMEMAINWINDOW_P_H #include #include #include #include #include #include #include -#include #include "area.h" #include "sublimedefs.h" #include "mainwindow.h" #include #include #include #include #include #include class QMenu; class QAction; class QSplitter; class QDockWidget; class QComboBox; namespace Sublime { class View; class Container; class Controller; class AreaIndex; class IdealMainWidget; class IdealController; class AreaTabButton : public QWidget { public: AreaTabButton(QString text, QIcon icon, uint iconSize, QWidget* parent, bool isCurrent, QWidget* _customButtonWidget) ; QLabel* iconLabel; QLabel* textLabel; QWidget* customButtonWidget; void setIsCurrent ( bool arg1 ); private: bool m_isCurrent; }; class MainWindowPrivate: public QObject { Q_OBJECT public: MainWindowPrivate(MainWindow *w, Controller* controller); ~MainWindowPrivate(); /**Use this to create tool views for an area.*/ class IdealToolViewCreator { public: IdealToolViewCreator(MainWindowPrivate *_d): d(_d) {} Area::WalkerMode operator() (View *view, Sublime::Position position); private: MainWindowPrivate *d; }; /**Use this to create views for an area.*/ class ViewCreator { public: ViewCreator(MainWindowPrivate *_d, QList _topViews = QList()): d(_d), topViews(_topViews.toSet()) {} Area::WalkerMode operator() (AreaIndex *index); private: MainWindowPrivate *d; QSet topViews; }; /**Reconstructs the mainwindow according to the current area.*/ void reconstruct(); /**Reconstructs the views according to the current area index.*/ void reconstructViews(QList topViews = QList()); /**Clears the area leaving mainwindow empty.*/ void clearArea(); /** Sets a @p w widget that will be shown when there are no documents on the area */ void setBackgroundCentralWidget(QWidget* w); void activateFirstVisibleView(); Controller *controller; Area *area; QList docks; QMap viewContainers; QMap widgetToView; View *activeView; View *activeToolView; QWidget *centralWidget; QWidget* bgCentralWidget; QSplitter* splitterCentralWidget; IdealController *idealController; int ignoreDockShown; bool autoAreaSettingsSave; public slots: void toggleDocksShown(); void viewAdded(Sublime::AreaIndex *index, Sublime::View *view); void viewRemovedInternal(Sublime::AreaIndex *index, Sublime::View *view); void raiseToolView(Sublime::View* view); void aboutToRemoveView(Sublime::AreaIndex *index, Sublime::View *view); void toolViewAdded(Sublime::View *toolView, Sublime::Position position); void aboutToRemoveToolView(Sublime::View *toolView, Sublime::Position position); void toolViewMoved(Sublime::View *toolView, Sublime::Position position); void setTabBarLeftCornerWidget(QWidget* widget); private slots: void switchToArea(QAction *action); void updateAreaSwitcher(Sublime::Area *area); void slotDockShown(Sublime::View*, Sublime::Position, bool); void widgetResized(Qt::DockWidgetArea dockArea, int thickness); void widgetCloseRequest(QWidget* widget); void showLeftDock(bool b); void showRightDock(bool b); void showBottomDock(bool b); void focusEditor(); void selectNextDock(); void selectPreviousDock(); private: void setBackgroundVisible(bool v); Qt::DockWidgetArea positionToDockArea(Position position); void cleanCentralWidget(); MainWindow *m_mainWindow; // uses QPointer to make already-deleted splitters detectable QMap > m_indexSplitters; QMap m_areaActions; QMap m_actionAreas; QPointer m_leftTabbarCornerWidget; }; } #endif diff --git a/vcs/dvcs/dvcsplugin.cpp b/vcs/dvcs/dvcsplugin.cpp index ebfa798064..3b1ca023b1 100644 --- a/vcs/dvcs/dvcsplugin.cpp +++ b/vcs/dvcs/dvcsplugin.cpp @@ -1,173 +1,172 @@ /*************************************************************************** * This file was partly taken from KDevelop's cvs plugin * * Copyright 2007 Robert Gruber * * * * Adapted for DVCS (added templates) * * Copyright 2008 Evgeniy Ivanov * * * * 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 DVCS_PLUGIN_CC #define DVCS_PLUGIN_CC #include "dvcsplugin.h" #include #include #include #include #include -#include #include #include #include #include #include #include #include #include #include #include #include "dvcsjob.h" #include "ui/dvcsimportmetadatawidget.h" #include "ui/branchmanager.h" #include "ui/revhistory/commitlogmodel.h" #include "ui/revhistory/commitView.h" #include #include namespace KDevelop { struct DistributedVersionControlPluginPrivate { explicit DistributedVersionControlPluginPrivate(DistributedVersionControlPlugin * pThis) : m_common(new VcsPluginHelper(pThis, pThis)) {} ~DistributedVersionControlPluginPrivate() { delete m_common; } VcsPluginHelper* m_common; }; //class DistributedVersionControlPlugin DistributedVersionControlPlugin::DistributedVersionControlPlugin(QObject *parent, const QString& componentName) : IPlugin(componentName, parent) , d(new DistributedVersionControlPluginPrivate(this)) {} DistributedVersionControlPlugin::~DistributedVersionControlPlugin() { //TODO: Find out why this crashes on the svn tests delete d->m_factory; delete d; } // End: KDevelop::IBasicVersionControl // Begin: KDevelop::IDistributedVersionControl // End: KDevelop::IDistributedVersionControl KDevelop::VcsImportMetadataWidget* DistributedVersionControlPlugin::createImportMetadataWidget(QWidget* parent) { return new DvcsImportMetadataWidget(parent); } KDevelop::ContextMenuExtension DistributedVersionControlPlugin::contextMenuExtension(Context* context) { d->m_common->setupFromContext(context); QList const & ctxUrlList = d->m_common->contextUrlList(); bool isWorkingDirectory = false; foreach(const QUrl &url, ctxUrlList) { if (isValidDirectory(url)) { isWorkingDirectory = true; break; } } if (!isWorkingDirectory) { // Not part of a repository return ContextMenuExtension(); } QMenu * menu = d->m_common->commonActions(); menu->addSeparator(); menu->addAction(i18n("Branches..."), this, SLOT(ctxBranchManager()))->setEnabled(ctxUrlList.count()==1); menu->addAction(i18n("Revision Graph..."), this, SLOT(ctxRevHistory()))->setEnabled(ctxUrlList.count()==1); additionalMenuEntries(menu, ctxUrlList); ContextMenuExtension menuExt; menuExt.addAction(ContextMenuExtension::VcsGroup, menu->menuAction()); return menuExt; } void DistributedVersionControlPlugin::additionalMenuEntries(QMenu* /*menu*/, const QList& /*urls*/) {} static QString stripPathToDir(const QString &path) { QFileInfo info = QFileInfo(path); return info.isDir() ? info.absoluteFilePath() : info.absolutePath(); } void DistributedVersionControlPlugin::ctxBranchManager() { QList const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); ICore::self()->documentController()->saveAllDocuments(); BranchManager branchManager(stripPathToDir(ctxUrlList.front().toLocalFile()), this, core()->uiController()->activeMainWindow()); branchManager.exec(); } // This is redundant with the normal VCS "history" action void DistributedVersionControlPlugin::ctxRevHistory() { QList const & ctxUrlList = d->m_common->contextUrlList(); Q_ASSERT(!ctxUrlList.isEmpty()); QDialog d; QVBoxLayout* layout = new QVBoxLayout(&d); d.setLayout(layout); CommitLogModel* model = new CommitLogModel(this, ctxUrlList.first().toLocalFile(), &d); CommitView *revTree = new CommitView(&d); revTree->setModel(model); layout->addWidget(revTree); QDialogButtonBox* dbox = new QDialogButtonBox(&d); dbox->setStandardButtons(QDialogButtonBox::Close); connect(dbox, &QDialogButtonBox::accepted, &d, &QDialog::accept); connect(dbox, &QDialogButtonBox::rejected, &d, &QDialog::reject); layout->addWidget(dbox); d.exec(); } } #endif