diff options
author | Jarek Kobus <jkobus@trolltech.com> | 2009-01-08 10:48:16 +0100 |
---|---|---|
committer | Jarek Kobus <jkobus@trolltech.com> | 2009-01-08 10:48:16 +0100 |
commit | 629832ce592a36457dba12d2fb583788469c77bf (patch) | |
tree | b1799646d41a076b2948eaafbbe070c79a9de9f7 /src/plugins | |
parent | 1b77e4e99ea4a85588f01b2fc3d406de00a115da (diff) | |
parent | 0bbed6d786bbb3a6d0f0ae0aa799ed8a4ddd1f41 (diff) | |
download | qt-creator-629832ce592a36457dba12d2fb583788469c77bf.tar.gz |
Merge branch 'master' of git@scm.dev.nokia.troll.no:creator/mainline
Diffstat (limited to 'src/plugins')
24 files changed, 852 insertions, 357 deletions
diff --git a/src/plugins/coreplugin/coreconstants.h b/src/plugins/coreplugin/coreconstants.h index 857dd5be37..301cfb6d39 100644 --- a/src/plugins/coreplugin/coreconstants.h +++ b/src/plugins/coreplugin/coreconstants.h @@ -52,7 +52,7 @@ namespace Constants { const char * const IDE_VERSION_LONG = IDE_VERSION; const char * const IDE_AUTHOR = "Nokia Corporation"; -const char * const IDE_YEAR = "2008"; +const char * const IDE_YEAR = "2009"; #ifdef IDE_REVISION const char * const IDE_REVISION_STR = STRINGIFY(IDE_REVISION); diff --git a/src/plugins/coreplugin/editormanager/editormanager.h b/src/plugins/coreplugin/editormanager/editormanager.h index 729ac7cd84..eec20a4a05 100644 --- a/src/plugins/coreplugin/editormanager/editormanager.h +++ b/src/plugins/coreplugin/editormanager/editormanager.h @@ -65,6 +65,7 @@ enum MakeWritableResult { }; struct EditorManagerPrivate; + namespace Internal { class OpenEditorsWindow; class EditorSplitter; @@ -224,7 +225,8 @@ private: namespace Internal { -class EditorClosingCoreListener : public ICoreListener { +class EditorClosingCoreListener : public ICoreListener +{ Q_OBJECT public: diff --git a/src/plugins/coreplugin/mainwindow.cpp b/src/plugins/coreplugin/mainwindow.cpp index 2a9fff0f4e..f68c5da7d0 100644 --- a/src/plugins/coreplugin/mainwindow.cpp +++ b/src/plugins/coreplugin/mainwindow.cpp @@ -625,6 +625,7 @@ void MainWindow::registerDefaultActions() // Toggle Sidebar Action m_toggleSideBarAction = new QAction(QIcon(Constants::ICON_TOGGLE_SIDEBAR), tr("Toggle Sidebar"), this); + m_toggleSideBarAction->setCheckable(true); cmd = am->registerAction(m_toggleSideBarAction, Constants::TOGGLE_SIDEBAR, m_globalContext); #ifdef Q_OS_MAC cmd->setDefaultKeySequence(QKeySequence("Ctrl+0")); diff --git a/src/plugins/coreplugin/navigationwidget.cpp b/src/plugins/coreplugin/navigationwidget.cpp index 9bbb4323d2..412559a9b0 100644 --- a/src/plugins/coreplugin/navigationwidget.cpp +++ b/src/plugins/coreplugin/navigationwidget.cpp @@ -166,6 +166,7 @@ int NavigationWidget::storedWidth() void NavigationWidget::placeHolderChanged(NavigationWidgetPlaceHolder *holder) { m_toggleSideBarAction->setEnabled(holder); + m_toggleSideBarAction->setChecked(holder && isShown()); } void NavigationWidget::resizeEvent(QResizeEvent *re) @@ -281,8 +282,12 @@ void NavigationWidget::setShown(bool b) if (m_shown == b) return; m_shown = b; - if (NavigationWidgetPlaceHolder::m_current) + if (NavigationWidgetPlaceHolder::m_current) { NavigationWidgetPlaceHolder::m_current->setVisible(m_shown && !m_suppressed); + m_toggleSideBarAction->setChecked(m_shown); + } else { + m_toggleSideBarAction->setChecked(false); + } } bool NavigationWidget::isShown() const diff --git a/src/plugins/coreplugin/outputpane.cpp b/src/plugins/coreplugin/outputpane.cpp index b9cd825e24..6d97c5d361 100644 --- a/src/plugins/coreplugin/outputpane.cpp +++ b/src/plugins/coreplugin/outputpane.cpp @@ -488,13 +488,13 @@ OutputPaneToggleButton::OutputPaneToggleButton(int number, const QString &text, setFocusPolicy(Qt::NoFocus); setCheckable(true); setStyleSheet( - "QPushButton { border-image: url(:/qworkbench/images/panel_button.png) 2 2 2 19 repeat;" + "QPushButton { border-image: url(:/qworkbench/images/panel_button.png) 2 2 2 19;" " border-width: 2px 2px 2px 19px; padding-left: -17; padding-right: 4 } " - "QPushButton:checked { border-image: url(:/qworkbench/images/panel_button_checked.png) 2 2 2 19 repeat } " + "QPushButton:checked { border-image: url(:/qworkbench/images/panel_button_checked.png) 2 2 2 19 } " #ifndef Q_WS_MAC // Mac UI's dont usually do hover - "QPushButton:checked:hover { border-image: url(:/qworkbench/images/panel_button_checked_hover.png) 2 2 2 19 repeat } " - "QPushButton:pressed:hover { border-image: url(:/qworkbench/images/panel_button_pressed.png) 2 2 2 19 repeat } " - "QPushButton:hover { border-image: url(:/qworkbench/images/panel_button_hover.png) 2 2 2 19 repeat } " + "QPushButton:checked:hover { border-image: url(:/qworkbench/images/panel_button_checked_hover.png) 2 2 2 19 } " + "QPushButton:pressed:hover { border-image: url(:/qworkbench/images/panel_button_pressed.png) 2 2 2 19 } " + "QPushButton:hover { border-image: url(:/qworkbench/images/panel_button_hover.png) 2 2 2 19 } " #endif ); } diff --git a/src/plugins/cppeditor/cpphoverhandler.cpp b/src/plugins/cppeditor/cpphoverhandler.cpp index ba97e5a212..6ebf51b2a2 100644 --- a/src/plugins/cppeditor/cpphoverhandler.cpp +++ b/src/plugins/cppeditor/cpphoverhandler.cpp @@ -72,10 +72,16 @@ CppHoverHandler::CppHoverHandler(QObject *parent) m_modelManager = m_core->pluginManager()->getObject<CppTools::CppModelManagerInterface>(); QFileInfo fi(ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->settings()->fileName()); - m_helpEngine = new QHelpEngineCore(fi.absolutePath() + // FIXME shouldn't the help engine create the directory if it doesn't exist? + QDir directory(fi.absolutePath()+"/qtcreator"); + if (!directory.exists()) + directory.mkpath(directory.absolutePath()); + + m_helpEngine = new QHelpEngineCore(directory.absolutePath() + QLatin1String("/helpcollection.qhc"), this); //m_helpEngine->setAutoSaveFilter(false); - m_helpEngine->setupData(); + if (!m_helpEngine->setupData()) + qWarning() << "Could not initialize help engine:" << m_helpEngine->error(); m_helpEngine->setCurrentFilter(tr("Unfiltered")); m_helpEngineNeedsSetup = m_helpEngine->registeredDocumentations().count() == 0; diff --git a/src/plugins/cpptools/cpptoolsplugin.cpp b/src/plugins/cpptools/cpptoolsplugin.cpp index 4195fbee33..866a3d05c9 100644 --- a/src/plugins/cpptools/cpptoolsplugin.cpp +++ b/src/plugins/cpptools/cpptoolsplugin.cpp @@ -163,7 +163,8 @@ QFileInfo CppToolsPlugin::findFile(const QDir &dir, const QString &name, if (debug) qDebug() << Q_FUNC_INFO << dir << name; - if (project) { + QFileInfo fileInSameDir(dir, name); + if (project && !fileInSameDir.isFile()) { QString pattern = QString(1, QLatin1Char('/')); pattern += name; const QStringList projectFiles = project->files(ProjectExplorer::Project::AllFiles); @@ -173,7 +174,7 @@ QFileInfo CppToolsPlugin::findFile(const QDir &dir, const QString &name, return QFileInfo(*it); return QFileInfo(); } - return QFileInfo(dir, name); + return fileInSameDir; } // Figure out file type diff --git a/src/plugins/debugger/debugger.pro b/src/plugins/debugger/debugger.pro index 7308fb441c..b47e7d5ee0 100644 --- a/src/plugins/debugger/debugger.pro +++ b/src/plugins/debugger/debugger.pro @@ -76,7 +76,6 @@ FORMS += attachexternaldialog.ui \ attachremotedialog.ui \ breakbyfunction.ui \ breakcondition.ui \ - mode.ui \ gdboptionpage.ui \ startexternaldialog.ui \ diff --git a/src/plugins/debugger/gdbengine.cpp b/src/plugins/debugger/gdbengine.cpp index 7c7d3b6d32..fa6f9ab325 100644 --- a/src/plugins/debugger/gdbengine.cpp +++ b/src/plugins/debugger/gdbengine.cpp @@ -2944,8 +2944,8 @@ void GdbEngine::runCustomDumper(const WatchData & data0, bool dumpChildren) QString outertype = isTemplate ? tmplate : data.type; // adjust the data extract - if (outertype == "QWidget") - outertype = "QObject"; + if (outertype == m_namespace + "QWidget") + outertype = m_namespace + "QObject"; QString extraArgs[4]; extraArgs[0] = "0"; @@ -2977,10 +2977,17 @@ void GdbEngine::runCustomDumper(const WatchData & data0, bool dumpChildren) if (lastOpened != -1 && lastClosed != -1) slotNumber = data.iname.mid(lastOpened + 1, lastClosed - lastOpened - 1); extraArgs[0] = slotNumber; - } else if (outertype == m_namespace + "QMap") { - QString nodetype = m_namespace + "QMapNode"; - nodetype += data.type.mid(m_namespace.size() + 4); - //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype; + } else if (outertype == m_namespace + "QMap" || outertype == m_namespace + "QMultiMap") { + QString nodetype; + if (m_qtVersion >= (4 << 16) + (5 << 8) + 0) { + nodetype = m_namespace + "QMapNode"; + nodetype += data.type.mid(outertype.size()); + } else { + // FIXME: doesn't work for QMultiMap + nodetype = data.type + "::Node"; + } + //qDebug() << "OUTERTYPE: " << outertype << " NODETYPE: " << nodetype + // << "QT VERSION" << m_qtVersion << ((4 << 16) + (5 << 8) + 0); extraArgs[2] = sizeofTypeExpression(nodetype); extraArgs[3] = "(size_t)&(('" + nodetype + "'*)0)->value"; } else if (outertype == m_namespace + "QMapNode") { @@ -3311,6 +3318,16 @@ void GdbEngine::handleQueryDataDumper2(const GdbResultRecord &record) GdbMi contents(output.data()); GdbMi simple = contents.findChild("dumpers"); m_namespace = contents.findChild("namespace").data(); + GdbMi qtversion = contents.findChild("qtversion"); + if (qtversion.children().size() == 3) { + m_qtVersion = (qtversion.childAt(0).data().toInt() << 16) + + (qtversion.childAt(1).data().toInt() << 8) + + qtversion.childAt(2).data().toInt(); + //qDebug() << "FOUND QT VERSION: " << qtversion.toString() << m_qtVersion; + } else { + m_qtVersion = 0; + } + //qDebug() << "OUTPUT: " << output.toString(); //qDebug() << "CONTENTS: " << contents.toString(); //qDebug() << "SIMPLE DUMPERS: " << simple.toString(); @@ -3536,8 +3553,9 @@ void GdbEngine::handleDumpCustomValue2(const GdbResultRecord &record, // << item.findChild("nameencoded").data()[1]; if (item.findChild("nameencoded").data()[0] == '1') data1.name = QByteArray::fromBase64(data1.name.toUtf8()); - if (item.findChild("nameisindex").data()[0] == '1') - data1.name = '[' + data1.name + ']'; + QString key = item.findChild("key").data(); + if (!key.isEmpty()) + data1.name += " (" + key + ")"; setWatchDataType(data1, item.findChild("type")); setWatchDataExpression(data1, item.findChild("exp")); setWatchDataChildCount(data1, item.findChild("numchild")); @@ -3951,6 +3969,9 @@ void GdbEngine::tryLoadCustomDumpers() sendCommand("sharedlibrary " + dotEscape(lib)); if (qq->useFastStart()) sendCommand("set stop-on-solib-events 1"); + } else { + qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " + << lib << QFileInfo(lib).isExecutable(); } #endif #if defined(Q_OS_MAC) @@ -3964,6 +3985,9 @@ void GdbEngine::tryLoadCustomDumpers() sendCommand("sharedlibrary " + dotEscape(lib)); if (qq->useFastStart()) sendCommand("set stop-on-solib-events 1"); + } else { + qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " + << lib << QFileInfo(lib).isExecutable(); } #endif #if defined(Q_OS_WIN) @@ -3977,6 +4001,9 @@ void GdbEngine::tryLoadCustomDumpers() sendCommand("sharedlibrary " + dotEscape(lib)); if (qq->useFastStart()) sendCommand("set stop-on-solib-events 1"); + } else { + qDebug() << "DEBUG HELPER LIBRARY IS NOT USABLE: " + << lib << QFileInfo(lib).isExecutable(); } #endif diff --git a/src/plugins/debugger/gdbengine.h b/src/plugins/debugger/gdbengine.h index c1344f86dd..000c0b84a9 100644 --- a/src/plugins/debugger/gdbengine.h +++ b/src/plugins/debugger/gdbengine.h @@ -333,6 +333,7 @@ private: QStringList m_availableSimpleDumpers; QString m_namespace; // namespace used in "namespaced Qt"; + int m_qtVersion; // Qt version used in the debugged program DataDumperState m_dataDumperState; // state of qt creator dumpers QList<GdbMi> m_currentFunctionArgs; diff --git a/src/plugins/debugger/mode.ui b/src/plugins/debugger/mode.ui deleted file mode 100644 index da44cf38b4..0000000000 --- a/src/plugins/debugger/mode.ui +++ /dev/null @@ -1,76 +0,0 @@ -<ui version="4.0" > - <class>DebugMode</class> - <widget class="QWidget" name="DebugMode" > - <property name="geometry" > - <rect> - <x>0</x> - <y>0</y> - <width>558</width> - <height>353</height> - </rect> - </property> - <property name="windowTitle" > - <string>Form</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3" > - <property name="spacing" > - <number>0</number> - </property> - <property name="margin" > - <number>0</number> - </property> - <item> - <widget class="QSplitter" name="vSplitter" > - <property name="orientation" > - <enum>Qt::Vertical</enum> - </property> - <widget class="QWidget" native="1" name="editorHolder" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Preferred" hsizetype="Preferred" > - <horstretch>10</horstretch> - <verstretch>10</verstretch> - </sizepolicy> - </property> - </widget> - <widget class="QWidget" name="layoutWidget" > - <layout class="QVBoxLayout" name="verticalLayout" > - <property name="spacing" > - <number>0</number> - </property> - <item> - <layout class="QVBoxLayout" name="toolbarLayout" > - <property name="spacing" > - <number>0</number> - </property> - </layout> - </item> - <item> - <widget class="QSplitter" name="hSplitter" > - <property name="orientation" > - <enum>Qt::Horizontal</enum> - </property> - <widget class="QTabWidget" name="bottomTabWidget" > - <property name="sizePolicy" > - <sizepolicy vsizetype="Expanding" hsizetype="Expanding" > - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="tabPosition" > - <enum>QTabWidget::South</enum> - </property> - <property name="tabShape" > - <enum>QTabWidget::Rounded</enum> - </property> - </widget> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/src/plugins/fakevim/fakevimplugin.cpp b/src/plugins/fakevim/fakevimplugin.cpp index 20b3b082a5..97e1cfffea 100644 --- a/src/plugins/fakevim/fakevimplugin.cpp +++ b/src/plugins/fakevim/fakevimplugin.cpp @@ -75,6 +75,7 @@ namespace FakeVim { namespace Constants { const char * const INSTALL_HANDLER = "FakeVim.InstallHandler"; +const char * const MINI_BUFFER = "FakeVim.MiniBuffer"; const char * const INSTALL_KEY = "Alt+V,Alt+V"; } // namespace Constants @@ -89,7 +90,7 @@ const char * const INSTALL_KEY = "Alt+V,Alt+V"; FakeVimPlugin::FakeVimPlugin() { - m_pm = 0; + m_core = 0; m_handler = 0; } @@ -109,12 +110,10 @@ bool FakeVimPlugin::initialize(const QStringList &arguments, QString *error_mess m_handler = new FakeVimHandler; - m_pm = ExtensionSystem::PluginManager::instance(); + m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>(); + QTC_ASSERT(m_core, return false); - ICore *core = m_pm->getObject<Core::ICore>(); - QTC_ASSERT(core, return false); - - Core::ActionManagerInterface *actionManager = core->actionManager(); + Core::ActionManagerInterface *actionManager = m_core->actionManager(); QTC_ASSERT(actionManager, return false); QList<int> globalcontext; @@ -143,44 +142,33 @@ void FakeVimPlugin::extensionsInitialized() void FakeVimPlugin::installHandler() { - ICore *core = m_pm->getObject<Core::ICore>(); - if (!core || !core->editorManager()) + if (!m_core || !m_core->editorManager()) return; - Core::IEditor *editor = core->editorManager()->currentEditor(); + Core::IEditor *editor = m_core->editorManager()->currentEditor(); ITextEditor *textEditor = qobject_cast<ITextEditor*>(editor); if (!textEditor) return; - QWidget *widget = textEditor->widget(); - QPlainTextEdit *plainTextEdit = qobject_cast<QPlainTextEdit *>(widget); - if (!plainTextEdit) - return; - plainTextEdit->removeEventFilter(m_handler); - plainTextEdit->installEventFilter(m_handler); - QFont font = plainTextEdit->font(); - //font.setFamily("Monospace"); - m_savedCursorWidth = plainTextEdit->cursorWidth(); - plainTextEdit->setCursorWidth(QFontMetrics(font).width(QChar('x'))); - - //QMainWindow mw; connect(m_handler, SIGNAL(commandBufferChanged(QString)), this, SLOT(showCommandBuffer(QString))); connect(m_handler, SIGNAL(quitRequested(QWidget *)), this, SLOT(removeHandler(QWidget *))); + + m_handler->addWidget(textEditor->widget()); } void FakeVimPlugin::removeHandler(QWidget *widget) { - widget->removeEventFilter(m_handler); - QPlainTextEdit *plainTextEdit = qobject_cast<QPlainTextEdit *>(widget); - if (!plainTextEdit) - return; - plainTextEdit->setCursorWidth(m_savedCursorWidth); + m_handler->removeWidget(widget); + Core::EditorManager::instance()->hideEditorInfoBar( + QLatin1String(Constants::MINI_BUFFER)); } void FakeVimPlugin::showCommandBuffer(const QString &contents) { - //qDebug() << "CMD: " << contents; + Core::EditorManager::instance()->showEditorInfoBar( + QLatin1String(Constants::MINI_BUFFER), contents, + tr("Quit FakeVim"), m_handler, SLOT(quit())); } diff --git a/src/plugins/fakevim/fakevimplugin.h b/src/plugins/fakevim/fakevimplugin.h index 6561e871b0..9025affcec 100644 --- a/src/plugins/fakevim/fakevimplugin.h +++ b/src/plugins/fakevim/fakevimplugin.h @@ -44,8 +44,21 @@ class QCursor; class QAbstractItemView; QT_END_NAMESPACE -namespace Core { class IEditor; } -namespace TextEditor { class ITextEditor; } + +namespace Core { + +class ICore; +class IEditor; + +} // namespace Core + + +namespace TextEditor { + +class ITextEditor; + +} // namespace TextEditor + namespace FakeVim { namespace Internal { @@ -72,9 +85,8 @@ private slots: private: FakeVimHandler *m_handler; - ExtensionSystem::PluginManager *m_pm; QAction *m_installHandlerAction; - int m_savedCursorWidth; + Core::ICore *m_core; }; } // namespace Internal diff --git a/src/plugins/fakevim/handler.cpp b/src/plugins/fakevim/handler.cpp index fd8734f211..2fba751042 100644 --- a/src/plugins/fakevim/handler.cpp +++ b/src/plugins/fakevim/handler.cpp @@ -46,19 +46,21 @@ #include <QtGui/QScrollBar> #include <QtGui/QTextBlock> #include <QtGui/QTextCursor> +#include <QtGui/QTextDocumentFragment> #include <QtGui/QTextEdit> using namespace FakeVim::Internal; -#define StartOfLine QTextCursor::StartOfLine -#define EndOfLine QTextCursor::EndOfLine -#define MoveAnchor QTextCursor::MoveAnchor -#define KeepAnchor QTextCursor::KeepAnchor -#define Up QTextCursor::Up -#define Down QTextCursor::Down -#define Right QTextCursor::Right -#define Left QTextCursor::Left +#define StartOfLine QTextCursor::StartOfLine +#define EndOfLine QTextCursor::EndOfLine +#define MoveAnchor QTextCursor::MoveAnchor +#define KeepAnchor QTextCursor::KeepAnchor +#define Up QTextCursor::Up +#define Down QTextCursor::Down +#define Right QTextCursor::Right +#define Left QTextCursor::Left +#define EndOfDocument QTextCursor::End /////////////////////////////////////////////////////////////////////// @@ -68,7 +70,6 @@ using namespace FakeVim::Internal; /////////////////////////////////////////////////////////////////////// #define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s) -#define THE_EDITOR (m_textedit ? (QWidget*)m_textedit : (QWidget*)m_plaintextedit) const int ParagraphSeparator = 0x00002029; @@ -78,7 +79,9 @@ enum Mode { InsertMode, CommandMode, - ExMode + ExMode, + SearchForwardMode, + SearchBackwardMode, }; enum SubMode @@ -87,7 +90,7 @@ enum SubMode RegisterSubMode, ChangeSubMode, DeleteSubMode, - ZSubMode + ZSubMode, }; enum SubSubMode @@ -99,16 +102,46 @@ enum SubSubMode TickSubSubMode // used for ' }; +enum VisualMode +{ + NoVisualMode, + VisualCharMode, + VisualLineMode, + VisualBlockMode, +}; + static const QString ConfigStartOfLine = "startofline"; static const QString ConfigOn = "on"; +struct EditOperation +{ + EditOperation() : m_position(-1), m_itemCount(0) {} + int m_position; + int m_itemCount; // used to combine several operations + QString m_from; + QString m_to; +}; + +QDebug &operator<<(QDebug &ts, const EditOperation &op) +{ + if (op.m_itemCount > 0) { + ts << "EDIT BLOCK WITH" << op.m_itemCount << "ITEMS"; + } else { + ts << "EDIT AT " << op.m_position + << " FROM " << op.m_from << " TO " << op.m_to; + } + return ts; +} + class FakeVimHandler::Private { public: Private(FakeVimHandler *parent); bool eventFilter(QObject *ob, QEvent *ev); + void handleExCommand(const QString &cmd); +private: static int shift(int key) { return key + 32; } static int control(int key) { return key + 256; } @@ -117,11 +150,9 @@ public: void handleInsertMode(int key, const QString &text); void handleCommandMode(int key, const QString &text); void handleRegisterMode(int key, const QString &text); - void handleExMode(int key, const QString &text); - void finishMovement(); - void updateMiniBuffer(); + void handleMiniBufferModes(int key, const QString &text); + void finishMovement(const QString &text = QString()); void search(const QString &needle, bool forward); - void showMessage(const QString &msg); int mvCount() const { return m_mvcount.isEmpty() ? 1 : m_mvcount.toInt(); } int opCount() const { return m_opcount.isEmpty() ? 1 : m_opcount.toInt(); } @@ -131,47 +162,57 @@ public: bool atEol() const { return m_tc.atBlockEnd() && m_tc.block().length()>1; } int lastPositionInDocument() const; - - // all zero-based counting - int cursorLineOnScreen() const; - int linesOnScreen() const; - int columnsOnScreen() const; - int cursorLineInDocument() const; - int cursorColumnInDocument() const; + int positionForLine(int line) const; // 1 based line, 0 based pos + int lineForPosition(int pos) const; // 1 based line, 0 based pos + + // all zero-based counting + int cursorLineOnScreen() const; + int linesOnScreen() const; + int columnsOnScreen() const; + int cursorLineInDocument() const; + int cursorColumnInDocument() const; int linesInDocument() const; - void scrollToLineInDocument(int line); + void scrollToLineInDocument(int line); void moveToFirstNonBlankOnLine(); void moveToNextWord(bool simple); void moveToWordBoundary(bool simple, bool forward); void handleFfTt(int key); - void handleCommand(const QString &cmd); // helper function for handleCommand. return 1 based line index. int readLineCode(QString &cmd); + QTextCursor selectRange(int beginLine, int endLine); +public: + void enterInsertMode(); + void enterCommandMode(); + void showMessage(const QString &msg); + void updateMiniBuffer(); + void updateSelection(); + void quit(); + +public: + QTextEdit *m_textedit; + QPlainTextEdit *m_plaintextedit; + +private: FakeVimHandler *q; Mode m_mode; SubMode m_submode; SubSubMode m_subsubmode; int m_subsubdata; QString m_input; - QTextEdit *m_textedit; - QPlainTextEdit *m_plaintextedit; QTextCursor m_tc; QHash<int, QString> m_registers; int m_register; QString m_mvcount; QString m_opcount; - QStack<QString> m_undoStack; - QStack<QString> m_redoStack; - bool m_fakeEnd; - bool isSearchCommand() const - { return m_commandCode == '?' || m_commandCode == '/'; } - int m_commandCode; // ?, /, : ... + QWidget *editor() const; + bool isSearchMode() const + { return m_mode == SearchForwardMode || m_mode == SearchBackwardMode; } int m_gflag; // whether current command started with 'g' QString m_commandBuffer; @@ -181,15 +222,33 @@ public: bool m_lastSearchForward; QString m_lastInsertion; - // History for '/' + // undo handling + void recordInsert(int position, const QString &data); + void recordRemove(int position, const QString &data); + void recordRemove(int position, int length); + void undo(); + void redo(); + QStack<EditOperation> m_undoStack; + QStack<EditOperation> m_redoStack; + + // extra data for '.' + QString m_dotCount; + QString m_dotCommand; + + // history for '/' QString lastSearchString() const; QStringList m_searchHistory; int m_searchHistoryIndex; - // History for ':' + // history for ':' QStringList m_commandHistory; int m_commandHistoryIndex; + // visual line mode + void enterVisualMode(VisualMode visualMode); + void leaveVisualMode(); + VisualMode m_visualMode; + // marks as lines QHash<int, int> m_marks; @@ -204,13 +263,13 @@ FakeVimHandler::Private::Private(FakeVimHandler *parent) m_mode = CommandMode; m_submode = NoSubMode; m_subsubmode = NoSubSubMode; - m_commandCode = 0; m_fakeEnd = false; m_lastSearchForward = true; m_register = '"'; m_gflag = false; m_textedit = 0; m_plaintextedit = 0; + m_visualMode = NoVisualMode; m_config[ConfigStartOfLine] = ConfigOn; } @@ -254,22 +313,30 @@ bool FakeVimHandler::Private::eventFilter(QObject *ob, QEvent *ev) void FakeVimHandler::Private::handleKey(int key, const QString &text) { + //qDebug() << "KEY: " << key << text << "POS: " << m_tc.position(); + //qDebug() << "\nUNDO: " << m_undoStack << "\nREDO: " << m_redoStack; if (m_mode == InsertMode) handleInsertMode(key, text); else if (m_mode == CommandMode) handleCommandMode(key, text); - else if (m_mode == ExMode) - handleExMode(key, text); + else if (m_mode == ExMode || m_mode == SearchForwardMode + || m_mode == SearchBackwardMode) + handleMiniBufferModes(key, text); } -void FakeVimHandler::Private::finishMovement() +void FakeVimHandler::Private::finishMovement(const QString &dotCommand) { if (m_submode == ChangeSubMode) { + if (!dotCommand.isEmpty()) + m_dotCommand = "c" + dotCommand; m_registers[m_register] = m_tc.selectedText(); m_tc.removeSelectedText(); m_mode = InsertMode; m_submode = NoSubMode; } else if (m_submode == DeleteSubMode) { + if (!dotCommand.isEmpty()) + m_dotCommand = "d" + dotCommand; + recordRemove(qMin(m_tc.position(), m_tc.anchor()), m_tc.selectedText()); m_registers[m_register] = m_tc.selectedText(); m_tc.removeSelectedText(); m_submode = NoSubMode; @@ -281,18 +348,81 @@ void FakeVimHandler::Private::finishMovement() m_gflag = false; m_register = '"'; m_tc.clearSelection(); + + updateSelection(); updateMiniBuffer(); } +void FakeVimHandler::Private::updateSelection() +{ + QList<QTextEdit::ExtraSelection> selections; + if (m_visualMode != NoVisualMode) { + QTextEdit::ExtraSelection sel; + sel.cursor = m_tc; + sel.format = m_tc.blockCharFormat(); + sel.format.setFontWeight(QFont::Bold); + sel.format.setFontUnderline(true); + int cursorPos = m_tc.position(); + int anchorPos = m_marks['<']; + //qDebug() << "POS: " << cursorPos << " ANCHOR: " << anchorPos; + if (m_visualMode == VisualCharMode) { + sel.cursor.setPosition(anchorPos, KeepAnchor); + selections.append(sel); + } else if (m_visualMode == VisualLineMode) { + sel.cursor.setPosition(qMin(cursorPos, anchorPos), MoveAnchor); + sel.cursor.movePosition(StartOfLine, MoveAnchor); + sel.cursor.setPosition(qMax(cursorPos, anchorPos), KeepAnchor); + sel.cursor.movePosition(EndOfLine, KeepAnchor); + selections.append(sel); + } else if (m_visualMode == VisualBlockMode) { + QTextCursor tc = m_tc; + tc.setPosition(anchorPos); + tc.movePosition(StartOfLine, MoveAnchor); + QTextBlock anchorBlock = tc.block(); + QTextBlock cursorBlock = m_tc.block(); + int anchorColumn = anchorPos - anchorBlock.position(); + int cursorColumn = cursorPos - cursorBlock.position(); + int startColumn = qMin(anchorColumn, cursorColumn); + int endColumn = qMax(anchorColumn, cursorColumn); + int endPos = cursorBlock.position(); + while (tc.position() <= endPos) { + if (startColumn < tc.block().length() - 1) { + int last = qMin(tc.block().length() - 1, endColumn); + int len = last - startColumn + 1; + sel.cursor = tc; + sel.cursor.movePosition(Right, MoveAnchor, startColumn); + sel.cursor.movePosition(Right, KeepAnchor, len); + selections.append(sel); + } + tc.movePosition(Down, MoveAnchor, 1); + } + } + } + EDITOR(setExtraSelections(selections)); +} + void FakeVimHandler::Private::updateMiniBuffer() { - if (m_tc.isNull()) - return; QString msg; - if (m_currentMessage.isEmpty()) { - msg = QChar(m_commandCode ? m_commandCode : ' '); - for (int i = 0; i != m_commandBuffer.size(); ++i) { - QChar c = m_commandBuffer.at(i); + if (!m_currentMessage.isEmpty()) { + msg = m_currentMessage; + m_currentMessage.clear(); + } else if (m_visualMode == VisualCharMode) { + msg = "-- VISUAL --"; + } else if (m_visualMode == VisualLineMode) { + msg = "-- VISUAL LINE --"; + } else if (m_visualMode == VisualBlockMode) { + msg = "-- VISUAL BLOCK --"; + } else if (m_mode == InsertMode) { + msg = "-- INSERT --"; + } else { + if (m_mode == SearchForwardMode) + msg += '/'; + else if (m_mode == SearchBackwardMode) + msg += '?'; + else if (m_mode == ExMode) + msg += ':'; + foreach (QChar c, m_commandBuffer) { if (c.unicode() < 32) { msg += '^'; msg += QChar(c.unicode() + 64); @@ -300,20 +430,22 @@ void FakeVimHandler::Private::updateMiniBuffer() msg += c; } } - } else { - msg = m_currentMessage; - m_currentMessage.clear(); } + emit q->commandBufferChanged(msg); + + int linesInDoc = linesInDocument(); int l = cursorLineInDocument(); - int w = columnsOnScreen(); - msg += QString(w, ' '); - msg = msg.left(w - 20); + QString status; QString pos = tr("%1,%2").arg(l + 1).arg(cursorColumnInDocument() + 1); - msg += tr("%1").arg(pos, -12); + status += tr("%1").arg(pos, -10); // FIXME: physical "-" logical - msg += tr("%1").arg(l * 100 / (m_tc.document()->blockCount() - 1), 4); - msg += '%'; - emit q->commandBufferChanged(msg); + if (linesInDoc != 0) { + status += tr("%1").arg(l * 100 / linesInDoc, 4); + status += "%"; + } else { + status += "All"; + } + emit q->statusDataChanged(status); } void FakeVimHandler::Private::showMessage(const QString &msg) @@ -334,16 +466,16 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) m_tc.movePosition(StartOfLine, MoveAnchor); m_tc.movePosition(Down, KeepAnchor, count()); m_registers[m_register] = m_tc.selectedText(); - finishMovement(); + finishMovement("c"); } else if (m_submode == DeleteSubMode && key == 'd') { m_tc.movePosition(StartOfLine, MoveAnchor); m_tc.movePosition(Down, KeepAnchor, count()); m_registers[m_register] = m_tc.selectedText(); - finishMovement(); + finishMovement("d"); } else if (m_submode == ZSubMode) { if (key == Key_Return) { // cursor line to top of window, cursor on first non-blank - scrollToLineInDocument(cursorLineInDocument()); + scrollToLineInDocument(cursorLineInDocument()); moveToFirstNonBlankOnLine(); finishMovement(); } else { @@ -353,14 +485,14 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) } else if (m_subsubmode == FtSubSubMode) { handleFfTt(key); m_subsubmode = NoSubSubMode; - finishMovement(); + finishMovement(QString(QChar(m_subsubdata)) + QChar(key)); } else if (m_subsubmode == MarkSubSubMode) { m_marks[key] = m_tc.position(); m_subsubmode = NoSubSubMode; } else if (m_subsubmode == BackTickSubSubMode || m_subsubmode == TickSubSubMode) { if (m_marks.contains(key)) { - m_tc.setPosition(m_marks[key]); + m_tc.setPosition(m_marks[key], MoveAnchor); if (m_subsubmode == TickSubSubMode) moveToFirstNonBlankOnLine(); finishMovement(); @@ -375,16 +507,21 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) } else { m_mvcount.append(QChar(key)); } - } else if (key == ':' || key == '/' || key == '?') { - m_commandCode = key; + } else if (key == ':') { m_mode = ExMode; - if (isSearchCommand()) { - m_searchHistory.append(QString()); - m_searchHistoryIndex = m_searchHistory.size() - 1; - } else { - m_commandHistory.append(QString()); - m_commandHistoryIndex = m_commandHistory.size() - 1; + m_commandBuffer.clear(); + if (m_visualMode != NoVisualMode) { + m_commandBuffer = "'<,'>"; + leaveVisualMode(); } + m_commandHistory.append(QString()); + m_commandHistoryIndex = m_commandHistory.size() - 1; + updateMiniBuffer(); + } else if (key == '/' || key == '?') { + m_mode = (key == '/') ? SearchForwardMode : SearchBackwardMode; + m_commandBuffer.clear(); + m_searchHistory.append(QString()); + m_searchHistoryIndex = m_searchHistory.size() - 1; updateMiniBuffer(); } else if (key == '`') { m_subsubmode = BackTickSubSubMode; @@ -405,14 +542,18 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) } else if (key == '$' || key == Key_End) { m_tc.movePosition(EndOfLine, KeepAnchor); finishMovement(); + } else if (key == '.') { + qDebug() << "REPEATING" << m_dotCommand; + for (int i = count(); --i >= 0; ) + foreach (QChar c, m_dotCommand) + handleKey(c.unicode(), QString(c)); } else if (key == 'a') { m_mode = InsertMode; m_lastInsertion.clear(); - m_tc.beginEditBlock(); m_tc.movePosition(Right, MoveAnchor, 1); + updateMiniBuffer(); } else if (key == 'A') { m_mode = InsertMode; - m_tc.beginEditBlock(); m_tc.movePosition(EndOfLine, MoveAnchor); m_lastInsertion.clear(); } else if (key == 'b') { @@ -423,18 +564,22 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) finishMovement(); } else if (key == 'c') { m_submode = ChangeSubMode; - m_tc.beginEditBlock(); } else if (key == 'C') { m_submode = ChangeSubMode; - m_tc.beginEditBlock(); m_tc.movePosition(EndOfLine, KeepAnchor); finishMovement(); - } else if (key == 'd') { + } else if (key == 'd' && m_visualMode == NoVisualMode) { if (atEol()) m_tc.movePosition(Left, MoveAnchor, 1); m_opcount = m_mvcount; m_mvcount.clear(); m_submode = DeleteSubMode; + } else if (key == 'd') { + leaveVisualMode(); + int beginLine = lineForPosition(m_marks['<']); + int endLine = lineForPosition(m_marks['>']); + m_tc = selectRange(beginLine, endLine); + m_tc.removeSelectedText(); } else if (key == 'D') { m_submode = DeleteSubMode; m_tc.movePosition(Down, KeepAnchor, qMax(count() - 1, 0)); @@ -453,7 +598,7 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) m_gflag = true; } else if (key == 'G') { int n = m_mvcount.isEmpty() ? linesInDocument() : count(); - m_tc.setPosition(m_tc.document()->findBlockByNumber(n - 1).position()); + m_tc.setPosition(positionForLine(n), MoveAnchor); if (m_config.contains(ConfigStartOfLine)) moveToFirstNonBlankOnLine(); finishMovement(); @@ -469,23 +614,19 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) moveToFirstNonBlankOnLine(); finishMovement(); } else if (key == 'i') { - m_mode = InsertMode; - m_tc.beginEditBlock(); - m_lastInsertion.clear(); + enterInsertMode(); + updateMiniBuffer(); } else if (key == 'I') { - m_mode = InsertMode; + enterInsertMode(); if (m_gflag) m_tc.movePosition(StartOfLine, KeepAnchor); else moveToFirstNonBlankOnLine(); - m_tc.clearSelection(); - m_tc.beginEditBlock(); - m_lastInsertion.clear(); } else if (key == 'j' || key == Key_Down) { m_tc.movePosition(Down, KeepAnchor, count()); finishMovement(); } else if (key == 'J') { - m_tc.beginEditBlock(); + EditOperation op; if (m_submode == NoSubMode) { for (int i = qMax(count(), 2) - 1; --i >= 0; ) { m_tc.movePosition(EndOfLine); @@ -496,7 +637,6 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) if (!m_gflag) m_tc.movePosition(Left, MoveAnchor, 1); } - m_tc.endEditBlock(); } else if (key == 'k' || key == Key_Up) { m_tc.movePosition(Up, KeepAnchor, count()); finishMovement(); @@ -519,15 +659,11 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) } else if (key == 'N') { search(lastSearchString(), !m_lastSearchForward); } else if (key == 'o') { - m_mode = InsertMode; - m_lastInsertion.clear(); - //m_tc.beginEditBlock(); // FIXME: unusable due to drawing errors + enterInsertMode(); m_tc.movePosition(EndOfLine, MoveAnchor); m_tc.insertText("\n"); } else if (key == 'O') { - m_mode = InsertMode; - m_lastInsertion.clear(); - //m_tc.beginEditBlock(); // FIXME: unusable due to drawing errors + enterInsertMode(); m_tc.movePosition(StartOfLine, MoveAnchor); m_tc.movePosition(Left, MoveAnchor, 1); m_tc.insertText("\n"); @@ -545,29 +681,33 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) m_tc.movePosition(Left); } } else if (key == control('r')) { - EDITOR(redo()); + redo(); } else if (key == 's') { m_submode = ChangeSubMode; - m_tc.beginEditBlock(); m_tc.movePosition(Right, KeepAnchor, qMin(count(), rightDist())); - finishMovement(); } else if (key == 't' || key == 'T') { m_subsubmode = FtSubSubMode; m_subsubdata = key; } else if (key == 'u') { - EDITOR(undo()); + undo(); + } else if (key == 'v') { + enterVisualMode(VisualCharMode); + } else if (key == 'V') { + enterVisualMode(VisualLineMode); + } else if (key == control('v')) { + enterVisualMode(VisualBlockMode); } else if (key == 'w') { moveToNextWord(false); - finishMovement(); + finishMovement("w"); } else if (key == 'W') { moveToNextWord(true); - finishMovement(); + finishMovement("W"); } else if (key == 'x') { // = "dl" if (atEol()) m_tc.movePosition(Left, MoveAnchor, 1); m_submode = DeleteSubMode; m_tc.movePosition(Right, KeepAnchor, qMin(count(), rightDist())); - finishMovement(); + finishMovement("l"); } else if (key == 'X') { if (leftDist() > 0) { m_tc.movePosition(Left, KeepAnchor, qMin(count(), leftDist())); @@ -596,7 +736,8 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) } else if (key == Key_Delete) { m_tc.deleteChar(); } else if (key == Key_Escape) { - // harmless + if (m_visualMode != NoVisualMode) + leaveVisualMode(); } else { qDebug() << "Ignored" << key << text; } @@ -605,11 +746,16 @@ void FakeVimHandler::Private::handleCommandMode(int key, const QString &text) void FakeVimHandler::Private::handleInsertMode(int key, const QString &text) { if (key == Key_Escape) { - for (int i = 1; i < count(); ++i) + // start with '1', as one instance was already physically inserted + // while typing + QString data = m_lastInsertion; + for (int i = 1; i < count(); ++i) { m_tc.insertText(m_lastInsertion); + data += m_lastInsertion; + } + recordInsert(m_tc.position() - m_lastInsertion.size(), data); m_tc.movePosition(Left, MoveAnchor, qMin(1, leftDist())); - m_mode = CommandMode; - m_tc.endEditBlock(); + enterCommandMode(); } else if (key == Key_Left) { m_tc.movePosition(Left, MoveAnchor, 1); m_lastInsertion.clear(); @@ -624,7 +770,7 @@ void FakeVimHandler::Private::handleInsertMode(int key, const QString &text) m_lastInsertion.clear(); } else if (key == Key_Return) { m_tc.insertBlock(); - m_lastInsertion.clear(); + m_lastInsertion += "\n"; } else if (key == Key_Backspace) { m_tc.deletePreviousChar(); m_lastInsertion = m_lastInsertion.left(m_lastInsertion.size() - 1); @@ -644,45 +790,40 @@ void FakeVimHandler::Private::handleInsertMode(int key, const QString &text) } else { m_lastInsertion.append(text); m_tc.insertText(text); - } + } + updateMiniBuffer(); } -void FakeVimHandler::Private::handleExMode(int key, const QString &text) +void FakeVimHandler::Private::handleMiniBufferModes(int key, const QString &text) { Q_UNUSED(text) if (key == Key_Escape) { m_commandBuffer.clear(); - m_commandCode = 0; - m_mode = CommandMode; + enterCommandMode(); updateMiniBuffer(); } else if (key == Key_Backspace) { if (m_commandBuffer.isEmpty()) - m_mode = CommandMode; + enterCommandMode(); else m_commandBuffer.chop(1); updateMiniBuffer(); - } else if (key == Key_Return && m_commandCode == ':') { + } else if (key == Key_Return && m_mode == ExMode) { if (!m_commandBuffer.isEmpty()) { m_commandHistory.takeLast(); m_commandHistory.append(m_commandBuffer); - handleCommand(m_commandBuffer); - m_commandBuffer.clear(); - m_commandCode = 0; + handleExCommand(m_commandBuffer); } - m_mode = CommandMode; - } else if (key == Key_Return && isSearchCommand()) { + } else if (key == Key_Return && isSearchMode()) { if (!m_commandBuffer.isEmpty()) { m_searchHistory.takeLast(); m_searchHistory.append(m_commandBuffer); - m_lastSearchForward = (m_commandCode == '/'); + m_lastSearchForward = (m_mode == SearchForwardMode); search(lastSearchString(), m_lastSearchForward); - m_commandBuffer.clear(); - m_commandCode = 0; } - m_mode = CommandMode; + enterCommandMode(); updateMiniBuffer(); - } else if (key == Key_Up && isSearchCommand()) { + } else if (key == Key_Up && isSearchMode()) { // FIXME: This and the three cases below are wrong as vim // takes only matching entires in the history into account. if (m_searchHistoryIndex > 0) { @@ -690,19 +831,19 @@ void FakeVimHandler::Private::handleExMode(int key, const QString &text) m_commandBuffer = m_searchHistory.at(m_searchHistoryIndex); updateMiniBuffer(); } - } else if (key == Key_Up && m_commandCode == ':') { + } else if (key == Key_Up && m_mode == ExMode) { if (m_commandHistoryIndex > 0) { --m_commandHistoryIndex; m_commandBuffer = m_commandHistory.at(m_commandHistoryIndex); updateMiniBuffer(); } - } else if (key == Key_Down && isSearchCommand()) { + } else if (key == Key_Down && isSearchMode()) { if (m_searchHistoryIndex < m_searchHistory.size() - 1) { ++m_searchHistoryIndex; m_commandBuffer = m_searchHistory.at(m_searchHistoryIndex); updateMiniBuffer(); } - } else if (key == Key_Down && m_commandCode == ':') { + } else if (key == Key_Down && m_mode == ExMode) { if (m_commandHistoryIndex < m_commandHistory.size() - 1) { ++m_commandHistoryIndex; m_commandBuffer = m_commandHistory.at(m_commandHistoryIndex); @@ -737,6 +878,16 @@ int FakeVimHandler::Private::readLineCode(QString &cmd) int n = readLineCode(cmd); return cursorLineInDocument() + 1 + (n == -1 ? 1 : n); } + if (c == '\'' && !cmd.isEmpty()) { + int pos = m_marks.value(cmd.at(0).unicode()); + qDebug() << " MARK: " << cmd.at(0) << pos << lineForPosition(pos); + if (!pos) { + showMessage(tr("E20: Mark '%1' not set").arg(cmd.at(0))); + return -1; + } + cmd = cmd.mid(1); + return lineForPosition(pos); + } if (c.isDigit()) { int n = c.unicode() - '0'; while (!cmd.isEmpty()) { @@ -754,14 +905,27 @@ int FakeVimHandler::Private::readLineCode(QString &cmd) return -1; } -void FakeVimHandler::Private::handleCommand(const QString &cmd0) +QTextCursor FakeVimHandler::Private::selectRange(int beginLine, int endLine) +{ + QTextCursor tc = m_tc; + tc.setPosition(positionForLine(beginLine), MoveAnchor); + if (endLine == linesInDocument()) { + tc.setPosition(positionForLine(endLine), KeepAnchor); + tc.movePosition(EndOfLine, KeepAnchor); + } else { + tc.setPosition(positionForLine(endLine + 1), KeepAnchor); + } + return tc; +} + +void FakeVimHandler::Private::handleExCommand(const QString &cmd0) { QString cmd = cmd0; if (cmd.startsWith("%")) cmd = "1,$" + cmd.mid(1); - int beginLine = 0; - int endLine = linesInDocument(); + int beginLine = -1; + int endLine = -1; int line = readLineCode(cmd); if (line != -1) @@ -774,44 +938,68 @@ void FakeVimHandler::Private::handleCommand(const QString &cmd0) endLine = line; } - //qDebug() << "RANGE: " << beginLine << endLine << cmd << cmd0; + qDebug() << "RANGE: " << beginLine << endLine << cmd << cmd0; static QRegExp reWrite("^w!?( (.*))?$"); + static QRegExp reDelete("^d( (.*))?$"); if (cmd.isEmpty()) { - m_tc.setPosition(m_tc.block().document() - ->findBlockByNumber(beginLine - 1).position()); - showMessage(QString()); - } else if (cmd == "q!" || cmd == "q") { - q->quitRequested(THE_EDITOR); + m_tc.setPosition(positionForLine(beginLine)); showMessage(QString()); - } else if (reWrite.indexIn(cmd) != -1) { + } else if (cmd == "q!" || cmd == "q") { // :q + quit(); + } else if (reDelete.indexIn(cmd) != -1) { // :d + if (beginLine == -1) + beginLine = cursorLineInDocument(); + if (endLine == -1) + endLine = cursorLineInDocument(); + QTextCursor tc = selectRange(beginLine, endLine); + QString reg = reDelete.cap(2); + if (!reg.isEmpty()) + m_registers[reg.at(0).unicode()] = tc.selection().toPlainText(); + tc.removeSelectedText(); + } else if (reWrite.indexIn(cmd) != -1) { // :w + enterCommandMode(); + bool noArgs = (beginLine == -1); + if (beginLine == -1) + beginLine = 0; + if (endLine == -1) + endLine = linesInDocument(); + qDebug() << "LINES: " << beginLine << endLine; bool forced = cmd.startsWith("w!"); QString fileName = reWrite.cap(2); if (fileName.isEmpty()) fileName = m_currentFileName; QFile file(fileName); bool exists = file.exists(); - if (exists && !forced) { - showMessage("E13: File exists (add ! to override)"); - } else { - file.open(QIODevice::ReadWrite); - QTextStream ts(&file); - ts << EDITOR(toPlainText()); + if (exists && !forced && !noArgs) { + showMessage(tr("File '%1' exists (add ! to override)").arg(fileName)); + } else if (file.open(QIODevice::ReadWrite)) { + QTextCursor tc = selectRange(beginLine, endLine); + qDebug() << "ANCHOR: " << tc.position() << tc.anchor() + << tc.selection().toPlainText(); + { QTextStream ts(&file); ts << tc.selection().toPlainText(); } file.close(); - file.open(QIODevice::ReadWrite); + file.open(QIODevice::ReadOnly); QByteArray ba = file.readAll(); - showMessage(tr("\"%1\" %2 %3L, %4C written") + m_commandBuffer = QString("\"%1\" %2 %3L, %4C written") .arg(fileName).arg(exists ? " " : " [New] ") - .arg(ba.count('\n')).arg(ba.size())); + .arg(ba.count('\n')).arg(ba.size()); + updateMiniBuffer(); + } else { + showMessage(tr("Cannot open file '%1' for reading").arg(fileName)); } - } else if (cmd.startsWith("r ")) { + } else if (cmd.startsWith("r ")) { // :r m_currentFileName = cmd.mid(2); QFile file(m_currentFileName); file.open(QIODevice::ReadOnly); QTextStream ts(&file); - EDITOR(setPlainText(ts.readAll())); - showMessage(QString()); + QString data = ts.readAll(); + EDITOR(setPlainText(data)); + m_commandBuffer = QString("\"%1\" %2L, %3C") + .arg(m_currentFileName).arg(data.count('\n')).arg(data.size()); + enterCommandMode(); + updateMiniBuffer(); } else { showMessage("E492: Not an editor command: " + cmd0); } @@ -961,30 +1149,37 @@ void FakeVimHandler::Private::moveToNextWord(bool simple) int FakeVimHandler::Private::cursorLineOnScreen() const { - QRect rect = EDITOR(cursorRect()); - return rect.y() / rect.height(); + if (!editor()) + return 0; + QRect rect = EDITOR(cursorRect()); + return rect.y() / rect.height(); } int FakeVimHandler::Private::linesOnScreen() const { - QRect rect = EDITOR(cursorRect()); - return EDITOR(height()) / rect.height(); + if (!editor()) + return 1; + QRect rect = EDITOR(cursorRect()); + return EDITOR(height()) / rect.height(); } int FakeVimHandler::Private::columnsOnScreen() const { - QRect rect = EDITOR(cursorRect()); - return EDITOR(width()) / rect.width(); + if (!editor()) + return 1; + QRect rect = EDITOR(cursorRect()); + // qDebug() << "WID: " << EDITOR(width()) << "RECT: " << rect; + return EDITOR(width()) / rect.width(); } int FakeVimHandler::Private::cursorLineInDocument() const { - return m_tc.block().blockNumber(); + return m_tc.block().blockNumber(); } int FakeVimHandler::Private::cursorColumnInDocument() const { - return m_tc.position() - m_tc.block().position(); + return m_tc.position() - m_tc.block().position(); } int FakeVimHandler::Private::linesInDocument() const @@ -994,9 +1189,9 @@ int FakeVimHandler::Private::linesInDocument() const void FakeVimHandler::Private::scrollToLineInDocument(int line) { - // FIXME: works only for QPlainTextEdit - QScrollBar *scrollBar = EDITOR(verticalScrollBar()); - scrollBar->setValue(line); + // FIXME: works only for QPlainTextEdit + QScrollBar *scrollBar = EDITOR(verticalScrollBar()); + scrollBar->setValue(line); } int FakeVimHandler::Private::lastPositionInDocument() const @@ -1010,6 +1205,141 @@ QString FakeVimHandler::Private::lastSearchString() const return m_searchHistory.empty() ? QString() : m_searchHistory.back(); } +int FakeVimHandler::Private::positionForLine(int line) const +{ + return m_tc.block().document()->findBlockByNumber(line - 1).position(); +} + +int FakeVimHandler::Private::lineForPosition(int pos) const +{ + QTextCursor tc = m_tc; + tc.setPosition(pos); + return tc.block().blockNumber() + 1; +} + +void FakeVimHandler::Private::enterVisualMode(VisualMode visualMode) +{ + m_visualMode = visualMode; + m_marks['<'] = m_tc.position(); + updateMiniBuffer(); + updateSelection(); +} + +void FakeVimHandler::Private::leaveVisualMode() +{ + m_visualMode = NoVisualMode; + m_marks['>'] = m_tc.position(); + updateMiniBuffer(); + updateSelection(); +} + +QWidget *FakeVimHandler::Private::editor() const +{ + return m_textedit + ? static_cast<QWidget *>(m_textedit) + : static_cast<QWidget *>(m_plaintextedit); +} + +void FakeVimHandler::Private::undo() +{ +#if 0 + EDITOR(undo()); +#else + if (m_undoStack.isEmpty()) + return; + EditOperation op = m_undoStack.pop(); + //qDebug() << "UNDO " << op; + if (op.m_itemCount > 0) { + for (int i = op.m_itemCount; --i >= 0; ) + undo(); + } else { + m_tc.setPosition(op.m_position, MoveAnchor); + if (!op.m_to.isEmpty()) { + m_tc.setPosition(op.m_position + op.m_to.size(), KeepAnchor); + m_tc.deleteChar(); + } + if (!op.m_from.isEmpty()) + m_tc.insertText(op.m_from); + m_tc.setPosition(op.m_position, MoveAnchor); + } + m_redoStack.push(op); +#endif +} + +void FakeVimHandler::Private::redo() +{ +#if 0 + EDITOR(redo()); +#else + if (m_redoStack.isEmpty()) + return; + EditOperation op = m_redoStack.pop(); + //qDebug() << "REDO " << op; + if (op.m_itemCount > 0) { + for (int i = op.m_itemCount; --i >= 0; ) + redo(); + } else { + m_tc.setPosition(op.m_position, MoveAnchor); + if (!op.m_from.isEmpty()) { + m_tc.setPosition(op.m_position + op.m_from.size(), KeepAnchor); + m_tc.deleteChar(); + } + if (!op.m_to.isEmpty()) + m_tc.insertText(op.m_to); + m_tc.setPosition(op.m_position, MoveAnchor); + } + m_undoStack.push(op); +#endif +} + +void FakeVimHandler::Private::recordInsert(int position, const QString &data) +{ + EditOperation op; + op.m_position = position; + op.m_to = data; + m_undoStack.push(op); + m_redoStack.clear(); +} + +void FakeVimHandler::Private::recordRemove(int position, int length) +{ + QTextCursor tc = m_tc; + tc.setPosition(position, MoveAnchor); + tc.setPosition(position + length, KeepAnchor); + recordRemove(position, tc.selection().toPlainText()); +} + +void FakeVimHandler::Private::recordRemove(int position, const QString &data) +{ + EditOperation op; + op.m_position = position; + op.m_from = data; + m_undoStack.push(op); + m_redoStack.clear(); +} + +void FakeVimHandler::Private::enterInsertMode() +{ + EDITOR(setOverwriteMode(false)); + m_mode = InsertMode; + m_lastInsertion.clear(); +} + +void FakeVimHandler::Private::enterCommandMode() +{ + if (editor()) + EDITOR(setOverwriteMode(true)); + m_mode = CommandMode; +} + +void FakeVimHandler::Private::quit() +{ + showMessage(QString()); + EDITOR(setOverwriteMode(false)); + q->quitRequested(editor()); +} + + /////////////////////////////////////////////////////////////////////// // // FakeVimHandler @@ -1035,23 +1365,22 @@ bool FakeVimHandler::eventFilter(QObject *ob, QEvent *ev) void FakeVimHandler::addWidget(QWidget *widget) { widget->installEventFilter(this); - QFont font = widget->font(); - //: -misc-fixed-medium-r-semicondensed--13-120-75-75-c-60-iso8859-1 - //font.setFamily("Misc"); - font.setFamily("Monospace"); - font.setStretch(QFont::SemiCondensed); - widget->setFont(font); + d->enterCommandMode(); if (QTextEdit *ed = qobject_cast<QTextEdit *>(widget)) { - ed->setCursorWidth(QFontMetrics(ed->font()).width(QChar('x'))); + //ed->setCursorWidth(QFontMetrics(ed->font()).width(QChar('x'))); ed->setLineWrapMode(QTextEdit::NoWrap); } else if (QPlainTextEdit *ed = qobject_cast<QPlainTextEdit *>(widget)) { - ed->setCursorWidth(QFontMetrics(ed->font()).width(QChar('x'))); + //ed->setCursorWidth(QFontMetrics(ed->font()).width(QChar('x'))); ed->setLineWrapMode(QPlainTextEdit::NoWrap); } + d->showMessage("vi emulation mode. Hit <Shift+Esc>:q<Return> to quit"); + d->updateMiniBuffer(); } void FakeVimHandler::removeWidget(QWidget *widget) { + d->showMessage(QString()); + d->updateMiniBuffer(); widget->removeEventFilter(this); } @@ -1059,6 +1388,11 @@ void FakeVimHandler::handleCommand(QWidget *widget, const QString &cmd) { d->m_textedit = qobject_cast<QTextEdit *>(widget); d->m_plaintextedit = qobject_cast<QPlainTextEdit *>(widget); - d->handleCommand(cmd); + d->handleExCommand(cmd); } + +void FakeVimHandler::quit() +{ + d->quit(); +} diff --git a/src/plugins/fakevim/handler.h b/src/plugins/fakevim/handler.h index 1ebf9adb8e..fccb9f0f84 100644 --- a/src/plugins/fakevim/handler.h +++ b/src/plugins/fakevim/handler.h @@ -52,16 +52,20 @@ public: FakeVimHandler(QObject *parent = 0); ~FakeVimHandler(); +public slots: // The same handler can be installed on several widgets + // FIXME: good idea? void addWidget(QWidget *widget); void removeWidget(QWidget *widget); // This executes an "ex" style command taking context // information from \p widget; void handleCommand(QWidget *widget, const QString &cmd); + void quit(); signals: void commandBufferChanged(const QString &msg); + void statusDataChanged(const QString &msg); void quitRequested(QWidget *); private: diff --git a/src/plugins/find/currentdocumentfind.cpp b/src/plugins/find/currentdocumentfind.cpp index 26ed8dd049..dd25564a43 100644 --- a/src/plugins/find/currentdocumentfind.cpp +++ b/src/plugins/find/currentdocumentfind.cpp @@ -147,9 +147,11 @@ void CurrentDocumentFind::updateCurrentFindFilter(QWidget *old, QWidget *now) if (!impl) candidate = candidate->parentWidget(); } - if (!impl) + if (!impl || impl == m_currentFind) return; removeFindSupportConnections(); + if (m_currentFind) + m_currentFind->highlightAll(QString(), 0); m_currentWidget = candidate; m_currentFind = impl; if (m_currentFind) { diff --git a/src/plugins/git/branchdialog.cpp b/src/plugins/git/branchdialog.cpp index 8d06c871f9..3eeee2347b 100644 --- a/src/plugins/git/branchdialog.cpp +++ b/src/plugins/git/branchdialog.cpp @@ -58,8 +58,9 @@ bool BranchDialog::init(GitClient *client, const QString &workingDirectory, QStr } m_ui->repositoryFieldLabel->setText(m_repoDirectory); - m_localModel = new BranchModel(client, BranchModel::LocalBranches, this); - m_remoteModel = new BranchModel(client, BranchModel::RemoteBranches, this); + m_localModel = new LocalBranchModel(client, this); + connect(m_localModel, SIGNAL(newBranchCreated(QString)), this, SLOT(slotNewLocalBranchCreated(QString))); + m_remoteModel = new RemoteBranchModel(client, this); if (!m_localModel->refresh(workingDirectory, errorMessage) || !m_remoteModel->refresh(workingDirectory, errorMessage)) return false; @@ -93,13 +94,23 @@ void BranchDialog::slotEnableButtons() const int selectedLocalRow = selectedLocalBranchIndex(); const int currentLocalBranch = m_localModel->currentBranch(); - const bool hasSelection = selectedLocalRow != -1; + const bool hasSelection = selectedLocalRow != -1 && !m_localModel->isNewBranchRow(selectedLocalRow); const bool currentIsNotSelected = hasSelection && selectedLocalRow != currentLocalBranch; m_checkoutButton->setEnabled(currentIsNotSelected); m_deleteButton->setEnabled(currentIsNotSelected); } +void BranchDialog::slotNewLocalBranchCreated(const QString &b) +{ + // Select the newly created branch + const int row = m_localModel->findBranchByName(b); + if (row != -1) { + const QModelIndex index = m_localModel->index(row); + m_ui->localBranchListView->selectionModel()->select(index, QItemSelectionModel::Select); + } +} + bool BranchDialog::ask(const QString &title, const QString &what, bool defaultButton) { return QMessageBox::question(this, title, what, QMessageBox::Yes|QMessageBox::No, diff --git a/src/plugins/git/branchdialog.h b/src/plugins/git/branchdialog.h index 064719b8ff..c803b57e83 100644 --- a/src/plugins/git/branchdialog.h +++ b/src/plugins/git/branchdialog.h @@ -14,7 +14,8 @@ namespace Git { } class GitClient; - class BranchModel; + class LocalBranchModel; + class RemoteBranchModel; /* Branch dialog: Display a list of local branches at the top * and remote branches below. Offers to checkout/delete local @@ -39,6 +40,7 @@ namespace Git { void slotCheckoutSelectedBranch(); void slotDeleteSelectedBranch(); void slotLocalBranchActivated(); + void slotNewLocalBranchCreated(const QString &); private: bool ask(const QString &title, const QString &what, bool defaultButton); @@ -51,8 +53,8 @@ namespace Git { QPushButton *m_checkoutButton; QPushButton *m_deleteButton; - BranchModel *m_localModel; - BranchModel *m_remoteModel; + LocalBranchModel *m_localModel; + RemoteBranchModel *m_remoteModel; QString m_repoDirectory; }; } // namespace Internal diff --git a/src/plugins/git/branchmodel.cpp b/src/plugins/git/branchmodel.cpp index b02d58dbd0..bb8ccf1951 100644 --- a/src/plugins/git/branchmodel.cpp +++ b/src/plugins/git/branchmodel.cpp @@ -2,6 +2,8 @@ #include "gitclient.h" #include <QtCore/QDebug> +#include <QtCore/QRegExp> +#include <QtCore/QTimer> enum { debug = 0 }; @@ -10,7 +12,7 @@ namespace Git { // Parse a branch line: " *name sha description". Return true if it is // the current one -bool BranchModel::Branch::parse(const QString &lineIn, bool *isCurrent) +bool RemoteBranchModel::Branch::parse(const QString &lineIn, bool *isCurrent) { if (debug) qDebug() << Q_FUNC_INFO << lineIn; @@ -28,40 +30,41 @@ bool BranchModel::Branch::parse(const QString &lineIn, bool *isCurrent) return true; } -static inline Qt::ItemFlags typeToModelFlags(BranchModel::Type t) +// ------ RemoteBranchModel +RemoteBranchModel::RemoteBranchModel(GitClient *client, QObject *parent) : + QAbstractListModel(parent), + m_flags(Qt::ItemIsSelectable|Qt::ItemIsEnabled), + m_client(client) { - Qt::ItemFlags rc = Qt::ItemIsSelectable|Qt::ItemIsEnabled; - if (t == BranchModel::LocalBranches) - rc |= Qt::ItemIsUserCheckable; - return rc; } -// --- BranchModel -BranchModel::BranchModel(GitClient *client, Type type, QObject *parent) : - QAbstractListModel(parent), - m_type(type), - m_flags(typeToModelFlags(type)), - m_client(client), - m_currentBranch(-1) +bool RemoteBranchModel::refresh(const QString &workingDirectory, QString *errorMessage) { + int currentBranch; + return refreshBranches(workingDirectory, true, ¤tBranch, errorMessage); } -int BranchModel::currentBranch() const +QString RemoteBranchModel::branchName(int row) const { - return m_currentBranch; + return m_branches.at(row).name; } -QString BranchModel::branchName(int row) const +QString RemoteBranchModel::workingDirectory() const { - return m_branches.at(row).name; + return m_workingDirectory; } -int BranchModel::rowCount(const QModelIndex & /* parent */) const +int RemoteBranchModel::branchCount() const { return m_branches.size(); } -QVariant BranchModel::data(const QModelIndex &index, int role) const +int RemoteBranchModel::rowCount(const QModelIndex & /* parent */) const +{ + return branchCount(); +} + +QVariant RemoteBranchModel::data(const QModelIndex &index, int role) const { const int row = index.row(); switch (role) { @@ -72,36 +75,52 @@ QVariant BranchModel::data(const QModelIndex &index, int role) const m_branches.at(row).toolTip = toolTip(m_branches.at(row).currentSHA); return m_branches.at(row).toolTip; break; - case Qt::CheckStateRole: - if (m_type == RemoteBranches) - return QVariant(); - return row == m_currentBranch ? Qt::Checked : Qt::Unchecked; default: break; } return QVariant(); } -Qt::ItemFlags BranchModel::flags(const QModelIndex & /*index */) const +Qt::ItemFlags RemoteBranchModel::flags(const QModelIndex & /* index */) const { return m_flags; } -bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage) +QString RemoteBranchModel::toolTip(const QString &sha) const +{ + // Show the sha description excluding diff as toolTip + QString output; + QString errorMessage; + if (!m_client->synchronousShow(m_workingDirectory, sha, &output, &errorMessage)) + return errorMessage; + // Remove 'diff' output + const int diffPos = output.indexOf(QLatin1String("\ndiff --")); + if (diffPos != -1) + output.remove(diffPos, output.size() - diffPos); + return output; +} + +bool RemoteBranchModel::runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage) +{ + return m_client->synchronousBranchCmd(workingDirectory, additionalArgs, output, errorMessage); +} + +bool RemoteBranchModel::refreshBranches(const QString &workingDirectory, bool remoteBranches, + int *currentBranch, QString *errorMessage) { // Run branch command with verbose. QStringList branchArgs(QLatin1String("-v")); QString output; - if (m_type == RemoteBranches) + *currentBranch = -1; + if (remoteBranches) branchArgs.push_back(QLatin1String("-r")); - if (!m_client->synchronousBranchCmd(workingDirectory, branchArgs, &output, errorMessage)) + if (!runGitBranchCommand(workingDirectory, branchArgs, &output, errorMessage)) return false; if (debug) qDebug() << Q_FUNC_INFO << workingDirectory << output; // Parse output m_workingDirectory = workingDirectory; m_branches.clear(); - m_currentBranch = -1; const QStringList branches = output.split(QLatin1Char('\n')); const int branchCount = branches.size(); bool isCurrent; @@ -110,25 +129,122 @@ bool BranchModel::refresh(const QString &workingDirectory, QString *errorMessage if (newBranch.parse(branches.at(b), &isCurrent)) { m_branches.push_back(newBranch); if (isCurrent) - m_currentBranch = b; + *currentBranch = b; } } reset(); return true; } -QString BranchModel::toolTip(const QString &sha) const +int RemoteBranchModel::findBranchByName(const QString &name) const { - // Show the sha description excluding diff as toolTip + const int count = branchCount(); + for (int i = 0; i < count; i++) + if (branchName(i) == name) + return i; + return -1; +} + +// --- LocalBranchModel +LocalBranchModel::LocalBranchModel(GitClient *client, QObject *parent) : + RemoteBranchModel(client, parent), + m_typeHere(tr("<New branch>")), + m_typeHereToolTip(tr("Type to create a new branch")), + m_currentBranch(-1) +{ +} + +int LocalBranchModel::currentBranch() const +{ + return m_currentBranch; +} + +bool LocalBranchModel::isNewBranchRow(int row) const +{ + return row >= branchCount(); +} + +Qt::ItemFlags LocalBranchModel::flags(const QModelIndex & index) const +{ + if (isNewBranchRow(index)) + return Qt::ItemIsEditable|Qt::ItemIsSelectable|Qt::ItemIsEnabled| Qt::ItemIsUserCheckable; + return RemoteBranchModel::flags(index) | Qt::ItemIsUserCheckable; +} + +int LocalBranchModel::rowCount(const QModelIndex & /* parent */) const +{ + return branchCount() + 1; +} + +QVariant LocalBranchModel::data(const QModelIndex &index, int role) const +{ + if (isNewBranchRow(index)) { + switch (role) { + case Qt::DisplayRole: + return m_typeHere; + case Qt::ToolTipRole: + return m_typeHereToolTip; + case Qt::CheckStateRole: + return QVariant(false); + } + return QVariant(); + } + + if (role == Qt::CheckStateRole) + return index.row() == m_currentBranch ? Qt::Checked : Qt::Unchecked; + return RemoteBranchModel::data(index, role); +} + +bool LocalBranchModel::refresh(const QString &workingDirectory, QString *errorMessage) +{ + return refreshBranches(workingDirectory, false, &m_currentBranch, errorMessage); +} + +bool LocalBranchModel::checkNewBranchName(const QString &name) const +{ + // Syntax + const QRegExp pattern(QLatin1String("[a-zA-Z0-9-_]+")); + if (!pattern.exactMatch(name)) + return false; + // existing + if (findBranchByName(name) != -1) + return false; + return true; +} + +bool LocalBranchModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + // Verify + if (role != Qt::EditRole || index.row() < branchCount()) + return false; + const QString branchName = value.toString(); + const bool ok = checkNewBranchName(branchName); + if (debug) + qDebug() << Q_FUNC_INFO << branchName << ok; + if (!ok) + return false; + // Create QString output; QString errorMessage; - if (!m_client->synchronousShow(m_workingDirectory, sha, &output, &errorMessage)) - return errorMessage; - // Remove 'diff' output - const int diffPos = output.indexOf(QLatin1String("\ndiff --")); - if (diffPos != -1) - output.remove(diffPos, output.size() - diffPos); - return output; + if (!runGitBranchCommand(workingDirectory(), QStringList(branchName), &output, &errorMessage)) + return false; + m_newBranch = branchName; + // Start a delayed complete refresh and return true for now. + QTimer::singleShot(0, this, SLOT(slotNewBranchDelayedRefresh())); + return true; +} + +void LocalBranchModel::slotNewBranchDelayedRefresh() +{ + if (debug) + qDebug() << Q_FUNC_INFO; + + QString errorMessage; + if (!refresh(workingDirectory(), &errorMessage)) { + qWarning("%s", qPrintable(errorMessage)); + return; + } + emit newBranchCreated(m_newBranch); } } diff --git a/src/plugins/git/branchmodel.h b/src/plugins/git/branchmodel.h index 5083a1c377..91b1ca84dc 100644 --- a/src/plugins/git/branchmodel.h +++ b/src/plugins/git/branchmodel.h @@ -3,27 +3,25 @@ #include <QtCore/QAbstractListModel> #include <QtCore/QList> +#include <QtCore/QVariant> namespace Git { namespace Internal { class GitClient; -/* A model to list git branches in a simple list of branch names. Local - * branches will have a read-only checkbox indicating the current one. The - * [delayed] tooltip describes the latest commit. */ +/* A read-only model to list git remote branches in a simple list of branch names. + * The tooltip describes the latest commit (delayed creation). + * Provides virtuals to be able to derive a local branch model with the notion + * of a "current branch". */ -class BranchModel : public QAbstractListModel { +class RemoteBranchModel : public QAbstractListModel { + Q_OBJECT public: - enum Type { LocalBranches, RemoteBranches }; + explicit RemoteBranchModel(GitClient *client, QObject *parent = 0); - explicit BranchModel(GitClient *client, - Type type = LocalBranches, - QObject *parent = 0); - - bool refresh(const QString &workingDirectory, QString *errorMessage); + virtual bool refresh(const QString &workingDirectory, QString *errorMessage); - int currentBranch() const; QString branchName(int row) const; // QAbstractListModel @@ -31,9 +29,12 @@ public: virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; virtual Qt::ItemFlags flags(const QModelIndex &index) const; -private: - QString toolTip(const QString &sha) const; + int branchCount() const; + QString workingDirectory() const; + int findBranchByName(const QString &name) const; + +protected: struct Branch { bool parse(const QString &line, bool *isCurrent); @@ -43,13 +44,61 @@ private: }; typedef QList<Branch> BranchList; - const Type m_type; + /* Parse git output and populate m_branches. */ + bool refreshBranches(const QString &workingDirectory, bool remoteBranches, + int *currentBranch, QString *errorMessage); + bool runGitBranchCommand(const QString &workingDirectory, const QStringList &additionalArgs, QString *output, QString *errorMessage); + +private: + QString toolTip(const QString &sha) const; + const Qt::ItemFlags m_flags; - GitClient *m_client; + GitClient *m_client; QString m_workingDirectory; BranchList m_branches; +}; + +/* LocalBranchModel: Extends RemoteBranchModel by a read-only + * checkable column indicating the current branch. Provides an + * editable "Type here" new-branch-row at the bottom to create + * a new branch. */ + +class LocalBranchModel : public RemoteBranchModel { + Q_OBJECT +public: + + explicit LocalBranchModel(GitClient *client, + QObject *parent = 0); + + virtual bool refresh(const QString &workingDirectory, QString *errorMessage); + + // is this the "type here" row? + bool isNewBranchRow(int row) const; + bool isNewBranchRow(const QModelIndex & index) const { return isNewBranchRow(index.row()); } + + int currentBranch() const; + + // QAbstractListModel + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + +signals: + void newBranchCreated(const QString &); + +private slots: + void slotNewBranchDelayedRefresh(); + +private: + bool checkNewBranchName(const QString &name) const; + + const QVariant m_typeHere; + const QVariant m_typeHereToolTip; + int m_currentBranch; + QString m_newBranch; }; } diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index bdc98b66ee..5ecb375240 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -83,7 +83,8 @@ void HelpManager::registerDocumentation(const QStringList &fileNames) bool needsSetup = false; { QHelpEngineCore hc(m_helpEngine->collectionFile()); - hc.setupData(); + if (!hc.setupData()) + qWarning() << "Could not initialize help engine:" << hc.error(); foreach (const QString &fileName, fileNames) { if (!QFile::exists(fileName)) continue; @@ -132,7 +133,7 @@ bool HelpPlugin::initialize(const QStringList & /*arguments*/, QString *) // FIXME shouldn't the help engine create the directory if it doesn't exist? QFileInfo fi(m_core->settings()->fileName()); - QDir directory(fi.absolutePath()); + QDir directory(fi.absolutePath()+"/qtcreator"); if (!directory.exists()) directory.mkpath(directory.absolutePath()); m_helpEngine = new QHelpEngine(directory.absolutePath() diff --git a/src/plugins/qt4projectmanager/qt4project.cpp b/src/plugins/qt4projectmanager/qt4project.cpp index 2a7fd0c242..dd61dbde09 100644 --- a/src/plugins/qt4projectmanager/qt4project.cpp +++ b/src/plugins/qt4projectmanager/qt4project.cpp @@ -566,7 +566,6 @@ QStringList Qt4Project::files(FilesMode fileMode) const if (fileMode == AllFiles) files += m_projectFiles->generatedFiles[i]; } - files += m_projectFiles->proFiles; return files; } diff --git a/src/plugins/quickopen/quickopentoolwindow.cpp b/src/plugins/quickopen/quickopentoolwindow.cpp index 415e347a3a..b3232147f3 100644 --- a/src/plugins/quickopen/quickopentoolwindow.cpp +++ b/src/plugins/quickopen/quickopentoolwindow.cpp @@ -451,14 +451,25 @@ void QuickOpenToolWindow::show(const QString &text, int selectionStart, int sele void QuickOpenToolWindow::filterSelected() { - const char * const TEXT = "<type here>"; + QString searchText = "<type here>"; QAction *action = qobject_cast<QAction*>(sender()); QTC_ASSERT(action, return); IQuickOpenFilter *filter = action->data().value<IQuickOpenFilter*>(); QTC_ASSERT(filter, return); - show(filter->shortcutString() + " " + TEXT, + QString currentText = m_fileLineEdit->text().trimmed(); + // add shortcut string at front or replace existing shortcut string + if (!currentText.isEmpty()) { + searchText = currentText; + foreach (IQuickOpenFilter *otherfilter, m_quickOpenPlugin->filter()) { + if (currentText.startsWith(otherfilter->shortcutString() + " ")) { + searchText = currentText.mid(otherfilter->shortcutString().length()+1); + break; + } + } + } + show(filter->shortcutString() + " " + searchText, filter->shortcutString().length() + 1, - QString(TEXT).length()); + searchText.length()); updateCompletionList(m_fileLineEdit->text()); m_fileLineEdit->setFocus(); } diff --git a/src/plugins/texteditor/completionwidget.cpp b/src/plugins/texteditor/completionwidget.cpp index 2b2f8520e7..2c9f6017b7 100644 --- a/src/plugins/texteditor/completionwidget.cpp +++ b/src/plugins/texteditor/completionwidget.cpp @@ -260,9 +260,9 @@ void CompletionWidget::updatePositionAndSize(int startPos) const QRect cursorRect = m_editor->cursorRect(startPos); const QDesktopWidget *desktop = QApplication::desktop(); #ifdef Q_OS_MAC - const QRect screen = desktop->availableGeometry(desktop->screenNumber(this)); + const QRect screen = desktop->availableGeometry(desktop->screenNumber(m_editorWidget)); #else - const QRect screen = desktop->screenGeometry(desktop->screenNumber(this)); + const QRect screen = desktop->screenGeometry(desktop->screenNumber(m_editorWidget)); #endif QPoint pos = cursorRect.bottomLeft(); |