summaryrefslogtreecommitdiff
path: root/src/plugins/texteditor
diff options
context:
space:
mode:
authorcon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
committercon <qtc-commiter@nokia.com>2008-12-02 12:01:29 +0100
commit05c35356abc31549c5db6eba31fb608c0365c2a0 (patch)
treebe044530104267afaff13f8943889cb97f8c8bad /src/plugins/texteditor
downloadqt-creator-05c35356abc31549c5db6eba31fb608c0365c2a0.tar.gz
Initial import
Diffstat (limited to 'src/plugins/texteditor')
-rw-r--r--src/plugins/texteditor/TextEditor.mimetypes.xml47
-rw-r--r--src/plugins/texteditor/TextEditor.pluginspec12
-rw-r--r--src/plugins/texteditor/basefilefind.cpp233
-rw-r--r--src/plugins/texteditor/basefilefind.h95
-rw-r--r--src/plugins/texteditor/basetextdocument.cpp349
-rw-r--r--src/plugins/texteditor/basetextdocument.h161
-rw-r--r--src/plugins/texteditor/basetexteditor.cpp3453
-rw-r--r--src/plugins/texteditor/basetexteditor.h513
-rw-r--r--src/plugins/texteditor/basetexteditor_p.h225
-rw-r--r--src/plugins/texteditor/basetextmark.cpp136
-rw-r--r--src/plugins/texteditor/basetextmark.h132
-rw-r--r--src/plugins/texteditor/codecselector.cpp179
-rw-r--r--src/plugins/texteditor/codecselector.h85
-rw-r--r--src/plugins/texteditor/completionsupport.cpp171
-rw-r--r--src/plugins/texteditor/completionsupport.h83
-rw-r--r--src/plugins/texteditor/completionwidget.cpp264
-rw-r--r--src/plugins/texteditor/completionwidget.h90
-rw-r--r--src/plugins/texteditor/displaysettings.cpp108
-rw-r--r--src/plugins/texteditor/displaysettings.h67
-rw-r--r--src/plugins/texteditor/findinfiles.cpp144
-rw-r--r--src/plugins/texteditor/findinfiles.h83
-rw-r--r--src/plugins/texteditor/fontsettings.cpp277
-rw-r--r--src/plugins/texteditor/fontsettings.h149
-rw-r--r--src/plugins/texteditor/fontsettingspage.cpp465
-rw-r--r--src/plugins/texteditor/fontsettingspage.h124
-rw-r--r--src/plugins/texteditor/fontsettingspage.ui268
-rw-r--r--src/plugins/texteditor/generalsettingspage.cpp217
-rw-r--r--src/plugins/texteditor/generalsettingspage.h98
-rw-r--r--src/plugins/texteditor/generalsettingspage.ui336
-rw-r--r--src/plugins/texteditor/icompletioncollector.h114
-rw-r--r--src/plugins/texteditor/images/finddirectory.pngbin0 -> 845 bytes
-rw-r--r--src/plugins/texteditor/images/finddocuments.pngbin0 -> 721 bytes
-rw-r--r--src/plugins/texteditor/itexteditable.h64
-rw-r--r--src/plugins/texteditor/itexteditor.h132
-rw-r--r--src/plugins/texteditor/linenumberfilter.cpp80
-rw-r--r--src/plugins/texteditor/linenumberfilter.h76
-rw-r--r--src/plugins/texteditor/plaintexteditor.cpp129
-rw-r--r--src/plugins/texteditor/plaintexteditor.h72
-rw-r--r--src/plugins/texteditor/plaintexteditorfactory.cpp83
-rw-r--r--src/plugins/texteditor/plaintexteditorfactory.h73
-rw-r--r--src/plugins/texteditor/storagesettings.cpp81
-rw-r--r--src/plugins/texteditor/storagesettings.h62
-rw-r--r--src/plugins/texteditor/tabsettings.cpp241
-rw-r--r--src/plugins/texteditor/tabsettings.h83
-rw-r--r--src/plugins/texteditor/textblockiterator.cpp96
-rw-r--r--src/plugins/texteditor/textblockiterator.h71
-rw-r--r--src/plugins/texteditor/texteditor.pri3
-rw-r--r--src/plugins/texteditor/texteditor.pro58
-rw-r--r--src/plugins/texteditor/texteditor.qrc7
-rw-r--r--src/plugins/texteditor/texteditor_dependencies.pri4
-rw-r--r--src/plugins/texteditor/texteditor_global.h57
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.cpp459
-rw-r--r--src/plugins/texteditor/texteditoractionhandler.h143
-rw-r--r--src/plugins/texteditor/texteditorconstants.h88
-rw-r--r--src/plugins/texteditor/texteditorplugin.cpp180
-rw-r--r--src/plugins/texteditor/texteditorplugin.h94
-rw-r--r--src/plugins/texteditor/texteditorsettings.cpp152
-rw-r--r--src/plugins/texteditor/texteditorsettings.h88
-rw-r--r--src/plugins/texteditor/textfilewizard.cpp63
-rw-r--r--src/plugins/texteditor/textfilewizard.h67
60 files changed, 11484 insertions, 0 deletions
diff --git a/src/plugins/texteditor/TextEditor.mimetypes.xml b/src/plugins/texteditor/TextEditor.mimetypes.xml
new file mode 100644
index 0000000000..e78754da68
--- /dev/null
+++ b/src/plugins/texteditor/TextEditor.mimetypes.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0"?>
+<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
+ <mime-type type="text/plain">
+ <comment>Plain text document</comment>
+ <sub-class-of type="application/octet-stream"/>
+ <comment xml:lang="bg">Документ с неформатиран текст</comment>
+ <comment xml:lang="ca">document de text pla</comment>
+ <comment xml:lang="cs">Prostý textový dokument</comment>
+ <comment xml:lang="da">ren tekst-dokument</comment>
+ <comment xml:lang="de">einfaches Textdokument</comment>
+ <comment xml:lang="el">έγγραφο απλού κειμένου</comment>
+ <comment xml:lang="eo">plata teksta dokumento</comment>
+ <comment xml:lang="es">documento de texto sencillo</comment>
+ <comment xml:lang="eu">testu soileko dokumentua</comment>
+ <comment xml:lang="fi">perustekstiasiakirja</comment>
+ <comment xml:lang="fr">document plein texte</comment>
+ <comment xml:lang="hu">egyszerű szöveg</comment>
+ <comment xml:lang="it">Documento in testo semplice</comment>
+ <comment xml:lang="ja">平文テキストドキュメント</comment>
+ <comment xml:lang="ko">보통 text 문서</comment>
+ <comment xml:lang="lt">paprastas tekstinis dokumentas</comment>
+ <comment xml:lang="ms">Dokumen teks jernih</comment>
+ <comment xml:lang="nb">vanlig tekstdokument</comment>
+ <comment xml:lang="nl">platte tekst document</comment>
+ <comment xml:lang="nn">vanleg tekstdokument</comment>
+ <comment xml:lang="pl">zwykły dokument tekstowy</comment>
+ <comment xml:lang="pt">documento em texto simples</comment>
+ <comment xml:lang="pt_BR">Documento somente texto</comment>
+ <comment xml:lang="sq">dokument teksti i thjeshtë</comment>
+ <comment xml:lang="sr">обичан текстуални документ</comment>
+ <comment xml:lang="sv">vanligt textdokument</comment>
+ <comment xml:lang="uk">звичайний текстовий документ</comment>
+ <comment xml:lang="vi">thư nhập thô (văn bản không có kiểu dáng)</comment>
+ <comment xml:lang="zh_CN">纯文本文档</comment>
+ <comment xml:lang="zh_TW">普通文本檔</comment>
+ <glob pattern="*.txt"/>
+ </mime-type>
+ <mime-type type="application/xml">
+ <sub-class-of type="text/plain"/>
+ <comment>XML document</comment>
+ <glob pattern="*.xml"/>
+ <glob pattern="*.xsl"/>
+ <glob pattern="*.xslt"/>
+ <glob pattern="*.xbl"/>
+ <alias type="text/xml"/>
+ </mime-type>
+</mime-info>
diff --git a/src/plugins/texteditor/TextEditor.pluginspec b/src/plugins/texteditor/TextEditor.pluginspec
new file mode 100644
index 0000000000..aaad622ea4
--- /dev/null
+++ b/src/plugins/texteditor/TextEditor.pluginspec
@@ -0,0 +1,12 @@
+<plugin name="TextEditor" version="0.9.1" compatVersion="0.9.1">
+ <vendor>Nokia Corporation</vendor>
+ <copyright>(C) 2008 Nokia Corporation</copyright>
+ <license>Nokia Technology Preview License Agreement</license>
+ <description>Text editor framework and the implementation of the basic text editor.</description>
+ <url>http://www.trolltech.com/</url>
+ <dependencyList>
+ <dependency name="Core" version="0.9.1"/>
+ <dependency name="Find" version="0.9.1"/>
+ <dependency name="QuickOpen" version="0.9.1"/>
+ </dependencyList>
+</plugin>
diff --git a/src/plugins/texteditor/basefilefind.cpp b/src/plugins/texteditor/basefilefind.cpp
new file mode 100644
index 0000000000..4c11a626db
--- /dev/null
+++ b/src/plugins/texteditor/basefilefind.cpp
@@ -0,0 +1,233 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basefilefind.h"
+
+#include <coreplugin/stylehelper.h>
+#include <coreplugin/progressmanager/progressmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <find/textfindconstants.h>
+#include <texteditor/itexteditor.h>
+#include <texteditor/basetexteditor.h>
+
+#include <QtDebug>
+#include <QtCore/QDirIterator>
+#include <QtGui/QPushButton>
+#include <QtGui/QFileDialog>
+
+using namespace Core::Utils;
+using namespace Find;
+using namespace TextEditor;
+
+BaseFileFind::BaseFileFind(Core::ICore *core, SearchResultWindow *resultWindow)
+ : m_core(core),
+ m_resultWindow(resultWindow),
+ m_isSearching(false),
+ m_resultLabel(0),
+ m_filterCombo(0),
+ m_useRegExp(false),
+ m_useRegExpCheckBox(0)
+{
+ m_watcher.setPendingResultsLimit(1);
+ connect(&m_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(displayResult(int)));
+ connect(&m_watcher, SIGNAL(finished()), this, SLOT(searchFinished()));
+}
+
+bool BaseFileFind::isEnabled() const
+{
+ return !m_isSearching;
+}
+
+QStringList BaseFileFind::fileNameFilters() const
+{
+ QStringList filters;
+ if (m_filterCombo && !m_filterCombo->currentText().isEmpty()) {
+ QStringList parts = m_filterCombo->currentText().split(",");
+ foreach (const QString &part, parts) {
+ QString filter = part.trimmed();
+ if (!filter.isEmpty()) {
+ filters << filter;
+ }
+ }
+ }
+ return filters;
+}
+
+void BaseFileFind::findAll(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ m_isSearching = true;
+ emit changed();
+ updateComboEntries(m_filterCombo, false);
+ m_watcher.setFuture(QFuture<FileSearchResult>());
+ m_resultWindow->clearContents();
+ m_resultWindow->popup(true);
+ if (m_useRegExp)
+ m_watcher.setFuture(Core::Utils::findInFilesRegExp(txt, files(), findFlags));
+ else
+ m_watcher.setFuture(Core::Utils::findInFiles(txt, files(), findFlags));
+ Core::FutureProgress *progress = m_core->progressManager()->addTask(m_watcher.future(),
+ "Search",
+ Constants::TASK_SEARCH);
+ progress->setWidget(createProgressWidget());
+ connect(progress, SIGNAL(clicked()), m_resultWindow, SLOT(popup()));
+}
+
+void BaseFileFind::displayResult(int index) {
+ Core::Utils::FileSearchResult result = m_watcher.future().resultAt(index);
+ ResultWindowItem *item = m_resultWindow->addResult(result.fileName,
+ result.lineNumber,
+ result.matchingLine,
+ result.matchStart,
+ result.matchLength);
+ if (item)
+ connect(item, SIGNAL(activated(const QString&,int,int)), this, SLOT(openEditor(const QString&,int,int)));
+
+ if (m_resultLabel)
+ m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
+}
+
+void BaseFileFind::searchFinished()
+{
+ m_isSearching = false;
+ m_resultLabel = 0;
+ emit changed();
+}
+
+QWidget *BaseFileFind::createProgressWidget()
+{
+ m_resultLabel = new QLabel;
+ // ### TODO this setup should be done by style
+ QFont f = m_resultLabel->font();
+ f.setBold(true);
+ f.setPointSizeF(StyleHelper::sidebarFontSize());
+ m_resultLabel->setFont(f);
+ m_resultLabel->setPalette(StyleHelper::sidebarFontPalette(m_resultLabel->palette()));
+ m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
+ return m_resultLabel;
+}
+
+QWidget *BaseFileFind::createPatternWidget()
+{
+/*
+ QWidget *widget = new QWidget;
+ QHBoxLayout *hlayout = new QHBoxLayout(widget);
+ hlayout->setMargin(0);
+ widget->setLayout(hlayout);
+*/
+ QString filterToolTip = tr("List of comma separated wildcard filters");
+/*
+ QLabel *label = new QLabel(tr("File pattern:"));
+ label->setToolTip(filterToolTip);
+*/
+/*
+ hlayout->addWidget(label);
+*/
+ m_filterCombo = new QComboBox;
+ m_filterCombo->setEditable(true);
+ m_filterCombo->setModel(&m_filterStrings);
+ m_filterCombo->setMaxCount(10);
+ m_filterCombo->setMinimumContentsLength(10);
+ m_filterCombo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
+ m_filterCombo->setInsertPolicy(QComboBox::InsertAtBottom);
+ m_filterCombo->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_filterCombo->setToolTip(filterToolTip);
+ syncComboWithSettings(m_filterCombo, m_filterSetting);
+/*
+ hlayout->addWidget(m_filterCombo);
+*/
+ return m_filterCombo;
+}
+
+QWidget *BaseFileFind::createRegExpWidget()
+{
+ m_useRegExpCheckBox = new QCheckBox(tr("Use Regular Expressions"));
+ m_useRegExpCheckBox->setChecked(m_useRegExp);
+ connect(m_useRegExpCheckBox, SIGNAL(toggled(bool)), this, SLOT(syncRegExpSetting(bool)));
+ return m_useRegExpCheckBox;
+}
+
+void BaseFileFind::writeCommonSettings(QSettings *settings)
+{
+ settings->setValue("filters", m_filterStrings.stringList());
+ if (m_filterCombo)
+ settings->setValue("currentFilter", m_filterCombo->currentText());
+ settings->setValue("useRegExp", m_useRegExp);
+}
+
+void BaseFileFind::readCommonSettings(QSettings *settings, const QString &defaultFilter)
+{
+ QStringList filters = settings->value("filters").toStringList();
+ m_filterSetting = settings->value("currentFilter").toString();
+ m_useRegExp = settings->value("useRegExp", false).toBool();
+ if (m_useRegExpCheckBox)
+ m_useRegExpCheckBox->setChecked(m_useRegExp);
+ if (filters.isEmpty())
+ filters << defaultFilter;
+ if (m_filterSetting.isEmpty())
+ m_filterSetting = filters.first();
+ m_filterStrings.setStringList(filters);
+ syncComboWithSettings(m_filterCombo, m_filterSetting);
+}
+
+void BaseFileFind::syncComboWithSettings(QComboBox *combo, const QString &setting)
+{
+ if (!combo)
+ return;
+ int index = combo->findText(setting);
+ if (index < 0)
+ combo->setEditText(setting);
+ else
+ combo->setCurrentIndex(index);
+}
+
+void BaseFileFind::updateComboEntries(QComboBox *combo, bool onTop)
+{
+ int index = combo->findText(combo->currentText());
+ if (index < 0) {
+ if (onTop) {
+ combo->insertItem(0, combo->currentText());
+ } else {
+ combo->addItem(combo->currentText());
+ }
+ combo->setCurrentIndex(combo->findText(combo->currentText()));
+ }
+}
+
+void BaseFileFind::syncRegExpSetting(bool useRegExp)
+{
+ m_useRegExp = useRegExp;
+}
+
+void BaseFileFind::openEditor(const QString &fileName, int line, int column)
+{
+ TextEditor::BaseTextEditor::openEditorAt(fileName, line, column);
+}
diff --git a/src/plugins/texteditor/basefilefind.h b/src/plugins/texteditor/basefilefind.h
new file mode 100644
index 0000000000..562a4487cc
--- /dev/null
+++ b/src/plugins/texteditor/basefilefind.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASEFILEFIND_H
+#define BASEFILEFIND_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/icore.h>
+#include <find/ifindfilter.h>
+#include <find/searchresultwindow.h>
+#include <utils/filesearch.h>
+
+#include <QtCore/QFutureWatcher>
+#include <QtCore/QPointer>
+#include <QtGui/QLabel>
+#include <QtGui/QComboBox>
+#include <QtGui/QStringListModel>
+#include <QtGui/QCheckBox>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT BaseFileFind : public Find::IFindFilter
+{
+ Q_OBJECT
+
+public:
+ BaseFileFind(Core::ICore *core, Find::SearchResultWindow *resultWindow);
+
+ bool isEnabled() const;
+ void findAll(const QString &txt, QTextDocument::FindFlags findFlags);
+
+protected:
+ virtual QStringList files() = 0;
+ void writeCommonSettings(QSettings *settings);
+ void readCommonSettings(QSettings *settings, const QString &defaultFilter);
+ QWidget *createPatternWidget();
+ QWidget *createRegExpWidget();
+ void syncComboWithSettings(QComboBox *combo, const QString &setting);
+ void updateComboEntries(QComboBox *combo, bool onTop);
+ QStringList fileNameFilters() const;
+
+private slots:
+ void displayResult(int index);
+ void searchFinished();
+ void openEditor(const QString &fileName, int line, int column);
+ void syncRegExpSetting(bool useRegExp);
+
+private:
+ QWidget *createProgressWidget();
+
+ Core::ICore *m_core;
+ Find::SearchResultWindow *m_resultWindow;
+ QFutureWatcher<Core::Utils::FileSearchResult> m_watcher;
+ bool m_isSearching;
+ QLabel *m_resultLabel;
+ QStringListModel m_filterStrings;
+ QString m_filterSetting;
+ QPointer<QComboBox> m_filterCombo;
+ bool m_useRegExp;
+ QCheckBox *m_useRegExpCheckBox;
+};
+
+} // namespace TextEditor
+
+#endif // BASEFILEFIND_H
diff --git a/src/plugins/texteditor/basetextdocument.cpp b/src/plugins/texteditor/basetextdocument.cpp
new file mode 100644
index 0000000000..916bc11f2f
--- /dev/null
+++ b/src/plugins/texteditor/basetextdocument.cpp
@@ -0,0 +1,349 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basetextdocument.h"
+#include "basetexteditor.h"
+#include "storagesettings.h"
+
+#include <QtCore/QFile>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextStream>
+#include <QtCore/QTextCodec>
+#include <QtGui/QMainWindow>
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QApplication>
+
+#ifndef TEXTEDITOR_STANDALONE
+#include <utils/reloadpromptutils.h>
+#include "coreplugin/icore.h"
+#endif
+
+using namespace TextEditor;
+
+#if defined (Q_OS_WIN)
+# define NATIVE_LINE_TERMINATOR CRLFLineTerminator
+#else
+# define NATIVE_LINE_TERMINATOR LFLineTerminator
+#endif
+
+DocumentMarker::DocumentMarker(QTextDocument *doc)
+ : ITextMarkable(doc), document(doc)
+{
+}
+
+BaseTextDocument::BaseTextDocument()
+ : m_document(new QTextDocument(this)),
+ m_highlighter(0)
+{
+ m_documentMarker = new DocumentMarker(m_document);
+ m_lineTerminatorMode = NativeLineTerminator;
+ m_isBinaryData = false;
+ m_codec = QTextCodec::codecForLocale();
+ m_hasDecodingError = false;
+}
+
+BaseTextDocument::~BaseTextDocument()
+{
+ QTextBlock block = m_document->begin();
+ while (block.isValid()) {
+ if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData()))
+ data->documentClosing();
+ block = block.next();
+ }
+ delete m_document;
+ m_document = 0;
+}
+
+QString BaseTextDocument::mimeType() const
+{
+ return m_mimeType;
+}
+
+void BaseTextDocument::setMimeType(const QString &mt)
+{
+ m_mimeType = mt;
+}
+
+bool BaseTextDocument::save(const QString &fileName)
+{
+ QTextCursor cursor(m_document);
+
+ cursor.beginEditBlock();
+ if (m_storageSettings.m_cleanWhitespace)
+ cleanWhitespace(cursor, m_storageSettings.m_inEntireDocument);
+ if (m_storageSettings.m_addFinalNewLine)
+ ensureFinalNewLine(cursor);
+ cursor.endEditBlock();
+
+ QString fName = m_fileName;
+ if (!fileName.isEmpty())
+ fName = fileName;
+
+ QFile file(fName);
+ if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate))
+ return false;
+
+ QString plainText = m_document->toPlainText();
+
+ if (m_lineTerminatorMode == CRLFLineTerminator)
+ plainText.replace(QLatin1Char('\n'), QLatin1String("\r\n"));
+
+ file.write(m_codec->fromUnicode(plainText));
+ if (!file.flush())
+ return false;
+ file.close();
+
+ const QFileInfo fi(fName);
+ m_fileName = fi.absoluteFilePath();
+
+ m_document->setModified(false);
+ emit titleChanged(fi.fileName());
+ emit changed();
+
+ m_isBinaryData = false;
+ m_hasDecodingError = false;
+ m_decodingErrorSample.clear();
+
+ return true;
+}
+
+bool BaseTextDocument::isReadOnly() const
+{
+ if (m_isBinaryData || m_hasDecodingError)
+ return true;
+ if (m_fileName.isEmpty()) //have no corresponding file, so editing is ok
+ return false;
+ const QFileInfo fi(m_fileName);
+ return !fi.isWritable();
+}
+
+bool BaseTextDocument::isModified() const
+{
+ return m_document->isModified();
+}
+
+bool BaseTextDocument::open(const QString &fileName)
+{
+ QString title = tr("untitled");
+ if (!fileName.isEmpty()) {
+ const QFileInfo fi(fileName);
+ m_fileName = fi.absoluteFilePath();
+
+ QFile file(fileName);
+ if (!file.exists())
+ return false;
+
+ if (!fi.isReadable())
+ return false;
+
+ if (!fi.isWritable()) {
+ if (!file.open(QIODevice::ReadOnly))
+ return false;
+ } else {
+ if (!file.open(QIODevice::ReadWrite))
+ return false;
+ }
+ title = fi.fileName();
+
+ QByteArray buf = file.readAll();
+ int bytesRead = buf.size();
+
+ QTextCodec *codec = m_codec;
+
+ // code taken from qtextstream
+ if (bytesRead >= 4 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe && uchar(buf[2]) == 0 && uchar(buf[3]) == 0)
+ || (uchar(buf[0]) == 0 && uchar(buf[1]) == 0 && uchar(buf[2]) == 0xfe && uchar(buf[3]) == 0xff))) {
+ codec = QTextCodec::codecForName("UTF-32");
+ } else if (bytesRead >= 2 && ((uchar(buf[0]) == 0xff && uchar(buf[1]) == 0xfe)
+ || (uchar(buf[0]) == 0xfe && uchar(buf[1]) == 0xff))) {
+ codec = QTextCodec::codecForName("UTF-16");
+ } else if (!codec) {
+ codec = QTextCodec::codecForLocale();
+ }
+ // end code taken from qtextstream
+
+ m_codec = codec;
+
+#if 0 // should work, but does not, Qt bug with "system" codec
+ QTextDecoder *decoder = m_codec->makeDecoder();
+ QString text = decoder->toUnicode(buf);
+ m_hasDecodingError = (decoder->hasFailure());
+ delete decoder;
+#else
+ QString text = m_codec->toUnicode(buf);
+ QByteArray verifyBuf = m_codec->fromUnicode(text); // slow
+ // the minSize trick lets us ignore unicode headers
+ int minSize = qMin(verifyBuf.size(), buf.size());
+ m_hasDecodingError = (minSize < buf.size()- 4
+ || memcmp(verifyBuf.constData() + verifyBuf.size() - minSize,
+ buf.constData() + buf.size() - minSize, minSize));
+#endif
+
+ if (m_hasDecodingError) {
+ int p = buf.indexOf('\n', 16384);
+ if (p < 0)
+ m_decodingErrorSample = buf;
+ else
+ m_decodingErrorSample = buf.left(p);
+ } else {
+ m_decodingErrorSample.clear();
+ }
+
+ int lf = text.indexOf('\n');
+ if (lf > 0 && text.at(lf-1) == QLatin1Char('\r')) {
+ m_lineTerminatorMode = CRLFLineTerminator;
+ } else if (lf >= 0) {
+ m_lineTerminatorMode = LFLineTerminator;
+ } else {
+ m_lineTerminatorMode = NativeLineTerminator;
+ }
+
+ m_document->setModified(false);
+ m_document->setUndoRedoEnabled(false);
+ if (m_isBinaryData)
+ m_document->setHtml(tr("<em>Binary data</em>"));
+ else
+ m_document->setPlainText(text);
+ m_document->setUndoRedoEnabled(true);
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(m_document->documentLayout());
+ Q_ASSERT(documentLayout);
+ documentLayout->lastSaveRevision = 0;
+ m_document->setModified(false);
+ emit titleChanged(title);
+ emit changed();
+ }
+ return true;
+}
+
+void BaseTextDocument::reload(QTextCodec *codec)
+{
+ Q_ASSERT(codec);
+ m_codec = codec;
+ reload();
+}
+
+void BaseTextDocument::reload()
+{
+ emit aboutToReload();
+ if (open(m_fileName)) {
+ emit reloaded();
+ }
+}
+
+void BaseTextDocument::modified(Core::IFile::ReloadBehavior *behavior)
+{
+ switch (*behavior) {
+ case Core::IFile::ReloadNone:
+ return;
+ case Core::IFile::ReloadAll:
+ reload();
+ return;
+ case Core::IFile::ReloadPermissions:
+ emit changed();
+ return;
+ case Core::IFile::AskForReload:
+ break;
+ }
+
+#ifndef TEXTEDITOR_STANDALONE
+ switch (Core::Utils::reloadPrompt(m_fileName, QApplication::activeWindow())) {
+ case Core::Utils::ReloadCurrent:
+ reload();
+ break;
+ case Core::Utils::ReloadAll:
+ reload();
+ *behavior = Core::IFile::ReloadAll;
+ break;
+ case Core::Utils::ReloadSkipCurrent:
+ break;
+ case Core::Utils::ReloadNone:
+ *behavior = Core::IFile::ReloadNone;
+ break;
+ }
+#endif
+}
+
+void BaseTextDocument::setSyntaxHighlighter(QSyntaxHighlighter *highlighter)
+{
+ if (m_highlighter)
+ delete m_highlighter;
+ m_highlighter = highlighter;
+ m_highlighter->setParent(this);
+ m_highlighter->setDocument(m_document);
+}
+
+void BaseTextDocument::cleanWhitespace(QTextCursor& cursor, bool inEntireDocument)
+{
+
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(m_document->documentLayout());
+
+ QTextBlock block = m_document->firstBlock();
+ while (block.isValid()) {
+
+ if (inEntireDocument || block.revision() > documentLayout->lastSaveRevision) {
+
+ QString blockText = block.text();
+ if (int trailing = m_tabSettings.trailingWhitespaces(blockText)) {
+ cursor.setPosition(block.position() + block.length() - 1);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor, trailing);
+ cursor.removeSelectedText();
+ }
+ if (!m_tabSettings.isIndentationClean(blockText)) {
+ cursor.setPosition(block.position());
+ int firstNonSpace = m_tabSettings.firstNonSpace(blockText);
+ if (firstNonSpace == blockText.length()) {
+ cursor.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ } else {
+ int column = m_tabSettings.columnAt(blockText, firstNonSpace);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace);
+ QString indentationString = m_tabSettings.indentationString(0, column);
+ cursor.insertText(indentationString);
+ }
+ }
+ }
+
+ block = block.next();
+ }
+}
+
+void BaseTextDocument::ensureFinalNewLine(QTextCursor& cursor)
+{
+ cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
+ bool emptyFile = !cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+
+ if (!emptyFile && cursor.selectedText().at(0) != QChar::ParagraphSeparator)
+ {
+ cursor.movePosition(QTextCursor::End, QTextCursor::MoveAnchor);
+ cursor.insertText(QLatin1String("\n"));
+ }
+}
diff --git a/src/plugins/texteditor/basetextdocument.h b/src/plugins/texteditor/basetextdocument.h
new file mode 100644
index 0000000000..8dbfda2ea8
--- /dev/null
+++ b/src/plugins/texteditor/basetextdocument.h
@@ -0,0 +1,161 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTDOCUMENT_H
+#define BASETEXTDOCUMENT_H
+
+#include "texteditor_global.h"
+#include "storagesettings.h"
+#include "itexteditor.h"
+#include "tabsettings.h"
+
+QT_BEGIN_NAMESPACE
+class QTextCursor;
+class QTextDocument;
+class QSyntaxHighlighter;
+QT_END_NAMESPACE
+
+
+namespace Core { class ICore; }
+
+namespace TextEditor {
+
+
+class DocumentMarker : public ITextMarkable
+{
+ Q_OBJECT
+public:
+ DocumentMarker(QTextDocument *);
+
+ // ITextMarkable
+ bool addMark(ITextMark *mark, int line);
+ TextMarks marksAt(int line) const;
+ void removeMark(ITextMark *mark);
+ bool hasMark(ITextMark *mark) const;
+ void updateMark(ITextMark *mark);
+
+private:
+ QTextDocument *document;
+};
+
+
+
+class TEXTEDITOR_EXPORT BaseTextDocument
+ : public Core::IFile
+{
+ Q_OBJECT
+
+public:
+ BaseTextDocument();
+ ~BaseTextDocument();
+ void setStorageSettings(const StorageSettings &storageSettings) { m_storageSettings = storageSettings; }
+ void setTabSettings(const TabSettings &tabSettings) { m_tabSettings = tabSettings; }
+
+ inline const StorageSettings &storageSettings() const { return m_storageSettings; }
+ inline const TabSettings &tabSettings() const { return m_tabSettings; }
+
+ DocumentMarker *documentMarker() const {return m_documentMarker; }
+
+ //IFile
+ virtual bool save(const QString &fileName = QString());
+ virtual QString fileName() const { return m_fileName; }
+ virtual bool isReadOnly() const;
+ virtual bool isModified() const;
+ virtual bool isSaveAsAllowed() const { return true; }
+ virtual void modified(Core::IFile::ReloadBehavior *behavior);
+ virtual QString mimeType() const;
+ void setMimeType(const QString &mt);
+
+ virtual QString defaultPath() const { return m_defaultPath; }
+ virtual QString suggestedFileName() const { return m_suggestedFileName; }
+
+ void setDefaultPath(const QString &defaultPath) { m_defaultPath = defaultPath; }
+ void setSuggestedFileName(const QString &suggestedFileName) { m_suggestedFileName = suggestedFileName; }
+
+ virtual bool open(const QString &fileName = QString());
+ virtual void reload();
+
+ QTextDocument *document() const { return m_document; }
+ void setSyntaxHighlighter(QSyntaxHighlighter *highlighter);
+ QSyntaxHighlighter *syntaxHighlighter() const { return m_highlighter; }
+
+
+ inline bool isBinaryData() const { return m_isBinaryData; }
+ inline bool hasDecodingError() const { return m_hasDecodingError || m_isBinaryData; }
+ inline QTextCodec *codec() const { return m_codec; }
+ inline void setCodec(QTextCodec *c) { m_codec = c; }
+ inline QByteArray decodingErrorSample() const { return m_decodingErrorSample; }
+
+ void reload(QTextCodec *codec);
+
+signals:
+ void titleChanged(QString title);
+ void changed();
+ void aboutToReload();
+ void reloaded();
+
+private:
+ QString m_fileName;
+ QString m_defaultPath;
+ QString m_suggestedFileName;
+ QString m_mimeType;
+ StorageSettings m_storageSettings;
+ TabSettings m_tabSettings;
+ Core::ICore *m_core;
+ QTextDocument *m_document;
+ DocumentMarker *m_documentMarker;
+ QSyntaxHighlighter *m_highlighter;
+
+ enum LineTerminatorMode {
+ LFLineTerminator,
+ CRLFLineTerminator,
+ NativeLineTerminator =
+#if defined (Q_OS_WIN)
+ CRLFLineTerminator
+#else
+ LFLineTerminator
+#endif
+ };
+ LineTerminatorMode m_lineTerminatorMode;
+ QTextCodec *m_codec;
+
+ bool m_isBinaryData;
+ bool m_hasDecodingError;
+ QByteArray m_decodingErrorSample;
+
+ void cleanWhitespace(QTextCursor& cursor, bool onlyInModifiedLines);
+ void ensureFinalNewLine(QTextCursor& cursor);
+};
+
+} // namespace TextEditor
+
+#endif
diff --git a/src/plugins/texteditor/basetexteditor.cpp b/src/plugins/texteditor/basetexteditor.cpp
new file mode 100644
index 0000000000..a112770f93
--- /dev/null
+++ b/src/plugins/texteditor/basetexteditor.cpp
@@ -0,0 +1,3453 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditor_global.h"
+#include "texteditorconstants.h"
+#ifndef TEXTEDITOR_STANDALONE
+#include "texteditorplugin.h"
+#include "completionsupport.h"
+#endif
+#include "basetextdocument.h"
+#include "basetexteditor_p.h"
+#include "codecselector.h"
+
+#ifndef TEXTEDITOR_STANDALONE
+#include <coreplugin/icore.h>
+#include <coreplugin/manhattanstyle.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <find/basetextfind.h>
+#include <texteditor/fontsettings.h>
+#include <utils/reloadpromptutils.h>
+#include <aggregation/aggregate.h>
+#endif
+#include <utils/linecolumnlabel.h>
+
+#include <QtCore/QCoreApplication>
+#include <QtCore/QTextCodec>
+#include <QtCore/QFile>
+#include <QtCore/QDebug>
+#include <QtCore/QTimer>
+#include <QtGui/QAbstractTextDocumentLayout>
+#include <QtGui/QApplication>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QLabel>
+#include <QtGui/QLayout>
+#include <QtGui/QPainter>
+#include <QtGui/QPrinter>
+#include <QtGui/QPrintDialog>
+#include <QtGui/QPainter>
+#include <QtGui/QScrollBar>
+#include <QtGui/QShortcut>
+#include <QtGui/QScrollBar>
+#include <QtGui/QStyle>
+#include <QtGui/QSyntaxHighlighter>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextBlock>
+#include <QtGui/QTextLayout>
+#include <QtGui/QToolBar>
+#include <QtGui/QToolTip>
+#include <QtGui/QInputDialog>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+
+namespace TextEditor {
+ namespace Internal {
+
+class TextEditExtraArea : public QWidget {
+ BaseTextEditor *textEdit;
+public:
+ TextEditExtraArea(BaseTextEditor *edit):QWidget(edit) {
+ textEdit = edit;
+ setAutoFillBackground(true);
+ }
+public:
+
+ QSize sizeHint() const {
+ return QSize(textEdit->extraAreaWidth(), 0);
+ }
+protected:
+ void paintEvent(QPaintEvent *event){
+ textEdit->extraAreaPaintEvent(event);
+ }
+ void mousePressEvent(QMouseEvent *event){
+ textEdit->extraAreaMouseEvent(event);
+ }
+ void mouseMoveEvent(QMouseEvent *event){
+ textEdit->extraAreaMouseEvent(event);
+ }
+ void mouseReleaseEvent(QMouseEvent *event){
+ textEdit->extraAreaMouseEvent(event);
+ }
+ void leaveEvent(QEvent *event){
+ textEdit->extraAreaLeaveEvent(event);
+ }
+
+ void wheelEvent(QWheelEvent *event) {
+ QCoreApplication::sendEvent(textEdit->viewport(), event);
+ }
+};
+
+ }
+}
+
+ITextEditor *BaseTextEditor::openEditorAt(const QString &fileName,
+ int line,
+ int column)
+{
+ Core::EditorManager *editorManager =
+ ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->editorManager();
+ editorManager->addCurrentPositionToNavigationHistory(true);
+ Core::IEditor *editor = editorManager->openEditor(fileName, QString(), true);
+ TextEditor::ITextEditor *texteditor = qobject_cast<TextEditor::ITextEditor *>(editor);
+ if (texteditor) {
+ texteditor->gotoLine(line, column);
+ editorManager->addCurrentPositionToNavigationHistory();
+ return texteditor;
+ }
+ return 0;
+}
+
+BaseTextEditor::BaseTextEditor(QWidget *parent)
+ : QPlainTextEdit(parent)
+{
+ d = new BaseTextEditorPrivate();
+ d->q = this;
+ d->m_extraArea = new TextEditExtraArea(this);
+ d->m_extraArea->setMouseTracking(true);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
+
+ d->setupDocumentSignals(d->m_document);
+ d->setupDocumentSignals(d->m_document);
+
+ d->m_lastScrollPos = -1;
+ setCursorWidth(2);
+
+
+ // from RESEARCH
+
+ setLayoutDirection(Qt::LeftToRight);
+ viewport()->setMouseTracking(true);
+ d->extraAreaSelectionAnchorBlockNumber
+ = d->extraAreaToggleMarkBlockNumber
+ = d->extraAreaHighlightCollapseBlockNumber
+ = d->extraAreaHighlightFadingBlockNumber
+ = -1;
+ d->extraAreaCollapseAlpha = 255;
+
+ d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber = -1;
+
+ connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(slotUpdateExtraAreaWidth()));
+ connect(this, SIGNAL(modificationChanged(bool)), this, SLOT(slotModificationChanged(bool)));
+ connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(slotCursorPositionChanged()));
+ connect(this, SIGNAL(updateRequest(QRect, int)), this, SLOT(slotUpdateRequest(QRect, int)));
+ connect(this, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged()));
+
+// (void) new QShortcut(tr("CTRL+L"), this, SLOT(centerCursor()), 0, Qt::WidgetShortcut);
+// (void) new QShortcut(tr("F9"), this, SLOT(slotToggleMark()), 0, Qt::WidgetShortcut);
+// (void) new QShortcut(tr("F11"), this, SLOT(slotToggleBlockVisible()));
+
+
+ // parentheses matcher
+ d->m_parenthesesMatchingEnabled = false;
+ d->m_formatRange = true;
+ d->m_matchFormat.setForeground(Qt::red);
+ d->m_rangeFormat.setBackground(QColor(0xb4, 0xee, 0xb4));
+ d->m_mismatchFormat.setBackground(Qt::magenta);
+ d->m_parenthesesMatchingTimer = new QTimer(this);
+ d->m_parenthesesMatchingTimer->setSingleShot(true);
+ connect(d->m_parenthesesMatchingTimer, SIGNAL(timeout()), this, SLOT(_q_matchParentheses()));
+
+
+ d->m_searchResultFormat.setBackground(QColor(0xffef0b));
+
+ slotUpdateExtraAreaWidth();
+ slotCursorPositionChanged();
+ setFrameStyle(QFrame::NoFrame);
+
+
+ d->extraAreaTimeLine = new QTimeLine(150, this);
+ d->extraAreaTimeLine->setFrameRange(0, 255);
+ connect(d->extraAreaTimeLine, SIGNAL(frameChanged(int)), this,
+ SLOT(setCollapseIndicatorAlpha(int)));
+
+
+ connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
+ this, SLOT(currentEditorChanged(Core::IEditor*)));
+}
+
+BaseTextEditor::~BaseTextEditor()
+{
+ delete d;
+ d = 0;
+}
+
+QString BaseTextEditor::mimeType() const
+{
+ return d->m_document->mimeType();
+}
+
+void BaseTextEditor::setMimeType(const QString &mt)
+{
+ d->m_document->setMimeType(mt);
+}
+
+void BaseTextEditor::print(QPrinter *printer)
+{
+ const bool oldFullPage = printer->fullPage();
+ printer->setFullPage(true);
+ QPrintDialog *dlg = new QPrintDialog(printer, this);
+ dlg->setWindowTitle(tr("Print Document"));
+ if (dlg->exec() == QDialog::Accepted) {
+ d->print(printer);
+ }
+ printer->setFullPage(oldFullPage);
+ delete dlg;
+}
+
+static void printPage(int index, QPainter *painter, const QTextDocument *doc,
+ const QRectF &body, const QRectF &titleBox,
+ const QString &title)
+{
+ painter->save();
+
+ painter->translate(body.left(), body.top() - (index - 1) * body.height());
+ QRectF view(0, (index - 1) * body.height(), body.width(), body.height());
+
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+ QAbstractTextDocumentLayout::PaintContext ctx;
+
+ painter->setFont(QFont(doc->defaultFont()));
+ QRectF box = titleBox.translated(0, view.top());
+ int dpix = painter->device()->logicalDpiX();
+ int dpiy = painter->device()->logicalDpiY();
+ int mx = 5 * dpix / 72.0;
+ int my = 2 * dpiy / 72.0;
+ painter->fillRect(box.adjusted(-mx, -my, mx, my), QColor(210, 210, 210));
+ if (!title.isEmpty())
+ painter->drawText(box, Qt::AlignCenter, title);
+ const QString pageString = QString::number(index);
+ painter->drawText(box, Qt::AlignRight, pageString);
+
+ painter->setClipRect(view);
+ ctx.clip = view;
+ // don't use the system palette text as default text color, on HP/UX
+ // for example that's white, and white text on white paper doesn't
+ // look that nice
+ ctx.palette.setColor(QPalette::Text, Qt::black);
+
+ layout->draw(painter, ctx);
+
+ painter->restore();
+}
+
+void BaseTextEditorPrivate::print(QPrinter *printer)
+{
+
+ QTextDocument *doc = q->document();
+
+ QString title = q->displayName();
+ if (title.isEmpty())
+ printer->setDocName(title);
+
+
+ QPainter p(printer);
+
+ // Check that there is a valid device to print to.
+ if (!p.isActive())
+ return;
+
+ doc = doc->clone(doc);
+
+ QTextOption opt = doc->defaultTextOption();
+ opt.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ doc->setDefaultTextOption(opt);
+
+ (void)doc->documentLayout(); // make sure that there is a layout
+
+
+ QColor background = q->palette().color(QPalette::Base);
+ bool backgroundIsDark = background.value() < 128;
+
+ for (QTextBlock srcBlock = q->document()->firstBlock(), dstBlock = doc->firstBlock();
+ srcBlock.isValid() && dstBlock.isValid();
+ srcBlock = srcBlock.next(), dstBlock = dstBlock.next()) {
+
+
+ QList<QTextLayout::FormatRange> formatList = srcBlock.layout()->additionalFormats();
+ if (backgroundIsDark) {
+ // adjust syntax highlighting colors for better contrast
+ for (int i = formatList.count() - 1; i >=0; --i) {
+ QTextCharFormat &format = formatList[i].format;
+ if (format.background().color() == background) {
+ QBrush brush = format.foreground();
+ QColor color = brush.color();
+ int h,s,v,a;
+ color.getHsv(&h, &s, &v, &a);
+ color.setHsv(h, s, qMin(128, v), a);
+ brush.setColor(color);
+ format.setForeground(brush);
+ }
+ format.setBackground(Qt::white);
+ }
+ }
+
+ dstBlock.layout()->setAdditionalFormats(formatList);
+ }
+
+ QAbstractTextDocumentLayout *layout = doc->documentLayout();
+ layout->setPaintDevice(p.device());
+
+ int dpiy = p.device()->logicalDpiY();
+ int margin = (int) ((2/2.54)*dpiy); // 2 cm margins
+
+ QTextFrameFormat fmt = doc->rootFrame()->frameFormat();
+ fmt.setMargin(margin);
+ doc->rootFrame()->setFrameFormat(fmt);
+
+ QRectF pageRect(printer->pageRect());
+ QRectF body = QRectF(0, 0, pageRect.width(), pageRect.height());
+ QFontMetrics fontMetrics(doc->defaultFont(), p.device());
+
+ QRectF titleBox(margin,
+ body.top() + margin
+ - fontMetrics.height()
+ - 6 * dpiy / 72.0,
+ body.width() - 2*margin,
+ fontMetrics.height());
+ doc->setPageSize(body.size());
+
+ int docCopies;
+ int pageCopies;
+ if (printer->collateCopies() == true){
+ docCopies = 1;
+ pageCopies = printer->numCopies();
+ } else {
+ docCopies = printer->numCopies();
+ pageCopies = 1;
+ }
+
+ int fromPage = printer->fromPage();
+ int toPage = printer->toPage();
+ bool ascending = true;
+
+ if (fromPage == 0 && toPage == 0) {
+ fromPage = 1;
+ toPage = doc->pageCount();
+ }
+ // paranoia check
+ fromPage = qMax(1, fromPage);
+ toPage = qMin(doc->pageCount(), toPage);
+
+ if (printer->pageOrder() == QPrinter::LastPageFirst) {
+ int tmp = fromPage;
+ fromPage = toPage;
+ toPage = tmp;
+ ascending = false;
+ }
+
+ for (int i = 0; i < docCopies; ++i) {
+
+ int page = fromPage;
+ while (true) {
+ for (int j = 0; j < pageCopies; ++j) {
+ if (printer->printerState() == QPrinter::Aborted
+ || printer->printerState() == QPrinter::Error)
+ goto UserCanceled;
+ printPage(page, &p, doc, body, titleBox, title);
+ if (j < pageCopies - 1)
+ printer->newPage();
+ }
+
+ if (page == toPage)
+ break;
+
+ if (ascending)
+ ++page;
+ else
+ --page;
+
+ printer->newPage();
+ }
+
+ if ( i < docCopies - 1)
+ printer->newPage();
+ }
+
+UserCanceled:
+ delete doc;
+}
+
+
+bool DocumentMarker::addMark(TextEditor::ITextMark *mark, int line)
+{
+ Q_ASSERT(line >= 1);
+ int blockNumber = line - 1;
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document->documentLayout());
+ Q_ASSERT(documentLayout);
+ QTextBlock block = document->findBlockByNumber(blockNumber);
+
+ if (block.isValid()) {
+ TextBlockUserData *userData = TextEditDocumentLayout::userData(block);
+ userData->addMark(mark);
+ mark->updateLineNumber(blockNumber + 1);
+ mark->updateBlock(block);
+ documentLayout->hasMarks = true;
+ documentLayout->requestUpdate();
+ return true;
+ }
+ return false;
+}
+
+
+TextEditor::TextMarks DocumentMarker::marksAt(int line) const
+{
+ Q_ASSERT(line >= 1);
+ int blockNumber = line - 1;
+ QTextBlock block = document->findBlockByNumber(blockNumber);
+
+ if (block.isValid()) {
+ if (TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
+ return userData->marks();
+ }
+ return TextMarks();
+}
+
+void DocumentMarker::removeMark(TextEditor::ITextMark *mark)
+{
+ bool needUpdate = false;
+ QTextBlock block = document->begin();
+ while (block.isValid()) {
+ if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData())) {
+ needUpdate |= data->removeMark(mark);
+ }
+ block = block.next();
+ }
+ if (needUpdate)
+ updateMark(0);
+}
+
+
+bool DocumentMarker::hasMark(TextEditor::ITextMark *mark) const
+{
+ QTextBlock block = document->begin();
+ while (block.isValid()) {
+ if (TextBlockUserData *data = static_cast<TextBlockUserData *>(block.userData())) {
+ if (data->hasMark(mark))
+ return true;
+ }
+ block = block.next();
+ }
+ return false;
+}
+
+ITextMarkable *BaseTextEditor::markableInterface() const
+{
+ return baseTextDocument()->documentMarker();
+}
+
+ITextEditable *BaseTextEditor::editableInterface() const
+{
+ if (!d->m_editable) {
+ d->m_editable = const_cast<BaseTextEditor*>(this)->createEditableInterface();
+ connect(this, SIGNAL(textChanged()),
+ d->m_editable, SIGNAL(contentsChanged()));
+ connect(this, SIGNAL(changed()),
+ d->m_editable, SIGNAL(changed()));
+ connect(this,
+ SIGNAL(markRequested(TextEditor::ITextEditor *, int)),
+ d->m_editable,
+ SIGNAL(markRequested(TextEditor::ITextEditor *, int)));
+ }
+ return d->m_editable;
+}
+
+
+void BaseTextEditor::currentEditorChanged(Core::IEditor *editor)
+{
+ if (editor == d->m_editable) {
+ if (d->m_document->hasDecodingError()) {
+ Core::EditorManager::instance()->showEditorInfoBar(QLatin1String(Constants::SELECT_ENCODING),
+ tr("<b>Error:</b> Could not decode \"%1\" with \"%2\"-encoding. Editing not possible.").arg(displayName()).arg(QString::fromLatin1(d->m_document->codec()->name())),
+ tr("Select Encoding"),
+ this, SLOT(selectEncoding()));
+ }
+ }
+}
+
+void BaseTextEditor::selectEncoding()
+{
+ BaseTextDocument *doc = d->m_document;
+ CodecSelector codecSelector(this, doc);
+
+ switch (codecSelector.exec()) {
+ case CodecSelector::Reload:
+ doc->reload(codecSelector.selectedCodec());
+ setReadOnly(d->m_document->hasDecodingError());
+ if (doc->hasDecodingError())
+ currentEditorChanged(Core::EditorManager::instance()->currentEditor());
+ else
+ Core::EditorManager::instance()->hideEditorInfoBar(QLatin1String(Constants::SELECT_ENCODING));
+ break;
+ case CodecSelector::Save:
+ doc->setCodec(codecSelector.selectedCodec());
+ Core::EditorManager::instance()->saveEditor(editableInterface());
+ break;
+ case CodecSelector::Cancel:
+ break;
+ }
+}
+
+
+void DocumentMarker::updateMark(ITextMark *mark)
+{
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document->documentLayout());
+ Q_ASSERT(documentLayout);
+ Q_UNUSED(mark);
+ documentLayout->requestUpdate();
+}
+
+
+void BaseTextEditor::triggerCompletions()
+{
+ emit requestAutoCompletion(editableInterface(), true);
+}
+
+bool BaseTextEditor::createNew(const QString &contents)
+{
+ setPlainText(contents);
+ document()->setModified(false);
+ return true;
+}
+
+bool BaseTextEditor::open(const QString &fileName)
+{
+ if (d->m_document->open(fileName)) {
+ moveCursor(QTextCursor::Start);
+ setReadOnly(d->m_document->hasDecodingError());
+ return true;
+ }
+ return false;
+}
+
+Core::IFile * BaseTextEditor::file()
+{
+ return d->m_document;
+}
+
+void BaseTextEditor::editorContentsChange(int position, int charsRemoved, int charsAdded)
+{
+ d->m_contentsChanged = true;
+
+ // Keep the line numbers and the block information for the text marks updated
+ if (charsRemoved != 0) {
+ d->updateMarksLineNumber();
+ d->updateMarksBlock(document()->findBlock(position));
+ } else {
+ const QTextBlock posBlock = document()->findBlock(position);
+ const QTextBlock nextBlock = document()->findBlock(position + charsAdded);
+ if (posBlock != nextBlock) {
+ d->updateMarksLineNumber();
+ d->updateMarksBlock(posBlock);
+ d->updateMarksBlock(nextBlock);
+ } else {
+ d->updateMarksBlock(posBlock);
+ }
+ }
+}
+
+
+void BaseTextEditor::slotSelectionChanged()
+{
+ bool changed = (d->m_inBlockSelectionMode != d->m_lastEventWasBlockSelectionEvent);
+ d->m_inBlockSelectionMode = d->m_lastEventWasBlockSelectionEvent;
+ if (changed || d->m_inBlockSelectionMode)
+ viewport()->update();
+ if (!d->m_inBlockSelectionMode)
+ d->m_blockSelectionExtraX = 0;
+}
+
+void BaseTextEditor::keyPressEvent(QKeyEvent *e)
+{
+
+ d->clearVisibleCollapsedBlock();
+
+ QKeyEvent *original_e = e;
+ d->m_lastEventWasBlockSelectionEvent = false;
+
+ if (e->key() == Qt::Key_Escape) {
+ e->accept();
+ QTextCursor cursor = textCursor();
+ cursor.clearSelection();
+ setTextCursor(cursor);
+ return;
+ }
+
+ d->m_contentsChanged = false;
+
+ bool ro = isReadOnly();
+
+ if (d->m_inBlockSelectionMode) {
+ if (e == QKeySequence::Cut) {
+ if (!ro) {
+ cut();
+ e->accept();
+ return;
+ }
+ } else if (e == QKeySequence::Delete) {
+ if (!ro) {
+ d->removeBlockSelection();
+ e->accept();
+ return;
+ }
+ }
+ }
+
+
+ if (!ro
+ && (e == QKeySequence::InsertParagraphSeparator
+ || (!d->m_lineSeparatorsAllowed && e == QKeySequence::InsertLineSeparator))
+ ) {
+
+ QTextCursor cursor = textCursor();
+ if (d->m_inBlockSelectionMode)
+ cursor.clearSelection();
+ cursor.insertBlock();
+ if (d->m_document->tabSettings().m_autoIndent) {
+ indent(document(), cursor, QChar::Null);
+ }
+ e->accept();
+ setTextCursor(cursor);
+ return;
+ } else switch (e->key()) {
+
+
+#if 0
+ case Qt::Key_sterling: {
+
+ static bool toggle = false;
+ if ((toggle = !toggle)) {
+ QList<BaseTextEditor::BlockRange> rangeList;
+ rangeList += BaseTextEditor::BlockRange(4, 12);
+ rangeList += BaseTextEditor::BlockRange(15, 19);
+ setIfdefedOutBlocks(rangeList);
+ } else {
+ setIfdefedOutBlocks(QList<BaseTextEditor::BlockRange>());
+ }
+ e->accept();
+ return;
+
+ } break;
+#endif
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ if (ro) break;
+ indentOrUnindent(e->key() == Qt::Key_Tab);
+ e->accept();
+ return;
+ case Qt::Key_Backspace:
+ if (ro) break;
+ if (d->m_document->tabSettings().m_smartBackspace
+ && (e->modifiers() & (Qt::ControlModifier
+ | Qt::ShiftModifier
+ | Qt::AltModifier
+ | Qt::MetaModifier)) == Qt::NoModifier
+ && !textCursor().hasSelection()) {
+ handleBackspaceKey();
+ e->accept();
+ return;
+ }
+ break;
+ case Qt::Key_Home:
+ if (!(e == QKeySequence::MoveToStartOfDocument) && !(e == QKeySequence::SelectStartOfDocument)) {
+ handleHomeKey(e->modifiers() & Qt::ShiftModifier);
+ e->accept();
+ return;
+ }
+ break;
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ if (e->modifiers() & Qt::ControlModifier) {
+ verticalScrollBar()->triggerAction(
+ e->key() == Qt::Key_Up ? QAbstractSlider::SliderSingleStepSub :
+ QAbstractSlider::SliderSingleStepAdd);
+ e->accept();
+ return;
+ }
+ // fall through
+ case Qt::Key_Right:
+ case Qt::Key_Left:
+#ifndef Q_OS_MAC
+ if ((e->modifiers() & (Qt::AltModifier | Qt::ShiftModifier)) == (Qt::AltModifier | Qt::ShiftModifier)) {
+
+ d->m_lastEventWasBlockSelectionEvent = true;
+
+ if (d->m_inBlockSelectionMode) {
+ if (e->key() == Qt::Key_Right && textCursor().atBlockEnd()) {
+ d->m_blockSelectionExtraX++;
+ viewport()->update();
+ e->accept();
+ return;
+ } else if (e->key() == Qt::Key_Left && d->m_blockSelectionExtraX > 0) {
+ d->m_blockSelectionExtraX--;
+ e->accept();
+ viewport()->update();
+ return;
+ }
+ }
+
+ e = new QKeyEvent(
+ e->type(),
+ e->key(),
+ e->modifiers() & ~Qt::AltModifier,
+ e->text(),
+ e->isAutoRepeat(),
+ e->count()
+ );
+ }
+#endif
+ break;
+ case Qt::Key_PageUp:
+ case Qt::Key_PageDown:
+ if (e->modifiers() == Qt::ControlModifier) {
+ verticalScrollBar()->triggerAction(
+ e->key() == Qt::Key_PageUp ? QAbstractSlider::SliderPageStepSub :
+ QAbstractSlider::SliderPageStepAdd);
+ e->accept();
+ return;
+ }
+ break;
+
+ default:
+ if (! ro && d->m_document->tabSettings().m_autoIndent
+ && ! e->text().isEmpty() && isElectricCharacter(e->text().at(0))) {
+ QTextCursor cursor = textCursor();
+ const QString text = e->text();
+ cursor.insertText(text);
+ const QString leftText = cursor.block().text().left(cursor.position() - 1 - cursor.block().position());
+ if (leftText.simplified().isEmpty()) {
+ const QChar typedChar = e->text().at(0);
+ indent(document(), cursor, typedChar);
+ }
+#if 0
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
+ Q_ASSERT(documentLayout);
+ documentLayout->requestUpdate(); // a bit drastic
+ e->accept();
+#endif
+ setTextCursor(cursor);
+ return;
+ }
+ break;
+ }
+
+ if (d->m_inBlockSelectionMode) {
+ QString text = e->text();
+ if (!text.isEmpty() && (text.at(0).isPrint() || text.at(0) == QLatin1Char('\t'))) {
+ d->removeBlockSelection(text);
+ goto skip_event;
+ }
+ }
+
+ QPlainTextEdit::keyPressEvent(e);
+
+skip_event:
+ if (!ro && e->key() == Qt::Key_Delete && d->m_parenthesesMatchingEnabled)
+ slotCursorPositionChanged(); // parentheses matching
+
+ if (!ro && d->m_contentsChanged && !e->text().isEmpty() && e->text().at(0).isPrint())
+ emit requestAutoCompletion(editableInterface(), false);
+
+ if (e != original_e)
+ delete e;
+}
+
+void BaseTextEditor::gotoLine(int line, int column)
+{
+ const int blockNumber = line - 1;
+ const QTextBlock &block = document()->findBlockByNumber(blockNumber);
+ if (block.isValid()) {
+ QTextCursor cursor(block);
+ if (column > 0) {
+ cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor, column);
+ } else {
+ int pos = cursor.position();
+ while (characterAt(pos).category() == QChar::Separator_Space) {
+ ++pos;
+ }
+ cursor.setPosition(pos);
+ }
+ setTextCursor(cursor);
+ centerCursor();
+ }
+}
+
+int BaseTextEditor::position(ITextEditor::PositionOperation posOp, int at) const
+{
+ QTextCursor tc = textCursor();
+
+ if (at != -1)
+ tc.setPosition(at);
+
+ if (posOp == ITextEditor::Current)
+ return tc.position();
+
+ switch (posOp) {
+ case ITextEditor::EndOfLine:
+ tc.movePosition(QTextCursor::EndOfLine);
+ return tc.position();
+ case ITextEditor::StartOfLine:
+ tc.movePosition(QTextCursor::StartOfLine);
+ return tc.position();
+ case ITextEditor::Anchor:
+ if (tc.hasSelection())
+ return tc.anchor();
+ break;
+ case ITextEditor::EndOfDoc:
+ tc.movePosition(QTextCursor::End);
+ return tc.position();
+ default:
+ break;
+ }
+
+ return -1;
+}
+
+void BaseTextEditor::convertPosition(int pos, int *line, int *column) const
+{
+ QTextBlock block = document()->findBlock(pos);
+ if (!block.isValid()) {
+ (*line) = -1;
+ (*column) = -1;
+ } else {
+ (*line) = block.blockNumber() + 1;
+ (*column) = pos - block.position();
+ }
+}
+
+QChar BaseTextEditor::characterAt(int pos) const
+{
+ return document()->characterAt(pos);
+}
+
+bool BaseTextEditor::event(QEvent *e)
+{
+ switch (e->type()) {
+ case QEvent::ShortcutOverride:
+ e->ignore(); // we are a really nice citizen
+ return true;
+ default:
+ break;
+ }
+
+ return QPlainTextEdit::event(e);
+}
+
+void BaseTextEditor::duplicateFrom(BaseTextEditor *editor)
+{
+ if (this == editor)
+ return;
+ setDisplayName(editor->displayName());
+ d->m_revisionsVisible = editor->d->m_revisionsVisible;
+ if (d->m_document == editor->d->m_document)
+ return;
+ d->setupDocumentSignals(editor->d->m_document);
+ d->m_document = editor->d->m_document;
+}
+
+QString BaseTextEditor::displayName() const
+{
+ return d->m_displayName;
+}
+
+void BaseTextEditor::setDisplayName(const QString &title)
+{
+ d->m_displayName = title;
+}
+
+BaseTextDocument *BaseTextEditor::baseTextDocument() const
+{
+ return d->m_document;
+}
+
+void BaseTextEditor::setBaseTextDocument(BaseTextDocument *doc)
+{
+ if (doc) {
+ d->setupDocumentSignals(doc);
+ d->m_document = doc;
+ }
+}
+
+void BaseTextEditor::memorizeCursorPosition()
+{
+ d->m_tempState = saveState();
+}
+
+void BaseTextEditor::restoreCursorPosition()
+{
+ restoreState(d->m_tempState);
+}
+
+QByteArray BaseTextEditor::saveState() const
+{
+ QByteArray state;
+ QDataStream stream(&state, QIODevice::WriteOnly);
+ stream << 0; // version number
+ stream << verticalScrollBar()->value();
+ stream << horizontalScrollBar()->value();
+ int line, column;
+ convertPosition(textCursor().position(), &line, &column);
+ stream << line;
+ stream << column;
+ return state;
+}
+
+bool BaseTextEditor::restoreState(const QByteArray &state)
+{
+ int version;
+ int vval;
+ int hval;
+ int lval;
+ int cval;
+ QDataStream stream(state);
+ stream >> version;
+ stream >> vval;
+ stream >> hval;
+ stream >> lval;
+ stream >> cval;
+ gotoLine(lval, cval);
+ verticalScrollBar()->setValue(vval);
+ horizontalScrollBar()->setValue(hval);
+ return true;
+}
+
+void BaseTextEditor::setDefaultPath(const QString &defaultPath)
+{
+ baseTextDocument()->setDefaultPath(defaultPath);
+}
+
+void BaseTextEditor::setSuggestedFileName(const QString &suggestedFileName)
+{
+ baseTextDocument()->setSuggestedFileName(suggestedFileName);
+}
+
+void BaseTextEditor::setParenthesesMatchingEnabled(bool b)
+{
+ d->m_parenthesesMatchingEnabled = b;
+}
+
+bool BaseTextEditor::isParenthesesMatchingEnabled() const
+{
+ return d->m_parenthesesMatchingEnabled;
+}
+
+void BaseTextEditor::setHighlightCurrentLine(bool b)
+{
+ d->m_highlightCurrentLine = b;
+ slotCursorPositionChanged();
+}
+
+bool BaseTextEditor::highlightCurrentLine() const
+{
+ return d->m_highlightCurrentLine;
+}
+
+void BaseTextEditor::setLineNumbersVisible(bool b)
+{
+ d->m_lineNumbersVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::lineNumbersVisible() const
+{
+ return d->m_lineNumbersVisible;
+}
+
+void BaseTextEditor::setMarksVisible(bool b)
+{
+ d->m_marksVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::marksVisible() const
+{
+ return d->m_marksVisible;
+}
+
+void BaseTextEditor::setRequestMarkEnabled(bool b)
+{
+ d->m_requestMarkEnabled = b;
+}
+
+bool BaseTextEditor::requestMarkEnabled() const
+{
+ return d->m_requestMarkEnabled;
+}
+
+void BaseTextEditor::setLineSeparatorsAllowed(bool b)
+{
+ d->m_lineSeparatorsAllowed = b;
+}
+
+bool BaseTextEditor::lineSeparatorsAllowed() const
+{
+ return d->m_lineSeparatorsAllowed;
+}
+
+
+void BaseTextEditor::setCodeFoldingVisible(bool b)
+{
+ d->m_codeFoldingVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::codeFoldingVisible() const
+{
+ return d->m_codeFoldingVisible;
+}
+
+void BaseTextEditor::setRevisionsVisible(bool b)
+{
+ d->m_revisionsVisible = b;
+ slotUpdateExtraAreaWidth();
+}
+
+bool BaseTextEditor::revisionsVisible() const
+{
+ return d->m_revisionsVisible;
+}
+
+void BaseTextEditor::setVisibleWrapColumn(int column)
+{
+ d->m_visibleWrapColumn = column;
+ viewport()->update();
+}
+
+int BaseTextEditor::visibleWrapColumn() const
+{
+ return d->m_visibleWrapColumn;
+}
+
+void BaseTextEditor::setFontSettings(const TextEditor::FontSettings &fs)
+{
+ const QTextCharFormat textFormat = fs.toTextCharFormat(QLatin1String(Constants::C_TEXT));
+ const QTextCharFormat selectionFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SELECTION));
+ const QTextCharFormat lineNumberFormat = fs.toTextCharFormat(QLatin1String(Constants::C_LINE_NUMBER));
+ const QTextCharFormat searchResultFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_RESULT));
+ const QTextCharFormat searchScopeFormat = fs.toTextCharFormat(QLatin1String(Constants::C_SEARCH_SCOPE));
+ const QTextCharFormat parenthesesFormat = fs.toTextCharFormat(QLatin1String(Constants::C_PARENTHESES));
+ const QTextCharFormat currentLineFormat = fs.toTextCharFormat(QLatin1String(Constants::C_CURRENT_LINE));
+ const QTextCharFormat ifdefedOutFormat = fs.toTextCharFormat(QLatin1String(Constants::C_DISABLED_CODE));
+ QFont font(textFormat.font());
+
+ const QColor foreground = textFormat.foreground().color();
+ const QColor background = textFormat.background().color();
+ QPalette p = palette();
+ p.setColor(QPalette::Text, foreground);
+ p.setColor(QPalette::Foreground, foreground);
+ p.setColor(QPalette::Base, background);
+ p.setColor(QPalette::Highlight, (selectionFormat.background().style() != Qt::NoBrush) ?
+ selectionFormat.background().color() :
+ QApplication::palette().color(QPalette::Highlight));
+ p.setColor(QPalette::HighlightedText, selectionFormat.foreground().color());
+ p.setBrush(QPalette::Inactive, QPalette::Highlight, p.highlight());
+ p.setBrush(QPalette::Inactive, QPalette::HighlightedText, p.highlightedText());
+ setPalette(p);
+ setFont(font);
+ setTabSettings(d->m_document->tabSettings()); // update tabs, they depend on the font
+
+ // Line numbers
+ QPalette ep = d->m_extraArea->palette();
+ ep.setColor(QPalette::Dark, lineNumberFormat.foreground().color());
+ ep.setColor(QPalette::Background, lineNumberFormat.background().style() != Qt::NoBrush ?
+ lineNumberFormat.background().color() : background);
+ d->m_extraArea->setPalette(ep);
+
+ // Search results
+ d->m_searchResultFormat.setBackground(searchResultFormat.background());
+ d->m_searchScopeFormat.setBackground(searchScopeFormat.background());
+ d->m_currentLineFormat.setBackground(currentLineFormat.background());
+
+ // Matching braces
+ d->m_matchFormat.setForeground(parenthesesFormat.foreground());
+ d->m_rangeFormat.setBackground(parenthesesFormat.background());
+
+ // Disabled code
+ d->m_ifdefedOutFormat.setForeground(ifdefedOutFormat.foreground());
+
+ slotUpdateExtraAreaWidth();
+}
+
+void BaseTextEditor::setStorageSettings(const StorageSettings &storageSettings)
+{
+ d->m_document->setStorageSettings(storageSettings);
+}
+
+//--------- BaseTextEditorPrivate -----------
+
+BaseTextEditorPrivate::BaseTextEditorPrivate()
+ :
+ m_contentsChanged(false),
+ m_document(new BaseTextDocument()),
+ m_parenthesesMatchingEnabled(false),
+ m_extraArea(0),
+ m_marksVisible(false),
+ m_codeFoldingVisible(false),
+ m_revisionsVisible(false),
+ m_lineNumbersVisible(true),
+ m_highlightCurrentLine(true),
+ m_requestMarkEnabled(true),
+ m_lineSeparatorsAllowed(false),
+ m_visibleWrapColumn(0),
+ m_editable(0),
+ m_actionHack(0),
+ m_inBlockSelectionMode(false),
+ m_lastEventWasBlockSelectionEvent(false),
+ m_blockSelectionExtraX(0)
+{
+}
+
+BaseTextEditorPrivate::~BaseTextEditorPrivate()
+{
+}
+
+void BaseTextEditorPrivate::setupDocumentSignals(BaseTextDocument *document)
+{
+ BaseTextDocument *oldDocument = q->baseTextDocument();
+ if (oldDocument) {
+ q->disconnect(oldDocument->document(), 0, q, 0);
+ q->disconnect(oldDocument, 0, q, 0);
+ }
+
+ QTextDocument *doc = document->document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ if (!documentLayout) {
+ QTextOption opt = doc->defaultTextOption();
+ opt.setTextDirection(Qt::LeftToRight);
+ opt.setFlags(opt.flags() | QTextOption::IncludeTrailingSpaces
+ | QTextOption::AddSpaceForLineAndParagraphSeparators
+ );
+ doc->setDefaultTextOption(opt);
+ documentLayout = new TextEditDocumentLayout(doc);
+ doc->setDocumentLayout(documentLayout);
+ }
+
+
+ q->setDocument(doc);
+ QObject::connect(documentLayout, SIGNAL(updateBlock(QTextBlock)), q, SLOT(slotUpdateBlockNotify(QTextBlock)));
+ QObject::connect(q, SIGNAL(requestBlockUpdate(QTextBlock)), documentLayout, SIGNAL(updateBlock(QTextBlock)));
+ QObject::connect(doc, SIGNAL(modificationChanged(bool)), q, SIGNAL(changed()));
+ QObject::connect(doc, SIGNAL(contentsChange(int,int,int)), q,
+ SLOT(editorContentsChange(int,int,int)), Qt::DirectConnection);
+ QObject::connect(document, SIGNAL(changed()), q, SIGNAL(changed()));
+ QObject::connect(document, SIGNAL(titleChanged(QString)), q, SLOT(setDisplayName(const QString &)));
+ QObject::connect(document, SIGNAL(aboutToReload()), q, SLOT(memorizeCursorPosition()));
+ QObject::connect(document, SIGNAL(reloaded()), q, SLOT(restoreCursorPosition()));
+ q->slotUpdateExtraAreaWidth();
+}
+
+#ifndef TEXTEDITOR_STANDALONE
+bool BaseTextEditorPrivate::needMakeWritableCheck() const
+{
+ return !m_document->isModified()
+ && !m_document->fileName().isEmpty()
+ && m_document->isReadOnly();
+}
+#endif
+
+bool Parenthesis::hasClosingCollapse(const Parentheses &parentheses)
+{
+ return closeCollapseAtPos(parentheses) >= 0;
+}
+
+
+int Parenthesis::closeCollapseAtPos(const Parentheses &parentheses)
+{
+ int depth = 0;
+ for (int i = 0; i < parentheses.size(); ++i) {
+ const Parenthesis &p = parentheses.at(i);
+ if (p.chr == QLatin1Char('{') || p.chr == QLatin1Char('+')) {
+ ++depth;
+ } else if (p.chr == QLatin1Char('}') || p.chr == QLatin1Char('-')) {
+ if (--depth < 0)
+ return p.pos;
+ }
+ }
+ return -1;
+}
+
+int Parenthesis::collapseAtPos(const Parentheses &parentheses, QChar *character)
+{
+ int result = -1;
+ QChar c;
+
+ int depth = 0;
+ for (int i = 0; i < parentheses.size(); ++i) {
+ const Parenthesis &p = parentheses.at(i);
+ if (p.chr == QLatin1Char('{') || p.chr == QLatin1Char('+')) {
+ if (depth == 0) {
+ result = p.pos;
+ c = p.chr;
+ }
+ ++depth;
+ } else if (p.chr == QLatin1Char('}') || p.chr == QLatin1Char('-')) {
+ if (--depth < 0)
+ depth = 0;
+ result = -1;
+ }
+ }
+ if (result >= 0 && character)
+ *character = c;
+ return result;
+}
+
+
+int TextBlockUserData::collapseAtPos() const
+{
+ return Parenthesis::collapseAtPos(m_parentheses);
+}
+
+
+void TextEditDocumentLayout::setParentheses(const QTextBlock &block, const Parentheses &parentheses)
+{
+ if (parentheses.isEmpty()) {
+ if (TextBlockUserData *userData = testUserData(block))
+ userData->clearParentheses();
+ } else {
+ userData(block)->setParentheses(parentheses);
+ }
+}
+
+Parentheses TextEditDocumentLayout::parentheses(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->parentheses();
+ return Parentheses();
+}
+
+bool TextEditDocumentLayout::hasParentheses(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->hasParentheses();
+ return false;
+}
+
+
+bool TextEditDocumentLayout::setIfdefedOut(const QTextBlock &block)
+{
+ return userData(block)->setIfdefedOut();
+}
+
+bool TextEditDocumentLayout::clearIfdefedOut(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->clearIfdefedOut();
+ return false;
+}
+
+bool TextEditDocumentLayout::ifdefedOut(const QTextBlock &block)
+{
+ if (TextBlockUserData *userData = testUserData(block))
+ return userData->ifdefedOut();
+ return false;
+}
+
+
+TextEditDocumentLayout::TextEditDocumentLayout(QTextDocument *doc)
+ :QPlainTextDocumentLayout(doc) {
+ lastSaveRevision = 0;
+ hasMarks = 0;
+}
+
+TextEditDocumentLayout::~TextEditDocumentLayout()
+{
+}
+
+QRectF TextEditDocumentLayout::blockBoundingRect(const QTextBlock &block) const
+{
+ QRectF r = QPlainTextDocumentLayout::blockBoundingRect(block);
+ return r;
+}
+
+
+bool BaseTextEditor::viewportEvent(QEvent *event)
+{
+ if (event->type() == QEvent::ContextMenu) {
+ const QContextMenuEvent *ce = static_cast<QContextMenuEvent*>(event);
+ if (ce->reason() == QContextMenuEvent::Mouse && !textCursor().hasSelection())
+ setTextCursor(cursorForPosition(ce->pos()));
+ } else if (event->type() == QEvent::ToolTip) {
+ const QHelpEvent *he = static_cast<QHelpEvent*>(event);
+ const QPoint &pos = he->pos();
+
+ // Allow plugins to show tooltips
+ const QTextCursor &c = cursorForPosition(pos);
+ QPoint cursorPos = mapToGlobal(cursorRect(c).bottomRight() + QPoint(1,1));
+ cursorPos.setX(cursorPos.x() + d->m_extraArea->width());
+
+ editableInterface(); // create if necessary
+
+ emit d->m_editable->tooltipRequested(editableInterface(), cursorPos, c.position());
+ return true;
+ }
+ return QPlainTextEdit::viewportEvent(event);
+}
+
+
+void BaseTextEditor::resizeEvent(QResizeEvent *e)
+{
+ QPlainTextEdit::resizeEvent(e);
+ QRect cr = viewport()->rect();
+ d->m_extraArea->setGeometry(
+ QStyle::visualRect(layoutDirection(), cr,
+ QRect(cr.left(), cr.top(), extraAreaWidth(), cr.height())));
+}
+
+QRect BaseTextEditor::collapseBox(const QTextBlock &block)
+{
+ QRectF br = blockBoundingGeometry(block).translated(contentOffset());
+ int collapseBoxWidth = fontMetrics().lineSpacing() + 1;
+ return QRect(d->m_extraArea->width() - collapseBoxWidth + collapseBoxWidth/4,
+ int(br.top()) + collapseBoxWidth/4,
+ 2 * (collapseBoxWidth/4) + 1, 2 * (collapseBoxWidth/4) + 1);
+
+}
+
+QTextBlock BaseTextEditor::collapsedBlockAt(const QPoint &pos, QRect *box) const {
+ QPointF offset(contentOffset());
+ QTextBlock block = firstVisibleBlock();
+ int top = (int)blockBoundingGeometry(block).translated(offset).top();
+ int bottom = top + (int)blockBoundingRect(block).height();
+
+ int viewportHeight = viewport()->height();
+
+ while (block.isValid() && top <= viewportHeight) {
+ QTextBlock nextBlock = block.next();
+ if (block.isVisible() && bottom >= 0) {
+ if (nextBlock.isValid() && !nextBlock.isVisible()) {
+ QTextLayout *layout = block.layout();
+ QTextLine line = layout->lineAt(layout->lineCount()-1);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ lineRect.adjust(0, 0, -1, -1);
+
+ QRectF collapseRect(lineRect.right() + 12,
+ lineRect.top(),
+ fontMetrics().width(QLatin1String(" {...}; ")),
+ lineRect.height());
+ if (collapseRect.contains(pos)) {
+ QTextBlock result = block;
+ if (box)
+ *box = collapseRect.toAlignedRect();
+ return result;
+ } else {
+ block = nextBlock;
+ while (nextBlock.isValid() && !nextBlock.isVisible()) {
+ block = nextBlock;
+ nextBlock = block.next();
+ }
+ }
+ }
+ }
+
+ block = nextBlock;
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ }
+ return QTextBlock();
+}
+
+void BaseTextEditorPrivate::highlightSearchResults(const QTextBlock &block,
+ QVector<QTextLayout::FormatRange> *selections)
+{
+ if (m_searchExpr.isEmpty())
+ return;
+
+ QString text = block.text();
+ text.replace(QChar::Nbsp, QLatin1Char(' '));
+ int idx = -1;
+ while (idx < text.length()) {
+ idx = m_searchExpr.indexIn(text, idx + 1);
+ if (idx < 0)
+ break;
+ int l = m_searchExpr.matchedLength();
+ if ((m_findFlags & QTextDocument::FindWholeWords)
+ && ((idx && text.at(idx-1).isLetterOrNumber())
+ || (idx + l < text.length() && text.at(idx + l).isLetterOrNumber())))
+ continue;
+
+ if (m_findScope.isNull()
+ || (block.position() + idx >= m_findScope.selectionStart()
+ && block.position() + idx + l <= m_findScope.selectionEnd())) {
+ QTextLayout::FormatRange selection;
+ selection.start = idx;
+ selection.length = l;
+ selection.format = m_searchResultFormat;
+ selections->append(selection);
+ }
+ }
+}
+
+
+namespace TextEditor {
+ namespace Internal {
+ struct BlockSelectionData {
+ int selectionIndex;
+ int selectionStart;
+ int selectionEnd;
+ int firstColumn;
+ int lastColumn;
+ };
+
+ }
+}
+
+void BaseTextEditorPrivate::clearBlockSelection()
+{
+ if (m_inBlockSelectionMode) {
+ m_inBlockSelectionMode = false;
+ QTextCursor cursor = q->textCursor();
+ cursor.clearSelection();
+ q->setTextCursor(cursor);
+ }
+}
+
+QString BaseTextEditorPrivate::copyBlockSelection()
+{
+ QString text;
+
+ QTextCursor cursor = q->textCursor();
+ if (!cursor.hasSelection())
+ return text;
+
+ QTextDocument *doc = q->document();
+ int start = cursor.selectionStart();
+ int end = cursor.selectionEnd();
+ QTextBlock startBlock = doc->findBlock(start);
+ int columnA = start - startBlock.position();
+ QTextBlock endBlock = doc->findBlock(end);
+ int columnB = end - endBlock.position();
+ int firstColumn = qMin(columnA, columnB);
+ int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX;
+
+ QTextBlock block = startBlock;
+ for (;;) {
+
+ cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn));
+ cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor);
+ text += cursor.selectedText();
+ if (block == endBlock)
+ break;
+ text += QLatin1Char('\n');
+ block = block.next();
+ }
+
+ return text;
+}
+
+void BaseTextEditorPrivate::removeBlockSelection(const QString &text)
+{
+ QTextCursor cursor = q->textCursor();
+ if (!cursor.hasSelection())
+ return;
+
+ QTextDocument *doc = q->document();
+ int start = cursor.selectionStart();
+ int end = cursor.selectionEnd();
+ QTextBlock startBlock = doc->findBlock(start);
+ int columnA = start - startBlock.position();
+ QTextBlock endBlock = doc->findBlock(end);
+ int columnB = end - endBlock.position();
+ int firstColumn = qMin(columnA, columnB);
+ int lastColumn = qMax(columnA, columnB) + m_blockSelectionExtraX;
+
+ cursor.clearSelection();
+ cursor.beginEditBlock();
+
+ QTextBlock block = startBlock;
+ for (;;) {
+
+ cursor.setPosition(block.position() + qMin(block.length()-1, firstColumn));
+ cursor.setPosition(block.position() + qMin(block.length()-1, lastColumn), QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ if (block == endBlock)
+ break;
+ block = block.next();
+ }
+
+ cursor.setPosition(start);
+ if (!text.isEmpty())
+ cursor.insertText(text);
+ cursor.endEditBlock();
+ q->setTextCursor(cursor);
+}
+
+void BaseTextEditor::paintEvent(QPaintEvent *e)
+{
+ /*
+ Here comes an almost verbatim copy of
+ QPlainTextEdit::paintEvent() so we can adjust the extra
+ selections dynamically to indicate all search results.
+ */
+ //begin QPlainTextEdit::paintEvent()
+
+ QPainter painter(viewport());
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QPointF offset(contentOffset());
+
+ QRect er = e->rect();
+ QRect viewportRect = viewport()->rect();
+
+ // keep right margin clean from full-width selection
+ int maxX = offset.x() + qMax((qreal)viewportRect.width(), documentLayout->documentSize().width())
+ - doc->documentMargin();
+ er.setRight(qMin(er.right(), maxX));
+ painter.setClipRect(er);
+
+ bool editable = !isReadOnly();
+
+ QTextBlock block = firstVisibleBlock();
+
+ QAbstractTextDocumentLayout::PaintContext context = getPaintContext();
+
+
+ if (!d->m_findScope.isNull()) {
+ QAbstractTextDocumentLayout::Selection selection;
+ selection.format.setBackground(d->m_searchScopeFormat.background());
+ selection.cursor = d->m_findScope;
+ context.selections.prepend(selection);
+ }
+
+ BlockSelectionData *blockSelection = 0;
+
+ if (d->m_inBlockSelectionMode
+ && context.selections.count() && context.selections.last().cursor == textCursor()) {
+ blockSelection = new BlockSelectionData;
+ blockSelection->selectionIndex = context.selections.size()-1;
+ const QAbstractTextDocumentLayout::Selection &selection = context.selections[blockSelection->selectionIndex];
+ int start = blockSelection->selectionStart = selection.cursor.selectionStart();
+ int end = blockSelection->selectionEnd = selection.cursor.selectionEnd();
+ QTextBlock block = doc->findBlock(start);
+ int columnA = start - block.position();
+ block = doc->findBlock(end);
+ int columnB = end - block.position();
+ blockSelection->firstColumn = qMin(columnA, columnB);
+ blockSelection->lastColumn = qMax(columnA, columnB) + d->m_blockSelectionExtraX;
+ }
+
+ const QColor baseColor = palette().base().color();
+ const int blendBase = (baseColor.value() > 128) ? 0 : 255;
+ // Darker backgrounds may need a bit more contrast
+ // (this calculation is temporary solution until we have a setting for this color)
+ const int blendFactor = (baseColor.value() > 128) ? 8 : 16;
+ const QColor blendColor(
+ (blendBase * blendFactor + baseColor.blue() * (256 - blendFactor)) / 256,
+ (blendBase * blendFactor + baseColor.green() * (256 - blendFactor)) / 256,
+ (blendBase * blendFactor + baseColor.blue() * (256 - blendFactor)) / 256);
+ if (d->m_visibleWrapColumn > 0) {
+ qreal lineX = fontMetrics().averageCharWidth() * d->m_visibleWrapColumn + offset.x() + 4;
+ painter.fillRect(QRectF(lineX, 0, viewportRect.width() - lineX, viewportRect.height()), blendColor);
+ }
+
+ QTextBlock visibleCollapsedBlock;
+ QPointF visibleCollapsedBlockOffset;
+
+ while (block.isValid()) {
+
+ if (!block.isVisible()) {
+ block = block.next();
+ continue;
+ }
+
+ QRectF r = blockBoundingRect(block).translated(offset);
+ QTextLayout *layout = block.layout();
+
+ QTextOption option = layout->textOption();
+ if (TextEditDocumentLayout::ifdefedOut(block)) {
+ option.setFlags(option.flags() | QTextOption::SuppressColors);
+ painter.setPen(d->m_ifdefedOutFormat.foreground().color());
+ } else {
+ option.setFlags(option.flags() & ~QTextOption::SuppressColors);
+ painter.setPen(context.palette.text().color());
+ }
+ layout->setTextOption(option);
+
+ if (r.bottom() >= er.top() && r.top() <= er.bottom()) {
+
+ int blpos = block.position();
+ int bllen = block.length();
+
+ QVector<QTextLayout::FormatRange> selections;
+ QVector<QTextLayout::FormatRange> selectionsWithText;
+
+ for (int i = 0; i < context.selections.size(); ++i) {
+ const QAbstractTextDocumentLayout::Selection &range = context.selections.at(i);
+ const int selStart = range.cursor.selectionStart() - blpos;
+ const int selEnd = range.cursor.selectionEnd() - blpos;
+ if (selStart < bllen && selEnd > 0
+ && selEnd > selStart) {
+ QTextLayout::FormatRange o;
+ o.start = selStart;
+ o.length = selEnd - selStart;
+ o.format = range.format;
+ if (blockSelection && blockSelection->selectionIndex == i) {
+ o.start = qMin(blockSelection->firstColumn, bllen-1);
+ o.length = qMin(blockSelection->lastColumn, bllen-1) - o.start;
+ }
+ if (o.format.foreground().style() != Qt::NoBrush)
+ selectionsWithText.append(o);
+ else
+ selections.append(o);
+ } else if (!range.cursor.hasSelection() && range.format.hasProperty(QTextFormat::FullWidthSelection)
+ && block.contains(range.cursor.position())) {
+ // for full width selections we don't require an actual selection, just
+ // a position to specify the line. that's more convenience in usage.
+ QTextLayout::FormatRange o;
+ QTextLine l = layout->lineForTextPosition(range.cursor.position() - blpos);
+ o.start = l.textStart();
+ o.length = l.textLength();
+ if (o.start + o.length == bllen - 1)
+ ++o.length; // include newline
+ o.format = range.format;
+ if (o.format.foreground().style() != Qt::NoBrush)
+ selectionsWithText.append(o);
+ else
+ selections.append(o);
+ }
+ }
+ d->highlightSearchResults(block, &selections);
+ selections += selectionsWithText;
+
+ bool drawCursor = ((editable || true) // we want the cursor in read-only mode
+ && context.cursorPosition >= blpos
+ && context.cursorPosition < blpos + bllen);
+
+ bool drawCursorAsBlock = drawCursor && overwriteMode() ;
+
+ if (drawCursorAsBlock) {
+ if (context.cursorPosition == blpos + bllen - 1) {
+ drawCursorAsBlock = false;
+ } else {
+ QTextLayout::FormatRange o;
+ o.start = context.cursorPosition - blpos;
+ o.length = 1;
+ o.format.setForeground(palette().base());
+ o.format.setBackground(palette().text());
+ selections.append(o);
+ }
+ }
+
+
+ layout->draw(&painter, offset, selections, er);
+
+ if ((drawCursor && !drawCursorAsBlock)
+ || (editable && context.cursorPosition < -1
+ && !layout->preeditAreaText().isEmpty())) {
+ int cpos = context.cursorPosition;
+ if (cpos < -1)
+ cpos = layout->preeditAreaPosition() - (cpos + 2);
+ else
+ cpos -= blpos;
+ layout->drawCursor(&painter, offset, cpos, cursorWidth());
+ }
+ }
+
+ offset.ry() += r.height();
+
+ if (offset.y() > viewportRect.height())
+ break;
+ block = block.next();
+ if (!block.isVisible()) {
+ if (block.blockNumber() == d->visibleCollapsedBlockNumber) {
+ visibleCollapsedBlock = block;
+ visibleCollapsedBlockOffset = offset;
+ }
+
+ // invisible blocks do have zero line count
+ block = doc->findBlockByLineNumber(block.firstLineNumber());
+ }
+
+ }
+
+ if (backgroundVisible() && !block.isValid() && offset.y() <= er.bottom()
+ && (centerOnScroll() || verticalScrollBar()->maximum() == verticalScrollBar()->minimum())) {
+ painter.fillRect(QRect(QPoint((int)er.left(), (int)offset.y()), er.bottomRight()), palette().background());
+ }
+
+ //end QPlainTextEdit::paintEvent()
+
+ delete blockSelection;
+
+ offset = contentOffset();
+ block = firstVisibleBlock();
+
+ int top = (int)blockBoundingGeometry(block).translated(offset).top();
+ int bottom = top + (int)blockBoundingRect(block).height();
+
+ QTextCursor cursor = textCursor();
+ bool hasSelection = cursor.hasSelection();
+ int selectionStart = cursor.selectionStart();
+ int selectionEnd = cursor.selectionEnd();
+
+
+ while (block.isValid() && top <= e->rect().bottom()) {
+ QTextBlock nextBlock = block.next();
+ QTextBlock nextVisibleBlock = nextBlock;
+
+ if (!nextVisibleBlock.isVisible())
+ // invisible blocks do have zero line count
+ nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
+ if (block.isVisible() && bottom >= e->rect().top()) {
+ if (d->m_displaySettings.m_visualizeWhitespace) {
+ QTextLayout *layout = block.layout();
+ int lineCount = layout->lineCount();
+ if (lineCount >= 2 || !nextBlock.isValid()) {
+ painter.save();
+ painter.setPen(Qt::lightGray);
+ for (int i = 0; i < lineCount-1; ++i) { // paint line wrap indicator
+ QTextLine line = layout->lineAt(i);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ QChar visualArrow((ushort)0x21b5);
+ painter.drawText(static_cast<int>(lineRect.right()),
+ static_cast<int>(lineRect.top() + line.ascent()), visualArrow);
+ }
+ if (!nextBlock.isValid()) { // paint EOF symbol
+ QTextLine line = layout->lineAt(lineCount-1);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ int h = 4;
+ lineRect.adjust(0, 0, -1, -1);
+ QPainterPath path;
+ QPointF pos(lineRect.topRight() + QPointF(h+4, line.ascent()));
+ path.moveTo(pos);
+ path.lineTo(pos + QPointF(-h, -h));
+ path.lineTo(pos + QPointF(0, -2*h));
+ path.lineTo(pos + QPointF(h, -h));
+ path.closeSubpath();
+ painter.setBrush(painter.pen().color());
+ painter.drawPath(path);
+ }
+ painter.restore();
+ }
+ }
+
+ if (nextBlock.isValid() && !nextBlock.isVisible()) {
+
+ bool selectThis = (hasSelection
+ && nextBlock.position() >= selectionStart
+ && nextBlock.position() < selectionEnd);
+ if (selectThis) {
+ painter.save();
+ painter.setBrush(palette().highlight());
+ }
+
+ QTextLayout *layout = block.layout();
+ QTextLine line = layout->lineAt(layout->lineCount()-1);
+ QRectF lineRect = line.naturalTextRect().translated(offset.x(), top);
+ lineRect.adjust(0, 0, -1, -1);
+
+ QRectF collapseRect(lineRect.right() + 12,
+ lineRect.top(),
+ fontMetrics().width(QLatin1String(" {...}; ")),
+ lineRect.height());
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.translate(.5, .5);
+ painter.drawRoundedRect(collapseRect.adjusted(0, 0, 0, -1), 3, 3);
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ painter.translate(-.5, -.5);
+
+ QString replacement = QLatin1String("...");
+
+ QTextBlock info = block;
+ if (block.userData()
+ && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == TextBlockUserData::CollapseAfter)
+ ;
+ else if (block.next().userData()
+ && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
+ == TextBlockUserData::CollapseThis) {
+ replacement.prepend(nextBlock.text().trimmed().left(1));
+ info = nextBlock;
+ }
+
+
+ block = nextVisibleBlock.previous();
+ if (!block.isValid())
+ block = doc->lastBlock();
+
+ if (info.userData()
+ && static_cast<TextBlockUserData*>(info.userData())->collapseIncludesClosure()) {
+ QString right = block.text().trimmed();
+ if (right.endsWith(QLatin1Char(';'))) {
+ right.chop(1);
+ right = right.trimmed();
+ replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+ replacement.append(QLatin1Char(';'));
+ } else {
+ replacement.append(right.right(right.endsWith(QLatin1Char('/')) ? 2 : 1));
+ }
+ }
+ if (selectThis)
+ painter.setPen(palette().highlightedText().color());
+ painter.drawText(collapseRect, Qt::AlignCenter, replacement);
+ if (selectThis)
+ painter.restore();
+ }
+ }
+
+ block = nextVisibleBlock;
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ }
+
+ if (visibleCollapsedBlock.isValid() ) {
+ int margin = doc->documentMargin();
+ qreal maxWidth = 0;
+ qreal blockHeight = 0;
+ QTextBlock b = visibleCollapsedBlock;
+
+ while (!b.isVisible() && visibleCollapsedBlockOffset.y() + blockHeight <= e->rect().bottom()) {
+ b.setVisible(true); // make sure block bounding rect works
+ QRectF r = blockBoundingRect(b).translated(visibleCollapsedBlockOffset);
+
+ QTextLayout *layout = b.layout();
+ for (int i = layout->lineCount()-1; i >= 0; --i)
+ maxWidth = qMax(maxWidth, layout->lineAt(i).naturalTextWidth() + margin);
+
+ blockHeight += r.height();
+
+ b.setVisible(false); // restore previous state
+ b = b.next();
+ }
+
+ painter.save();
+ painter.setRenderHint(QPainter::Antialiasing, true);
+ painter.translate(.5, .5);
+ QColor color = blendColor;
+// color.setAlpha(240); // someone thinks alpha blending looks messy
+ painter.setBrush(color);
+ painter.drawRoundedRect(QRectF(visibleCollapsedBlockOffset.x(),
+ visibleCollapsedBlockOffset.y(),
+ maxWidth, blockHeight).adjusted(0, 0, 1, 1), 3, 3);
+ painter.restore();
+
+ QTextBlock end = b;
+ b = visibleCollapsedBlock;
+ while (b != end) {
+ b.setVisible(true); // make sure block bounding rect works
+ QRectF r = blockBoundingRect(b).translated(visibleCollapsedBlockOffset);
+ QTextLayout *layout = b.layout();
+ QVector<QTextLayout::FormatRange> selections;
+ d->highlightSearchResults(b, &selections);
+ layout->draw(&painter, visibleCollapsedBlockOffset, selections, er);
+
+ b.setVisible(false); // restore previous state
+ visibleCollapsedBlockOffset.ry() += r.height();
+ b = b.next();
+ }
+ }
+
+
+ if (d->m_visibleWrapColumn > 0) {
+ qreal lineX = fontMetrics().width('x') * d->m_visibleWrapColumn + offset.x() + 4;
+ const QColor bg = palette().base().color();
+ QColor col = (bg.value() > 128) ? Qt::black : Qt::white;
+ col.setAlpha(32);
+ painter.setPen(QPen(col, 0));
+ painter.drawLine(QPointF(lineX, 0), QPointF(lineX, viewport()->height()));
+ }
+}
+
+void BaseTextEditor::slotUpdateExtraAreaWidth()
+{
+ if (isLeftToRight())
+ setViewportMargins(extraAreaWidth(), 0, 0, 0);
+ else
+ setViewportMargins(0, 0, extraAreaWidth(), 0);
+}
+
+
+QWidget *BaseTextEditor::extraArea() const
+{
+ return d->m_extraArea;
+}
+
+int BaseTextEditor::extraAreaWidth(int *markWidthPtr) const
+{
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
+ if (!documentLayout)
+ return 0;
+
+ if (!d->m_marksVisible && documentLayout->hasMarks)
+ d->m_marksVisible = true;
+
+ int space = 0;
+ const QFontMetrics fm(d->m_extraArea->fontMetrics());
+
+ if (d->m_lineNumbersVisible) {
+ int digits = 2;
+ int max = qMax(1, blockCount());
+ while (max >= 100) {
+ max /= 10;
+ ++digits;
+ }
+ space += fm.width(QLatin1Char('9')) * digits;
+ }
+ int markWidth = 0;
+
+ if (d->m_marksVisible) {
+ markWidth += fm.lineSpacing();
+// if (documentLayout->doubleMarkCount)
+// markWidth += fm.lineSpacing() / 3;
+ space += markWidth;
+ } else {
+ space += 2;
+ }
+
+ if (markWidthPtr)
+ *markWidthPtr = markWidth;
+
+ space += 4;
+
+ if (d->m_codeFoldingVisible)
+ space += fm.lineSpacing();
+ return space;
+}
+
+void BaseTextEditor::slotModificationChanged(bool m)
+{
+ if (m)
+ return;
+
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ int oldLastSaveRevision = documentLayout->lastSaveRevision;
+ documentLayout->lastSaveRevision = doc->revision();
+
+ if (oldLastSaveRevision != documentLayout->lastSaveRevision) {
+ QTextBlock block = doc->begin();
+ while (block.isValid()) {
+ if (block.revision() < 0 || block.revision() != oldLastSaveRevision) {
+ block.setRevision(-documentLayout->lastSaveRevision - 1);
+ } else {
+ block.setRevision(documentLayout->lastSaveRevision);
+ }
+ block = block.next();
+ }
+ }
+ d->m_extraArea->update();
+}
+
+void BaseTextEditor::slotUpdateBlockNotify(const QTextBlock &block)
+{
+ static bool blockRecursion = false;
+ if (blockRecursion)
+ return;
+ if (block.previous().isValid() && block.userState() != block.previous().userState()) {
+ /* The syntax highlighting state changes. This opens up for
+ the possibility that the paragraph has braces that support
+ code folding. In this case, do the save thing and also
+ update the previous block, which might contain a collapse
+ box which now is invalid.*/
+ blockRecursion = true;
+ emit requestBlockUpdate(block.previous());
+ blockRecursion = false;
+ }
+}
+
+void BaseTextEditor::slotUpdateRequest(const QRect &r, int dy)
+{
+ if (dy)
+ d->m_extraArea->scroll(0, dy);
+ else if (r.width() > 4) { // wider than cursor width, not just cursor blinking
+ d->m_extraArea->update(0, r.y(), d->m_extraArea->width(), r.height());
+ }
+
+ if (r.contains(viewport()->rect()))
+ slotUpdateExtraAreaWidth();
+}
+
+
+void BaseTextEditor::setCollapseIndicatorAlpha(int alpha)
+{
+ d->extraAreaCollapseAlpha = alpha;
+ d->m_extraArea->update();
+}
+
+void BaseTextEditor::extraAreaPaintEvent(QPaintEvent *e)
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QPalette pal = d->m_extraArea->palette();
+ pal.setCurrentColorGroup(QPalette::Active);
+ QPainter painter(d->m_extraArea);
+ QFontMetrics fm(painter.fontMetrics());
+ int fmLineSpacing = fm.lineSpacing();
+
+ int markWidth = 0;
+ if (d->m_marksVisible)
+ markWidth += fm.lineSpacing();
+// if (documentLayout->doubleMarkCount)
+// markWidth += fm.lineSpacing() / 3;
+
+ const int collapseBoxWidth = d->m_codeFoldingVisible ? fmLineSpacing + 1: 0;
+ const int extraAreaWidth = d->m_extraArea->width() - collapseBoxWidth;
+
+ painter.fillRect(e->rect(), pal.color(QPalette::Base));
+ painter.fillRect(e->rect().intersected(QRect(0, 0, extraAreaWidth, INT_MAX)),
+ pal.color(QPalette::Background));
+
+
+ QTextBlock block = firstVisibleBlock();
+ int blockNumber = block.blockNumber();
+ int top = (int)blockBoundingGeometry(block).translated(contentOffset()).top();
+ int bottom = top;
+
+ int extraAreaHighlightCollapseEndBlockNumber = -1;
+
+ int extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
+ if (extraAreaHighlightCollapseBlockNumber < 0) {
+ extraAreaHighlightCollapseBlockNumber = d->extraAreaHighlightFadingBlockNumber;
+ }
+
+ if (extraAreaHighlightCollapseBlockNumber >= 0 ) {
+ QTextBlock highlightBlock = doc->findBlockByNumber(extraAreaHighlightCollapseBlockNumber);
+ if (highlightBlock.isValid() && highlightBlock.next().isValid() && highlightBlock.next().isVisible())
+ extraAreaHighlightCollapseEndBlockNumber = TextBlockUserData::testCollapse(highlightBlock).blockNumber();
+ else
+ extraAreaHighlightCollapseEndBlockNumber = extraAreaHighlightCollapseBlockNumber;
+ }
+
+
+ while (block.isValid() && top <= e->rect().bottom()) {
+
+ bool collapseThis = false;
+ bool collapseAfter = false;
+ bool hasClosingCollapse = false;
+
+
+ top = bottom;
+ bottom = top + (int)blockBoundingRect(block).height();
+ QTextBlock nextBlock = block.next();
+
+ QTextBlock nextVisibleBlock = nextBlock;
+ int nextVisibleBlockNumber = blockNumber + 1;
+
+ if (!nextVisibleBlock.isVisible()) {
+ // invisible blocks do have zero line count
+ nextVisibleBlock = doc->findBlockByLineNumber(nextVisibleBlock.firstLineNumber());
+ nextVisibleBlockNumber = nextVisibleBlock.blockNumber();
+ }
+
+ painter.setPen(pal.color(QPalette::Dark));
+
+ if (d->m_codeFoldingVisible || d->m_marksVisible) {
+ painter.save();
+ painter.setRenderHint(QPainter::Antialiasing, false);
+
+ int previousBraceDepth = block.previous().userState();
+ if (previousBraceDepth >= 0)
+ previousBraceDepth >>= 8;
+ else
+ previousBraceDepth = 0;
+
+ int braceDepth = block.userState();
+ if (!nextBlock.isVisible()) {
+ QTextBlock lastInvisibleBlock = nextVisibleBlock.previous();
+ if (!lastInvisibleBlock.isValid())
+ lastInvisibleBlock = doc->lastBlock();
+ braceDepth = lastInvisibleBlock.userState();
+ }
+ if (braceDepth >= 0)
+ braceDepth >>= 8;
+ else
+ braceDepth = 0;
+
+ if (TextBlockUserData *userData = static_cast<TextBlockUserData*>(block.userData())) {
+ if (d->m_marksVisible) {
+ int xoffset = 0;
+ foreach (ITextMark *mrk, userData->marks()) {
+ int x = 0;
+ int radius = fmLineSpacing - 1;
+ QRect r(x + xoffset, top, radius, radius);
+ mrk->icon().paint(&painter, r, Qt::AlignCenter);
+ xoffset += 2;
+ }
+ }
+
+ collapseAfter = (userData->collapseMode() == TextBlockUserData::CollapseAfter);
+ collapseThis = (userData->collapseMode() == TextBlockUserData::CollapseThis);
+ hasClosingCollapse = userData->hasClosingCollapse() && (previousBraceDepth > 0);
+ }
+
+ if (d->m_codeFoldingVisible) {
+ const QRect box(extraAreaWidth + collapseBoxWidth/4, top + collapseBoxWidth/4,
+ 2 * (collapseBoxWidth/4) + 1, 2 * (collapseBoxWidth/4) + 1);
+ const QPoint boxCenter = box.center();
+
+ QColor textColorAlpha = pal.text().color();
+ textColorAlpha.setAlpha(d->extraAreaCollapseAlpha);
+ QColor textColorInactive = pal.text().color();
+ textColorInactive.setAlpha(100);
+ QColor textColor = pal.text().color();
+ textColor.setAlpha(qMax(textColorInactive.alpha(), d->extraAreaCollapseAlpha));
+
+ const QPen pen( (blockNumber >= extraAreaHighlightCollapseBlockNumber
+ && blockNumber <= extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+ const QPen boxPen((blockNumber == extraAreaHighlightCollapseBlockNumber) ?
+ textColor : textColorInactive);
+ const QPen endPen((blockNumber == extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+ const QPen previousPen((blockNumber-1 >= extraAreaHighlightCollapseBlockNumber
+ && blockNumber-1 < extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+ const QPen nextPen((blockNumber+1 > extraAreaHighlightCollapseBlockNumber
+ && blockNumber+1 <= extraAreaHighlightCollapseEndBlockNumber) ?
+ textColorAlpha : pal.base().color());
+
+ TextBlockUserData *nextBlockUserData = TextEditDocumentLayout::testUserData(nextBlock);
+
+ bool collapseNext = nextBlockUserData
+ && nextBlockUserData->collapseMode()
+ == TextBlockUserData::CollapseThis;
+
+ bool nextHasClosingCollapse = nextBlockUserData
+ && nextBlockUserData->hasClosingCollapseInside();
+
+ bool drawBox = ((collapseAfter || collapseNext) && !nextHasClosingCollapse);
+
+ if (braceDepth || (collapseNext && nextBlock.isVisible())) {
+ painter.setPen((hasClosingCollapse || !nextBlock.isVisible())? nextPen : pen);
+ painter.drawLine(boxCenter.x(), boxCenter.y(), boxCenter.x(), bottom - 1);
+ }
+
+ if (previousBraceDepth || collapseThis) {
+ painter.setPen((collapseAfter || collapseNext) ? previousPen : pen);
+ painter.drawLine(boxCenter.x(), top, boxCenter.x(), boxCenter.y());
+ }
+
+ if (drawBox) {
+ painter.setPen(boxPen);
+ painter.setBrush(pal.base());
+ painter.drawRect(box.adjusted(0, 0, -1, -1));
+ if (!nextBlock.isVisible())
+ painter.drawLine(boxCenter.x(), box.top() + 2, boxCenter.x(), box.bottom() - 2);
+ painter.drawLine(box.left() + 2, boxCenter.y(), box.right() - 2, boxCenter.y());
+ } else if (hasClosingCollapse || collapseAfter || collapseNext) {
+ painter.setPen(endPen);
+ painter.drawLine(boxCenter.x() + 1, boxCenter.y(), box.right() - 1, boxCenter.y());
+ }
+
+ }
+
+ painter.restore();
+ }
+
+
+ if (d->m_revisionsVisible && block.revision() != documentLayout->lastSaveRevision) {
+ painter.save();
+ painter.setRenderHint(QPainter::Antialiasing, false);
+ if (block.revision() < 0)
+ painter.setPen(QPen(Qt::darkGreen, 2));
+ else
+ painter.setPen(QPen(Qt::red, 2));
+ painter.drawLine(extraAreaWidth-1, top, extraAreaWidth-1, bottom-1);
+ painter.restore();
+ }
+
+ if (d->m_lineNumbersVisible) {
+ const QString &number = QString::number(blockNumber + 1);
+ painter.drawText(markWidth, top, extraAreaWidth - markWidth - 4, fm.height(), Qt::AlignRight, number);
+ }
+
+ block = nextVisibleBlock;
+ blockNumber = nextVisibleBlockNumber;
+ }
+}
+
+void BaseTextEditor::timerEvent(QTimerEvent *e)
+{
+ if (e->timerId() == d->autoScrollTimer.timerId()) {
+ const QPoint globalPos = QCursor::pos();
+ const QPoint pos = d->m_extraArea->mapFromGlobal(globalPos);
+ QRect visible = d->m_extraArea->rect();
+ verticalScrollBar()->triggerAction( pos.y() < visible.center().y() ?
+ QAbstractSlider::SliderSingleStepSub
+ : QAbstractSlider::SliderSingleStepAdd);
+ QMouseEvent ev(QEvent::MouseMove, pos, globalPos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
+ extraAreaMouseEvent(&ev);
+ int delta = qMax(pos.y() - visible.top(), visible.bottom() - pos.y()) - visible.height();
+ if (delta < 7)
+ delta = 7;
+ int timeout = 4900 / (delta * delta);
+ d->autoScrollTimer.start(timeout, this);
+
+ } else if (e->timerId() == d->collapsedBlockTimer.timerId()) {
+ d->visibleCollapsedBlockNumber = d->suggestedVisibleCollapsedBlockNumber;
+ d->suggestedVisibleCollapsedBlockNumber = -1;
+ d->collapsedBlockTimer.stop();
+ viewport()->update();
+ }
+ QPlainTextEdit::timerEvent(e);
+}
+
+
+void BaseTextEditorPrivate::clearVisibleCollapsedBlock()
+{
+ if (suggestedVisibleCollapsedBlockNumber) {
+ suggestedVisibleCollapsedBlockNumber = -1;
+ collapsedBlockTimer.stop();
+ }
+ if (visibleCollapsedBlockNumber >= 0) {
+ visibleCollapsedBlockNumber = -1;
+ q->viewport()->update();
+ }
+}
+
+
+void BaseTextEditor::mouseMoveEvent(QMouseEvent *e)
+{
+ d->m_lastEventWasBlockSelectionEvent = (e->modifiers() & Qt::AltModifier);
+ if (e->buttons() == 0) {
+ QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
+ int blockNumber = collapsedBlock.next().blockNumber();
+ if (blockNumber < 0) {
+ d->clearVisibleCollapsedBlock();
+ } else if (blockNumber != d->visibleCollapsedBlockNumber) {
+ d->suggestedVisibleCollapsedBlockNumber = blockNumber;
+ d->collapsedBlockTimer.start(40, this);
+ }
+ viewport()->setCursor(collapsedBlock.isValid() ? Qt::PointingHandCursor : Qt::IBeamCursor);
+ } else {
+ QPlainTextEdit::mouseMoveEvent(e);
+ }
+ if (d->m_lastEventWasBlockSelectionEvent && d->m_inBlockSelectionMode) {
+ if (textCursor().atBlockEnd()) {
+ d->m_blockSelectionExtraX = qMax(0, e->pos().x() - cursorRect().center().x()) / fontMetrics().width(QLatin1Char('x'));
+ } else {
+ d->m_blockSelectionExtraX = 0;
+ }
+ }
+}
+
+void BaseTextEditor::mousePressEvent(QMouseEvent *e)
+{
+ if (e->button() == Qt::LeftButton) {
+ d->clearBlockSelection(); // just in case, otherwise we might get strange drag and drop
+
+ QTextBlock collapsedBlock = collapsedBlockAt(e->pos());
+ if (collapsedBlock.isValid()) {
+ toggleBlockVisible(collapsedBlock);
+ viewport()->setCursor(Qt::IBeamCursor);
+ }
+ }
+ QPlainTextEdit::mousePressEvent(e);
+}
+
+void BaseTextEditor::extraAreaLeaveEvent(QEvent *)
+{
+ if (d->extraAreaHighlightCollapseBlockNumber >= 0) {
+ d->extraAreaHighlightFadingBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
+ d->extraAreaHighlightCollapseBlockNumber = -1; // missing mouse move event from Qt
+ d->extraAreaTimeLine->setDirection(QTimeLine::Backward);
+ if (d->extraAreaTimeLine->state() != QTimeLine::Running)
+ d->extraAreaTimeLine->start();
+ }
+}
+
+void BaseTextEditor::extraAreaMouseEvent(QMouseEvent *e)
+{
+ QTextCursor cursor = cursorForPosition(QPoint(0, e->pos().y()));
+ cursor.setPosition(cursor.block().position());
+
+ int markWidth;
+ extraAreaWidth(&markWidth);
+
+ if (e->type() == QEvent::MouseMove && e->buttons() == 0) { // mouse tracking
+ int highlightBlockNumber = d->extraAreaHighlightCollapseBlockNumber;
+ d->extraAreaHighlightCollapseBlockNumber = -1;
+ if (TextBlockUserData::canCollapse(cursor.block())
+ && !TextBlockUserData::hasClosingCollapseInside(cursor.block().next())
+ && collapseBox(cursor.block()).contains(e->pos()))
+ d->extraAreaHighlightCollapseBlockNumber = cursor.blockNumber();
+
+ bool hand = (e->pos().x() <= markWidth || d->extraAreaHighlightCollapseBlockNumber >= 0);
+ if (hand != (d->m_extraArea->cursor().shape() == Qt::PointingHandCursor))
+ d->m_extraArea->setCursor(hand ? Qt::PointingHandCursor : Qt::ArrowCursor);
+
+ if (highlightBlockNumber != d->extraAreaHighlightCollapseBlockNumber) {
+ d->extraAreaTimeLine->stop();
+ d->extraAreaTimeLine->setDirection(d->extraAreaHighlightCollapseBlockNumber >= 0?
+ QTimeLine::Forward : QTimeLine::Backward);
+ if (d->extraAreaTimeLine->direction() == QTimeLine::Backward)
+ d->extraAreaHighlightFadingBlockNumber = highlightBlockNumber;
+ else
+ d->extraAreaHighlightFadingBlockNumber = -1;
+ if (d->extraAreaTimeLine->state() != QTimeLine::Running)
+ d->extraAreaTimeLine->start();
+ }
+ }
+
+
+ if (e->type() == QEvent::MouseButtonPress || e->type() == QEvent::MouseButtonDblClick) {
+ if (e->button() == Qt::LeftButton) {
+ if (TextBlockUserData::canCollapse(cursor.block())
+ && !TextBlockUserData::hasClosingCollapseInside(cursor.block().next())
+ && collapseBox(cursor.block()).contains(e->pos())) {
+ setTextCursor(cursor);
+ toggleBlockVisible(cursor.block());
+ } else if (e->pos().x() > markWidth) {
+ QTextCursor selection = cursor;
+ selection.setVisualNavigation(true);
+ d->extraAreaSelectionAnchorBlockNumber = selection.blockNumber();
+ selection.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ selection.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+ setTextCursor(selection);
+ } else {
+ d->extraAreaToggleMarkBlockNumber = cursor.blockNumber();
+ }
+ }
+ } else if (d->extraAreaSelectionAnchorBlockNumber >= 0) {
+ QTextCursor selection = cursor;
+ selection.setVisualNavigation(true);
+ if (e->type() == QEvent::MouseMove) {
+ QTextBlock anchorBlock = document()->findBlockByNumber(d->extraAreaSelectionAnchorBlockNumber);
+ selection.setPosition(anchorBlock.position());
+ if (cursor.blockNumber() < d->extraAreaSelectionAnchorBlockNumber) {
+ selection.movePosition(QTextCursor::EndOfBlock);
+ selection.movePosition(QTextCursor::Right);
+ }
+ selection.setPosition(cursor.block().position(), QTextCursor::KeepAnchor);
+ if (cursor.blockNumber() >= d->extraAreaSelectionAnchorBlockNumber) {
+ selection.movePosition(QTextCursor::EndOfBlock, QTextCursor::KeepAnchor);
+ selection.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor);
+ }
+
+ if (e->pos().y() >= 0 && e->pos().y() <= d->m_extraArea->height())
+ d->autoScrollTimer.stop();
+ else if (!d->autoScrollTimer.isActive())
+ d->autoScrollTimer.start(100, this);
+
+ } else {
+ d->autoScrollTimer.stop();
+ d->extraAreaSelectionAnchorBlockNumber = -1;
+ return;
+ }
+ setTextCursor(selection);
+ } else if (d->extraAreaToggleMarkBlockNumber >= 0 && d->m_marksVisible && d->m_requestMarkEnabled) {
+ if (e->type() == QEvent::MouseButtonRelease && e->button() == Qt::LeftButton) {
+ int n = d->extraAreaToggleMarkBlockNumber;
+ d->extraAreaToggleMarkBlockNumber = -1;
+ if (cursor.blockNumber() == n) {
+ int line = n + 1;
+ emit markRequested(editableInterface(), line);
+ }
+ }
+ }
+}
+
+void BaseTextEditor::slotCursorPositionChanged()
+{
+ QList<QTextEdit::ExtraSelection> extraSelections;
+
+ if (d->m_highlightCurrentLine) {
+ QTextEdit::ExtraSelection sel;
+ sel.format.setBackground(d->m_currentLineFormat.background());
+ sel.format.setProperty(QTextFormat::FullWidthSelection, true);
+ sel.cursor = textCursor();
+ sel.cursor.clearSelection();
+ extraSelections.append(sel);
+ }
+
+ if (d->m_parenthesesMatchingEnabled)
+ d->m_parenthesesMatchingTimer->start(50);
+
+ d->m_extraSelections = extraSelections;
+ setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections);
+}
+
+QTextBlock TextBlockUserData::testCollapse(const QTextBlock& block)
+{
+ QTextBlock info = block;
+ if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter)
+ ;
+ else if (block.next().userData()
+ && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
+ == TextBlockUserData::CollapseThis)
+ info = block.next();
+ else
+ return QTextBlock();
+ int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos();
+ if (pos < 0)
+ return QTextBlock();
+ QTextCursor cursor(info);
+ cursor.setPosition(cursor.position() + pos);
+ matchCursorForward(&cursor);
+ return cursor.block();
+}
+
+void TextBlockUserData::doCollapse(const QTextBlock& block, bool visible)
+{
+ QTextBlock info = block;
+ if (block.userData() && static_cast<TextBlockUserData*>(block.userData())->collapseMode() == CollapseAfter)
+ ;
+ else if (block.next().userData()
+ && static_cast<TextBlockUserData*>(block.next().userData())->collapseMode()
+ == TextBlockUserData::CollapseThis)
+ info = block.next();
+ else {
+ if (visible && !block.next().isVisible()) {
+ // no match, at least unfold!
+ QTextBlock b = block.next();
+ while (b.isValid() && !b.isVisible()) {
+ b.setVisible(true);
+ b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
+ b = b.next();
+ }
+ }
+ return;
+ }
+ int pos = static_cast<TextBlockUserData*>(info.userData())->collapseAtPos();
+ if (pos < 0)
+ return;
+ QTextCursor cursor(info);
+ cursor.setPosition(cursor.position() + pos);
+ if (matchCursorForward(&cursor) != Match) {
+ if (visible) {
+ // no match, at least unfold!
+ QTextBlock b = block.next();
+ while (b.isValid() && !b.isVisible()) {
+ b.setVisible(true);
+ b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
+ b = b.next();
+ }
+ }
+ return;
+ }
+
+ QTextBlock b = block.next();
+ while (b < cursor.block()) {
+ b.setVisible(visible);
+ b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
+ if (visible) {
+ TextBlockUserData *data = canCollapse(b);
+ if (data && data->collapsed()) {
+ QTextBlock end = testCollapse(b);
+ if (data->collapseIncludesClosure())
+ end = end.next();
+ if (end.isValid()) {
+ b = end;
+ continue;
+ }
+ }
+ }
+ b = b.next();
+ }
+
+ bool collapseIncludesClosure = hasClosingCollapseAtEnd(b);
+ if (collapseIncludesClosure) {
+ b.setVisible(visible);
+ b.setLineCount(visible ? qMax(1, b.layout()->lineCount()) : 0);
+ }
+ static_cast<TextBlockUserData*>(info.userData())->setCollapseIncludesClosure(collapseIncludesClosure);
+ static_cast<TextBlockUserData*>(info.userData())->setCollapsed(!block.next().isVisible());
+
+}
+
+
+void BaseTextEditor::ensureCursorVisible()
+{
+ QTextBlock block = textCursor().block();
+ if (!block.isVisible()) {
+ while (!block.isVisible() && block.previous().isValid())
+ block = block.previous();
+ toggleBlockVisible(block);
+ }
+ QPlainTextEdit::ensureCursorVisible();
+}
+
+void BaseTextEditor::toggleBlockVisible(const QTextBlock &block)
+{
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(document()->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ bool visible = block.next().isVisible();
+ TextBlockUserData::doCollapse(block, !visible);
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+}
+
+
+const TabSettings &BaseTextEditor::tabSettings() const
+{
+ return d->m_document->tabSettings();
+}
+
+const DisplaySettings &BaseTextEditor::displaySettings() const
+{
+ return d->m_displaySettings;
+}
+
+
+
+void BaseTextEditor::indentOrUnindent(bool doIndent)
+{
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+
+ int pos = cursor.position();
+ const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings();
+
+
+ QTextDocument *doc = document();
+ if (!cursor.hasSelection()
+ || (doc->findBlock(cursor.selectionStart()) == doc->findBlock(cursor.selectionEnd()) )) {
+ cursor.removeSelectedText();
+ QTextBlock block = cursor.block();
+ QString text = block.text();
+ int indentPosition = (cursor.position() - block.position());;
+ int spaces = tabSettings.spacesLeftFromPosition(text, indentPosition);
+ int startColumn = tabSettings.columnAt(text, indentPosition - spaces);
+ int targetColumn = tabSettings.indentedColumn(tabSettings.columnAt(text, indentPosition), doIndent);
+
+ cursor.setPosition(block.position() + indentPosition);
+ cursor.setPosition(block.position() + indentPosition - spaces, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ cursor.insertText(tabSettings.indentationString(startColumn, targetColumn));
+ } else {
+ int anchor = cursor.anchor();
+ int start = qMin(anchor, pos);
+ int end = qMax(anchor, pos);
+
+ QTextBlock startBlock = doc->findBlock(start);
+ QTextBlock endBlock = doc->findBlock(end-1).next();
+
+ for (QTextBlock block = startBlock; block != endBlock; block = block.next()) {
+ QString text = block.text();
+ int indentPosition = tabSettings.lineIndentPosition(text);
+ if (!doIndent && !indentPosition)
+ indentPosition = tabSettings.firstNonSpace(text);
+ int targetColumn = tabSettings.indentedColumn(tabSettings.columnAt(text, indentPosition), doIndent);
+ cursor.setPosition(block.position() + indentPosition);
+ cursor.insertText(tabSettings.indentationString(0, targetColumn));
+ cursor.setPosition(block.position());
+ cursor.setPosition(block.position() + indentPosition, QTextCursor::KeepAnchor);
+ cursor.removeSelectedText();
+ }
+ }
+
+ cursor.endEditBlock();
+}
+
+void BaseTextEditor::handleHomeKey(bool anchor)
+{
+ QTextCursor cursor = textCursor();
+ QTextCursor::MoveMode mode = QTextCursor::MoveAnchor;
+
+ if (anchor)
+ mode = QTextCursor::KeepAnchor;
+
+ const int initpos = cursor.position();
+ int pos = cursor.block().position();
+ QChar character = characterAt(pos);
+ const QLatin1Char tab = QLatin1Char('\t');
+
+ while (character == tab || character.category() == QChar::Separator_Space) {
+ ++pos;
+ character = characterAt(pos);
+ }
+
+ // Go to the start of the block when we're already at the start of the text
+ if (pos == initpos)
+ pos = cursor.block().position();
+
+ cursor.setPosition(pos, mode);
+ setTextCursor(cursor);
+}
+
+void BaseTextEditor::handleBackspaceKey()
+{
+ QTextCursor cursor = textCursor();
+ Q_ASSERT(!cursor.hasSelection());
+
+ const TextEditor::TabSettings &tabSettings = d->m_document->tabSettings();
+ QTextBlock currentBlock = cursor.block();
+ int positionInBlock = cursor.position() - currentBlock.position();
+ const QString blockText = currentBlock.text();
+ if (cursor.atBlockStart() || tabSettings.firstNonSpace(blockText) < positionInBlock) {
+ cursor.deletePreviousChar();
+ return;
+ }
+
+ int previousIndent = 0;
+ const int indent = tabSettings.columnAt(blockText, positionInBlock);
+
+ for (QTextBlock previousNonEmptyBlock = currentBlock.previous();
+ previousNonEmptyBlock.isValid();
+ previousNonEmptyBlock = previousNonEmptyBlock.previous()) {
+ QString previousNonEmptyBlockText = previousNonEmptyBlock.text();
+ if (previousNonEmptyBlockText.trimmed().isEmpty())
+ continue;
+ previousIndent = tabSettings.columnAt(previousNonEmptyBlockText,
+ tabSettings.firstNonSpace(previousNonEmptyBlockText));
+ if (previousIndent < indent)
+ break;
+ }
+
+ if (previousIndent >= indent)
+ previousIndent = 0;
+
+ cursor.beginEditBlock();
+ cursor.setPosition(currentBlock.position(), QTextCursor::KeepAnchor);
+ cursor.insertText(tabSettings.indentationString(0, previousIndent));
+ cursor.endEditBlock();
+}
+
+
+void BaseTextEditor::format()
+{
+ QTextCursor cursor = textCursor();
+ indent(document(), cursor, QChar::Null);
+}
+
+void BaseTextEditor::unCommentSelection()
+{
+}
+
+void BaseTextEditor::setTabSettings(const TabSettings &ts)
+{
+ d->m_document->setTabSettings(ts);
+ int charWidth = QFontMetrics(font()).width(QChar(' '));
+ setTabStopWidth(charWidth * ts.m_tabSize);
+}
+
+void BaseTextEditor::setDisplaySettings(const DisplaySettings &ds)
+{
+ setLineWrapMode(ds.m_textWrapping ? QPlainTextEdit::WidgetWidth : QPlainTextEdit::NoWrap);
+ setLineNumbersVisible(ds.m_displayLineNumbers);
+ setVisibleWrapColumn(ds.m_showWrapColumn ? ds.m_wrapColumn : 0);
+ setCodeFoldingVisible(ds.m_displayFoldingMarkers);
+ setHighlightCurrentLine(ds.m_highlightCurrentLine);
+
+ if (d->m_displaySettings.m_visualizeWhitespace != ds.m_visualizeWhitespace) {
+ if (QSyntaxHighlighter *highlighter = baseTextDocument()->syntaxHighlighter())
+ highlighter->rehighlight();
+ QTextOption option = document()->defaultTextOption();
+ if (ds.m_visualizeWhitespace)
+ option.setFlags(option.flags() | QTextOption::ShowTabsAndSpaces);
+ else
+ option.setFlags(option.flags() & ~QTextOption::ShowTabsAndSpaces);
+ option.setFlags(option.flags() | QTextOption::AddSpaceForLineAndParagraphSeparators);
+ document()->setDefaultTextOption(option);
+ }
+
+ d->m_displaySettings = ds;
+}
+
+
+void BaseTextEditor::wheelEvent(QWheelEvent *e)
+{
+ d->clearVisibleCollapsedBlock();
+ if (e->modifiers() & Qt::ControlModifier) {
+ const int delta = e->delta();
+ if (delta < 0)
+ zoomOut();
+ else if (delta > 0)
+ zoomIn();
+ return;
+ }
+ QPlainTextEdit::wheelEvent(e);
+}
+
+void BaseTextEditor::zoomIn(int range)
+{
+ d->clearVisibleCollapsedBlock();
+ QFont f = font();
+ const int newSize = f.pointSize() + range;
+ if (newSize <= 0)
+ return;
+ f.setPointSize(newSize);
+ setFont(f);
+}
+
+void BaseTextEditor::zoomOut(int range)
+{
+ zoomIn(-range);
+}
+
+bool BaseTextEditor::isElectricCharacter(const QChar &) const
+{
+ return false;
+}
+
+void BaseTextEditor::indentBlock(QTextDocument *, QTextBlock, QChar)
+{
+}
+
+void BaseTextEditor::indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar)
+{
+ if (cursor.hasSelection()) {
+ QTextBlock block = doc->findBlock(qMin(cursor.selectionStart(), cursor.selectionEnd()));
+ const QTextBlock end = doc->findBlock(qMax(cursor.selectionStart(), cursor.selectionEnd())).next();
+ do {
+ indentBlock(doc, block, typedChar);
+ block = block.next();
+ } while (block.isValid() && block != end);
+ } else {
+ indentBlock(doc, cursor.block(), typedChar);
+ }
+}
+
+void BaseTextEditorPrivate::updateMarksBlock(const QTextBlock &block)
+{
+ if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
+ foreach (ITextMark *mrk, userData->marks()) {
+ mrk->updateBlock(block);
+ }
+}
+
+void BaseTextEditorPrivate::updateMarksLineNumber()
+{
+ QTextDocument *doc = q->document();
+ QTextBlock block = doc->begin();
+ int blockNumber = 0;
+ while (block.isValid()) {
+ if (const TextBlockUserData *userData = TextEditDocumentLayout::testUserData(block))
+ foreach (ITextMark *mrk, userData->marks()) {
+ mrk->updateLineNumber(blockNumber + 1);
+ }
+ block = block.next();
+ ++blockNumber;
+ }
+}
+
+void BaseTextEditor::markBlocksAsChanged(QList<int> blockNumbers) {
+ QTextBlock block = document()->begin();
+ while (block.isValid()) {
+ if (block.revision() < 0)
+ block.setRevision(-block.revision() - 1);
+ block = block.next();
+ }
+ foreach (const int blockNumber, blockNumbers) {
+ QTextBlock block = document()->findBlockByNumber(blockNumber);
+ if (block.isValid())
+ block.setRevision(-block.revision() - 1);
+ }
+}
+
+
+
+TextBlockUserData::MatchType TextBlockUserData::checkOpenParenthesis(QTextCursor *cursor, QChar c)
+{
+ if (!TextEditDocumentLayout::hasParentheses(cursor->block()))
+ return NoMatch;
+
+ Parentheses parenList = TextEditDocumentLayout::parentheses(cursor->block());
+ Parenthesis openParen, closedParen;
+ QTextBlock closedParenParag = cursor->block();
+
+ const int cursorPos = cursor->position() - closedParenParag.position();
+ int i = 0;
+ int ignore = 0;
+ bool foundOpen = false;
+ for (;;) {
+ if (!foundOpen) {
+ if (i >= parenList.count())
+ return NoMatch;
+ openParen = parenList.at(i);
+ if (openParen.pos != cursorPos) {
+ ++i;
+ continue;
+ } else {
+ foundOpen = true;
+ ++i;
+ }
+ }
+
+ if (i >= parenList.count()) {
+ for (;;) {
+ closedParenParag = closedParenParag.next();
+ if (!closedParenParag.isValid())
+ return NoMatch;
+ if (TextEditDocumentLayout::hasParentheses(closedParenParag)) {
+ parenList = TextEditDocumentLayout::parentheses(closedParenParag);
+ break;
+ }
+ }
+ i = 0;
+ }
+
+ closedParen = parenList.at(i);
+ if (closedParen.type == Parenthesis::Opened) {
+ ignore++;
+ ++i;
+ continue;
+ } else {
+ if (ignore > 0) {
+ ignore--;
+ ++i;
+ continue;
+ }
+
+ cursor->clearSelection();
+ cursor->setPosition(closedParenParag.position() + closedParen.pos + 1, QTextCursor::KeepAnchor);
+
+ if ((c == QLatin1Char('{') && closedParen.chr != QLatin1Char('}'))
+ || (c == QLatin1Char('(') && closedParen.chr != QLatin1Char(')'))
+ || (c == QLatin1Char('[') && closedParen.chr != QLatin1Char(']'))
+ || (c == QLatin1Char('+') && closedParen.chr != QLatin1Char('-'))
+ )
+ return Mismatch;
+
+ return Match;
+ }
+ }
+}
+
+TextBlockUserData::MatchType TextBlockUserData::checkClosedParenthesis(QTextCursor *cursor, QChar c)
+{
+ if (!TextEditDocumentLayout::hasParentheses(cursor->block()))
+ return NoMatch;
+
+ Parentheses parenList = TextEditDocumentLayout::parentheses(cursor->block());
+ Parenthesis openParen, closedParen;
+ QTextBlock openParenParag = cursor->block();
+
+ const int cursorPos = cursor->position() - openParenParag.position();
+ int i = parenList.count() - 1;
+ int ignore = 0;
+ bool foundClosed = false;
+ for (;;) {
+ if (!foundClosed) {
+ if (i < 0)
+ return NoMatch;
+ closedParen = parenList.at(i);
+ if (closedParen.pos != cursorPos - 1) {
+ --i;
+ continue;
+ } else {
+ foundClosed = true;
+ --i;
+ }
+ }
+
+ if (i < 0) {
+ for (;;) {
+ openParenParag = openParenParag.previous();
+ if (!openParenParag.isValid())
+ return NoMatch;
+
+ if (TextEditDocumentLayout::hasParentheses(openParenParag)) {
+ parenList = TextEditDocumentLayout::parentheses(openParenParag);
+ break;
+ }
+ }
+ i = parenList.count() - 1;
+ }
+
+ openParen = parenList.at(i);
+ if (openParen.type == Parenthesis::Closed) {
+ ignore++;
+ --i;
+ continue;
+ } else {
+ if (ignore > 0) {
+ ignore--;
+ --i;
+ continue;
+ }
+
+ cursor->clearSelection();
+ cursor->setPosition(openParenParag.position() + openParen.pos, QTextCursor::KeepAnchor);
+
+ if ((c == '}' && openParen.chr != '{') ||
+ (c == ')' && openParen.chr != '(') ||
+ (c == ']' && openParen.chr != '[') ||
+ (c == '-' && openParen.chr != '+'))
+ return Mismatch;
+
+ return Match;
+ }
+ }
+}
+
+TextBlockUserData::MatchType TextBlockUserData::matchCursorBackward(QTextCursor *cursor)
+{
+ cursor->clearSelection();
+ const QTextBlock block = cursor->block();
+
+ if (!TextEditDocumentLayout::hasParentheses(block))
+ return NoMatch;
+
+ const int relPos = cursor->position() - block.position();
+
+ Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
+ const Parentheses::const_iterator cend = parentheses.constEnd();
+ for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
+ const Parenthesis &paren = *it;
+ if (paren.pos == relPos - 1
+ && paren.type == Parenthesis::Closed) {
+ return checkClosedParenthesis(cursor, paren.chr);
+ }
+ }
+ return NoMatch;
+}
+
+TextBlockUserData::MatchType TextBlockUserData::matchCursorForward(QTextCursor *cursor)
+{
+ cursor->clearSelection();
+ const QTextBlock block = cursor->block();
+
+ if (!TextEditDocumentLayout::hasParentheses(block))
+ return NoMatch;
+
+ const int relPos = cursor->position() - block.position();
+
+ Parentheses parentheses = TextEditDocumentLayout::parentheses(block);
+ const Parentheses::const_iterator cend = parentheses.constEnd();
+ for (Parentheses::const_iterator it = parentheses.constBegin();it != cend; ++it) {
+ const Parenthesis &paren = *it;
+ if (paren.pos == relPos
+ && paren.type == Parenthesis::Opened) {
+ return checkOpenParenthesis(cursor, paren.chr);
+ }
+ }
+ return NoMatch;
+}
+
+
+void BaseTextEditor::highlightSearchResults(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ if (d->m_searchExpr.pattern() == txt)
+ return;
+ d->m_searchExpr.setPattern(txt);
+ d->m_searchExpr.setPatternSyntax(QRegExp::FixedString);
+ d->m_searchExpr.setCaseSensitivity((findFlags & QTextDocument::FindCaseSensitively) ?
+ Qt::CaseSensitive : Qt::CaseInsensitive);
+ d->m_findFlags = findFlags;
+ viewport()->update();
+}
+
+
+void BaseTextEditor::setFindScope(const QTextCursor &scope)
+{
+ if (scope.isNull() != d->m_findScope.isNull()) {
+ d->m_findScope = scope;
+ viewport()->update();
+ }
+}
+
+void BaseTextEditor::_q_matchParentheses()
+{
+ if (isReadOnly())
+ return;
+
+ QTextCursor backwardMatch = textCursor();
+ QTextCursor forwardMatch = textCursor();
+ const TextBlockUserData::MatchType backwardMatchType = TextBlockUserData::matchCursorBackward(&backwardMatch);
+ const TextBlockUserData::MatchType forwardMatchType = TextBlockUserData::matchCursorForward(&forwardMatch);
+
+ if (backwardMatchType == TextBlockUserData::NoMatch && forwardMatchType == TextBlockUserData::NoMatch)
+ return;
+
+ QList<QTextEdit::ExtraSelection> extraSelections = d->m_extraSelections;
+
+ if (backwardMatch.hasSelection()) {
+ QTextEdit::ExtraSelection sel;
+ if (backwardMatchType == TextBlockUserData::Mismatch) {
+ sel.cursor = backwardMatch;
+ sel.format = d->m_mismatchFormat;
+ } else {
+
+ if (d->m_formatRange) {
+ sel.cursor = backwardMatch;
+ sel.format = d->m_rangeFormat;
+ extraSelections.append(sel);
+ }
+
+ sel.cursor = backwardMatch;
+ sel.format = d->m_matchFormat;
+
+ sel.cursor.setPosition(backwardMatch.selectionStart());
+ sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ extraSelections.append(sel);
+
+ sel.cursor.setPosition(backwardMatch.selectionEnd());
+ sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ }
+ extraSelections.append(sel);
+ }
+
+ if (forwardMatch.hasSelection()) {
+ QTextEdit::ExtraSelection sel;
+ if (forwardMatchType == TextBlockUserData::Mismatch) {
+ sel.cursor = forwardMatch;
+ sel.format = d->m_mismatchFormat;
+ } else {
+
+ if (d->m_formatRange) {
+ sel.cursor = forwardMatch;
+ sel.format = d->m_rangeFormat;
+ extraSelections.append(sel);
+ }
+
+ sel.cursor = forwardMatch;
+ sel.format = d->m_matchFormat;
+
+ sel.cursor.setPosition(forwardMatch.selectionStart());
+ sel.cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor);
+ extraSelections.append(sel);
+
+ sel.cursor.setPosition(forwardMatch.selectionEnd());
+ sel.cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ }
+ extraSelections.append(sel);
+ }
+ d->m_extraSelections = extraSelections;
+ setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections);
+}
+
+void BaseTextEditor::setActionHack(QObject *hack)
+{
+ d->m_actionHack = hack;
+}
+
+QObject *BaseTextEditor::actionHack() const
+{
+ return d->m_actionHack;
+}
+
+void BaseTextEditor::changeEvent(QEvent *e)
+{
+ QPlainTextEdit::changeEvent(e);
+ if (e->type() == QEvent::ApplicationFontChange
+ || e->type() == QEvent::FontChange) {
+ if (d->m_extraArea) {
+ QFont f = d->m_extraArea->font();
+ f.setPointSize(font().pointSize());
+ d->m_extraArea->setFont(f);
+ slotUpdateExtraAreaWidth();
+ d->m_extraArea->update();
+ }
+ }
+}
+
+// shift+del
+void BaseTextEditor::deleteLine()
+{
+ QTextCursor cursor = textCursor();
+ if (!cursor.hasSelection()) {
+ const QTextBlock &block = cursor.block();
+ if (block.next().isValid()) {
+ cursor.setPosition(block.position());
+ cursor.setPosition(block.next().position(), QTextCursor::KeepAnchor);
+ } else {
+ cursor.movePosition(QTextCursor::EndOfBlock);
+ cursor.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
+ cursor.movePosition(QTextCursor::PreviousCharacter, QTextCursor::KeepAnchor);
+ }
+ setTextCursor(cursor);
+ }
+ cut();
+}
+
+void BaseTextEditor::setExtraExtraSelections(const QList<QTextEdit::ExtraSelection> &selections)
+{
+ d->m_extraExtraSelections = selections;
+ setExtraSelections(d->m_extraSelections + d->m_extraExtraSelections);
+}
+
+QList<QTextEdit::ExtraSelection> BaseTextEditor::extraExtraSelections() const
+{
+ return d->m_extraExtraSelections;
+}
+
+
+// the blocks list must be sorted
+void BaseTextEditor::setIfdefedOutBlocks(const QList<BaseTextEditor::BlockRange> &blocks)
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ bool needUpdate = false;
+
+ QTextBlock block = doc->firstBlock();
+
+ int rangeNumber = 0;
+ while (block.isValid()) {
+ if (rangeNumber < blocks.size()) {
+ const BlockRange &range = blocks.at(rangeNumber);
+
+ if (block.position() >= range.first && (block.position() <= range.last || !range.last)) {
+ needUpdate += TextEditDocumentLayout::setIfdefedOut(block);
+ } else {
+ needUpdate += TextEditDocumentLayout::clearIfdefedOut(block);
+ }
+ if (block.contains(range.last))
+ ++rangeNumber;
+ } else {
+ needUpdate |= TextEditDocumentLayout::clearIfdefedOut(block);
+ }
+
+ block = block.next();
+ }
+
+ if (needUpdate)
+ documentLayout->requestUpdate();
+}
+
+
+void BaseTextEditorPrivate::moveCursorVisible()
+{
+ QTextCursor cursor = q->textCursor();
+ if (!cursor.block().isVisible()) {
+ cursor.setVisualNavigation(true);
+ cursor.movePosition(QTextCursor::PreviousBlock);
+ q->setTextCursor(cursor);
+ }
+ q->ensureCursorVisible();
+}
+
+void BaseTextEditor::collapse()
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ QTextBlock block = textCursor().block();
+ while (block.isValid()) {
+ if (TextBlockUserData::canCollapse(block)) {
+ if ((block.next().userState()) >> 8 == (textCursor().block().userState() >> 8))
+ break;
+ }
+ block = block.previous();
+ }
+ if (block.isValid()) {
+ TextBlockUserData::doCollapse(block, false);
+ d->moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+ }
+}
+
+void BaseTextEditor::expand()
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+ QTextBlock block = textCursor().block();
+ while (block.isValid() && !block.isVisible())
+ block = block.previous();
+ TextBlockUserData::doCollapse(block, true);
+ d->moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+}
+
+void BaseTextEditor::unCollapseAll()
+{
+ QTextDocument *doc = document();
+ TextEditDocumentLayout *documentLayout = qobject_cast<TextEditDocumentLayout*>(doc->documentLayout());
+ Q_ASSERT(documentLayout);
+
+ QTextBlock block = doc->firstBlock();
+ bool makeVisible = true;
+ while (block.isValid()) {
+ if (block.isVisible() && TextBlockUserData::canCollapse(block) && block.next().isVisible()) {
+ makeVisible = false;
+ break;
+ }
+ block = block.next();
+ }
+
+ block = doc->firstBlock();
+
+ while (block.isValid()) {
+ if (TextBlockUserData::canCollapse(block))
+ TextBlockUserData::doCollapse(block, makeVisible);
+ block = block.next();
+
+ }
+
+ d->moveCursorVisible();
+ documentLayout->requestUpdate();
+ documentLayout->emitDocumentSizeChanged();
+}
+
+void BaseTextEditor::setTextCodec(QTextCodec *codec)
+{
+ baseTextDocument()->setCodec(codec);
+}
+
+QTextCodec *BaseTextEditor::textCodec() const
+{
+ return baseTextDocument()->codec();
+}
+
+void BaseTextEditor::setReadOnly(bool b)
+{
+ QPlainTextEdit::setReadOnly(b);
+ if (b)
+ setTextInteractionFlags(textInteractionFlags() | Qt::TextSelectableByKeyboard);
+}
+
+void BaseTextEditor::cut()
+{
+ if (d->m_inBlockSelectionMode) {
+ copy();
+ d->removeBlockSelection();
+ return;
+ }
+ QPlainTextEdit::cut();
+}
+
+QMimeData *BaseTextEditor::createMimeDataFromSelection() const
+{
+ if (d->m_inBlockSelectionMode) {
+ QMimeData *mimeData = new QMimeData;
+ QString text = d->copyBlockSelection();
+ mimeData->setData(QLatin1String("application/vnd.nokia.qtcreator.blocktext"), text.toUtf8());
+ mimeData->setText(text); // for exchangeability
+ return mimeData;
+ }
+ return QPlainTextEdit::createMimeDataFromSelection();
+}
+
+bool BaseTextEditor::canInsertFromMimeData(const QMimeData *source) const
+{
+ return QPlainTextEdit::canInsertFromMimeData(source);
+}
+
+void BaseTextEditor::insertFromMimeData(const QMimeData *source)
+{
+ if (!isReadOnly() && source->hasFormat(QLatin1String("application/vnd.nokia.qtcreator.blocktext"))) {
+ QString text = QString::fromUtf8(source->data(QLatin1String("application/vnd.nokia.qtcreator.blocktext")));
+ if (text.isEmpty())
+ return;
+ QStringList lines = text.split(QLatin1Char('\n'));
+ QTextCursor cursor = textCursor();
+ cursor.beginEditBlock();
+ int initialCursorPosition = cursor.position();
+ int column = cursor.position() - cursor.block().position();
+ cursor.insertText(lines.first());
+ for (int i = 1; i < lines.count(); ++i) {
+ QTextBlock next = cursor.block().next();
+ if (next.isValid()) {
+ cursor.setPosition(next.position() + qMin(column, next.length()-1));
+ } else {
+ cursor.movePosition(QTextCursor::EndOfBlock);
+ cursor.insertBlock();
+ }
+
+ int actualColumn = cursor.position() - cursor.block().position();
+ if (actualColumn < column)
+ cursor.insertText(QString(column - actualColumn, QLatin1Char(' ')));
+ cursor.insertText(lines.at(i));
+ }
+ cursor.setPosition(initialCursorPosition);
+ cursor.endEditBlock();
+ setTextCursor(cursor);
+ ensureCursorVisible();
+ return;
+ }
+ QPlainTextEdit::insertFromMimeData(source);
+}
+
+BaseTextEditorEditable::BaseTextEditorEditable(BaseTextEditor *editor)
+ : e(editor)
+{
+#ifndef TEXTEDITOR_STANDALONE
+ using namespace Find;
+ Aggregation::Aggregate *aggregate = new Aggregation::Aggregate;
+ BaseTextFind *baseTextFind = new BaseTextFind(editor);
+ connect(baseTextFind, SIGNAL(highlightAll(QString, QTextDocument::FindFlags)),
+ editor, SLOT(highlightSearchResults(QString, QTextDocument::FindFlags)));
+ connect(baseTextFind, SIGNAL(findScopeChanged(QTextCursor)), editor, SLOT(setFindScope(QTextCursor)));
+ aggregate->add(baseTextFind);
+ aggregate->add(editor);
+#endif
+
+ m_cursorPositionLabel = new Core::Utils::LineColumnLabel;
+
+ QHBoxLayout *l = new QHBoxLayout;
+ QWidget *w = new QWidget;
+ l->setMargin(0);
+ l->setContentsMargins(0, 0, 5, 0);
+ l->addStretch(1);
+ l->addWidget(m_cursorPositionLabel);
+ w->setLayout(l);
+
+ m_toolBar = new QToolBar;
+ m_toolBar->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ m_toolBar->addWidget(w);
+
+ connect(editor, SIGNAL(cursorPositionChanged()), this, SLOT(updateCursorPosition()));
+}
+
+BaseTextEditorEditable::~BaseTextEditorEditable()
+{
+ delete m_toolBar;
+ delete e;
+}
+
+QToolBar *BaseTextEditorEditable::toolBar()
+{
+ return m_toolBar;
+}
+
+int BaseTextEditorEditable::find(const QString &) const
+{
+ return 0;
+}
+
+int BaseTextEditorEditable::currentLine() const
+{
+ return e->textCursor().blockNumber() + 1;
+}
+
+int BaseTextEditorEditable::currentColumn() const
+{
+ QTextCursor cursor = e->textCursor();
+ return cursor.position() - cursor.block().position() + 1;
+}
+
+QRect BaseTextEditorEditable::cursorRect(int pos) const
+{
+ QTextCursor tc = e->textCursor();
+ if (pos >= 0)
+ tc.setPosition(pos);
+ QRect result = e->cursorRect(tc);
+ result.moveTo(e->viewport()->mapToGlobal(result.topLeft()));
+ return result;
+}
+
+QString BaseTextEditorEditable::contents() const
+{
+ return e->toPlainText();
+}
+
+QString BaseTextEditorEditable::selectedText() const
+{
+ if (e->textCursor().hasSelection())
+ return e->textCursor().selectedText();
+ return QString();
+}
+
+QString BaseTextEditorEditable::textAt(int pos, int length) const
+{
+ QTextCursor c = e->textCursor();
+
+ if (pos < 0)
+ pos = 0;
+ c.movePosition(QTextCursor::End);
+ if (pos + length > c.position())
+ length = c.position() - pos;
+
+ c.setPosition(pos);
+ c.setPosition(pos + length, QTextCursor::KeepAnchor);
+
+ return c.selectedText();
+}
+
+void BaseTextEditorEditable::remove(int length)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
+ tc.removeSelectedText();
+}
+
+void BaseTextEditorEditable::insert(const QString &string)
+{
+ QTextCursor tc = e->textCursor();
+ tc.insertText(string);
+}
+
+void BaseTextEditorEditable::replace(int length, const QString &string)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(tc.position() + length, QTextCursor::KeepAnchor);
+ tc.insertText(string);
+}
+
+void BaseTextEditorEditable::setCurPos(int pos)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(pos);
+ e->setTextCursor(tc);
+}
+
+void BaseTextEditorEditable::select(int toPos)
+{
+ QTextCursor tc = e->textCursor();
+ tc.setPosition(toPos, QTextCursor::KeepAnchor);
+ e->setTextCursor(tc);
+}
+
+void BaseTextEditorEditable::updateCursorPosition()
+{
+ const QTextCursor cursor = e->textCursor();
+ const QTextBlock block = cursor.block();
+ const int line = block.blockNumber() + 1;
+ const int column = cursor.position() - block.position() + 1;
+ m_cursorPositionLabel->setText(QString("Line: %1, Col: %2").arg(line).arg(column),
+ QString("Line: %1, Col: 999").arg(e->blockCount()));
+ m_contextHelpId.clear();
+
+ if (!block.isVisible())
+ e->ensureCursorVisible();
+
+}
+
+QString BaseTextEditorEditable::contextHelpId() const
+{
+ if (m_contextHelpId.isEmpty())
+ emit const_cast<BaseTextEditorEditable*>(this)->contextHelpIdRequested(e->editableInterface(),
+ e->textCursor().position());
+ return m_contextHelpId;
+}
+
+
+TextBlockUserData::~TextBlockUserData()
+{
+ TextMarks marks = m_marks;
+ m_marks.clear();
+ foreach (ITextMark *mrk, marks) {
+ mrk->removedFromEditor();
+ }
+}
+
diff --git a/src/plugins/texteditor/basetexteditor.h b/src/plugins/texteditor/basetexteditor.h
new file mode 100644
index 0000000000..f41e26b2b0
--- /dev/null
+++ b/src/plugins/texteditor/basetexteditor.h
@@ -0,0 +1,513 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTEDITOR_H
+#define BASETEXTEDITOR_H
+
+#include "displaysettings.h"
+#include "tabsettings.h"
+#include "itexteditable.h"
+
+#include <QtGui/QPlainTextEdit>
+#include <QtGui/QLabel>
+#include <QtGui/QKeyEvent>
+
+QT_BEGIN_NAMESPACE
+class QLabel;
+class QTextCharFormat;
+class QToolBar;
+QT_END_NAMESPACE
+
+namespace Core {
+ namespace Utils {
+ class LineColumnLabel;
+ }
+}
+
+namespace TextEditor {
+
+namespace Internal {
+ class BaseTextEditorPrivate;
+}
+
+class ITextMark;
+class ITextMarkable;
+
+class TextEditorActionHandler;
+class BaseTextDocument;
+class FontSettings;
+struct StorageSettings;
+
+struct Parenthesis;
+typedef QVector<Parenthesis> Parentheses;
+struct TEXTEDITOR_EXPORT Parenthesis
+{
+ enum Type { Opened, Closed };
+
+ inline Parenthesis() : type(Opened), pos(-1) {}
+ inline Parenthesis(Type t, QChar c, int position)
+ : type(t), chr(c), pos(position) {}
+ Type type;
+ QChar chr;
+ int pos;
+ static int collapseAtPos(const Parentheses &parentheses, QChar *character = 0);
+ static int closeCollapseAtPos(const Parentheses &parentheses);
+ static bool hasClosingCollapse(const Parentheses &parentheses);
+};
+
+
+
+class TEXTEDITOR_EXPORT TextBlockUserData : public QTextBlockUserData {
+public:
+
+ enum CollapseMode { NoCollapse , CollapseThis, CollapseAfter };
+ enum ClosingCollapseMode { NoClosingCollapse, ClosingCollapse, ClosingCollapseAtEnd };
+
+ inline TextBlockUserData()
+ : m_collapseIncludesClosure(false),
+ m_collapseMode(NoCollapse),
+ m_closingCollapseMode(NoClosingCollapse),
+ m_collapsed(false),
+ m_ifdefedOut(false) {}
+ ~TextBlockUserData();
+
+ inline TextMarks marks() const { return m_marks; }
+ inline void addMark(ITextMark *mark) { m_marks += mark; }
+ inline bool removeMark(ITextMark *mark) { return m_marks.removeAll(mark); }
+ inline bool hasMark(ITextMark *mark) const { return m_marks.contains(mark); }
+ inline void clearMarks() { m_marks.clear(); }
+ inline void documentClosing() { Q_FOREACH(ITextMark *tm, m_marks) { tm->documentClosing(); } m_marks.clear();}
+
+ inline CollapseMode collapseMode() const { return (CollapseMode)m_collapseMode; }
+ inline void setCollapseMode(CollapseMode c) { m_collapseMode = c; }
+
+ inline void setClosingCollapseMode(ClosingCollapseMode c) { m_closingCollapseMode = c; }
+ inline ClosingCollapseMode closingCollapseMode() const { return (ClosingCollapseMode) m_closingCollapseMode; }
+
+ inline bool hasClosingCollapse() const { return closingCollapseMode() != NoClosingCollapse; }
+ inline bool hasClosingCollapseAtEnd() const { return closingCollapseMode() == ClosingCollapseAtEnd; }
+ inline bool hasClosingCollapseInside() const { return closingCollapseMode() == ClosingCollapse; }
+
+ inline void setCollapsed(bool b) { m_collapsed = b; }
+ inline bool collapsed() const { return m_collapsed; }
+
+ inline void setCollapseIncludesClosure(bool b) { m_collapseIncludesClosure = b; }
+ inline bool collapseIncludesClosure() const { return m_collapseIncludesClosure; }
+
+ inline void setParentheses(const Parentheses &parentheses) { m_parentheses = parentheses; }
+ inline void clearParentheses() { m_parentheses.clear(); }
+ inline const Parentheses &parentheses() const { return m_parentheses; }
+ inline bool hasParentheses() const { return !m_parentheses.isEmpty(); }
+
+ inline bool setIfdefedOut() { bool result = m_ifdefedOut; m_ifdefedOut = true; return !result; }
+ inline bool clearIfdefedOut() { bool result = m_ifdefedOut; m_ifdefedOut = false; return result;}
+ inline bool ifdefedOut() const { return m_ifdefedOut; }
+
+ inline static TextBlockUserData *canCollapse(const QTextBlock& block) {
+ TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
+ if (!data || data->collapseMode() != CollapseAfter) {
+ data = static_cast<TextBlockUserData*>(block.next().userData());
+ if (!data || data->collapseMode() != TextBlockUserData::CollapseThis)
+ data = 0;
+ }
+ return data;
+ }
+
+ inline static bool hasClosingCollapse(const QTextBlock &block) {
+ TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
+ return (data && data->hasClosingCollapse());
+ }
+
+ inline static bool hasClosingCollapseAtEnd(const QTextBlock &block) {
+ TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
+ return (data && data->hasClosingCollapseAtEnd());
+ }
+
+ inline static bool hasClosingCollapseInside(const QTextBlock &block) {
+ TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
+ return (data && data->hasClosingCollapseInside());
+ }
+
+ static QTextBlock testCollapse(const QTextBlock& block);
+ static void doCollapse(const QTextBlock& block, bool visible);
+
+ int collapseAtPos() const;
+
+ enum MatchType { NoMatch, Match, Mismatch };
+ static MatchType checkOpenParenthesis(QTextCursor *cursor, QChar c);
+ static MatchType checkClosedParenthesis(QTextCursor *cursor, QChar c);
+ static MatchType matchCursorBackward(QTextCursor *cursor);
+ static MatchType matchCursorForward(QTextCursor *cursor);
+
+
+private:
+ TextMarks m_marks;
+ uint m_collapseIncludesClosure : 1;
+ uint m_collapseMode : 4;
+ uint m_closingCollapseMode : 4;
+ uint m_collapsed : 1;
+ uint m_ifdefedOut : 1;
+ Parentheses m_parentheses;
+};
+
+
+class TEXTEDITOR_EXPORT TextEditDocumentLayout : public QPlainTextDocumentLayout
+{
+ Q_OBJECT
+
+public:
+ TextEditDocumentLayout(QTextDocument *doc);
+ ~TextEditDocumentLayout();
+
+ QRectF blockBoundingRect(const QTextBlock &block) const;
+
+ static void setParentheses(const QTextBlock &block, const Parentheses &parentheses);
+ static void clearParentheses(const QTextBlock &block) { setParentheses(block, Parentheses());}
+ static Parentheses parentheses(const QTextBlock &block);
+ static bool hasParentheses(const QTextBlock &block);
+ static bool setIfdefedOut(const QTextBlock &block);
+ static bool clearIfdefedOut(const QTextBlock &block);
+ static bool ifdefedOut(const QTextBlock &block);
+
+ static TextBlockUserData *testUserData(const QTextBlock &block) {
+ return static_cast<TextBlockUserData*>(block.userData());
+ }
+ static TextBlockUserData *userData(const QTextBlock &block) {
+ TextBlockUserData *data = static_cast<TextBlockUserData*>(block.userData());
+ if (!data && block.isValid())
+ const_cast<QTextBlock &>(block).setUserData((data = new TextBlockUserData));
+ return data;
+ }
+
+
+ void emitDocumentSizeChanged() { emit documentSizeChanged(documentSize()); }
+ int lastSaveRevision;
+ bool hasMarks;
+};
+
+
+class BaseTextEditorEditable;
+
+class TEXTEDITOR_EXPORT BaseTextEditor
+ : public QPlainTextEdit
+{
+ Q_OBJECT
+
+public:
+ BaseTextEditor(QWidget *parent);
+ ~BaseTextEditor();
+
+ static ITextEditor *openEditorAt(const QString &fileName, int line, int column = 0);
+
+ // EditorInterface
+ Core::IFile * file();
+ bool createNew(const QString &contents);
+ bool open(const QString &fileName = QString());
+ QByteArray saveState() const;
+ bool restoreState(const QByteArray &state);
+ QString displayName() const;
+
+ // ITextEditor
+
+ void gotoLine(int line, int column = 0);
+
+ int position(
+ ITextEditor::PositionOperation posOp = ITextEditor::Current
+ , int at = -1) const;
+ void convertPosition(int pos, int *line, int *column) const;
+
+ ITextEditable *editableInterface() const;
+ ITextMarkable *markableInterface() const;
+
+ virtual void triggerCompletions();
+
+ QChar characterAt(int pos) const;
+
+ void print(QPrinter *);
+
+ void setSuggestedFileName(const QString &suggestedFileName);
+ QString mimeType() const;
+ void setMimeType(const QString &mt);
+
+
+ // Works only in conjunction with a syntax highlighter that puts
+ // parentheses into text block user data
+ void setParenthesesMatchingEnabled(bool b);
+ bool isParenthesesMatchingEnabled() const;
+
+ void setHighlightCurrentLine(bool b);
+ bool highlightCurrentLine() const;
+
+ void setLineNumbersVisible(bool b);
+ bool lineNumbersVisible() const;
+
+ void setMarksVisible(bool b);
+ bool marksVisible() const;
+
+ void setRequestMarkEnabled(bool b);
+ bool requestMarkEnabled() const;
+
+ void setLineSeparatorsAllowed(bool b);
+ bool lineSeparatorsAllowed() const;
+
+ void setCodeFoldingVisible(bool b);
+ bool codeFoldingVisible() const;
+
+ void setRevisionsVisible(bool b);
+ bool revisionsVisible() const;
+
+ void setVisibleWrapColumn(int column);
+ int visibleWrapColumn() const;
+
+ void setActionHack(QObject *);
+ QObject *actionHack() const;
+
+ void setTextCodec(QTextCodec *codec);
+ QTextCodec *textCodec() const;
+
+ void setReadOnly(bool b);
+
+public slots:
+ void setDisplayName(const QString &title);
+ virtual void setFontSettings(const TextEditor::FontSettings &);
+ virtual void format();
+ virtual void unCommentSelection();
+ virtual void setStorageSettings(const TextEditor::StorageSettings &);
+
+ void cut();
+
+ void zoomIn(int range = 1);
+ void zoomOut(int range = 1);
+
+ void deleteLine();
+ void unCollapseAll();
+ void collapse();
+ void expand();
+ void selectEncoding();
+
+signals:
+ void changed();
+
+ // ITextEditor
+ void contentsChanged();
+
+protected:
+ bool event(QEvent *e);
+ void keyPressEvent(QKeyEvent *e);
+ void wheelEvent(QWheelEvent *e);
+ void changeEvent(QEvent *e);
+
+ // reimplemented to support block selection
+ QMimeData *createMimeDataFromSelection() const;
+ bool canInsertFromMimeData(const QMimeData *source) const;
+ void insertFromMimeData(const QMimeData *source);
+
+public:
+ void duplicateFrom(BaseTextEditor *editor);
+protected:
+ BaseTextDocument *baseTextDocument() const;
+ void setBaseTextDocument(BaseTextDocument *doc);
+
+ void setDefaultPath(const QString &defaultPath);
+
+ virtual BaseTextEditorEditable *createEditableInterface() = 0;
+
+private slots:
+ void editorContentsChange(int position, int charsRemoved, int charsAdded);
+ void memorizeCursorPosition();
+ void restoreCursorPosition();
+ void highlightSearchResults(const QString &txt, QTextDocument::FindFlags findFlags);
+ void setFindScope(const QTextCursor &);
+ void setCollapseIndicatorAlpha(int);
+ void currentEditorChanged(Core::IEditor *editor);
+
+private:
+ Internal::BaseTextEditorPrivate *d;
+ friend class Internal::BaseTextEditorPrivate;
+
+
+public:
+ QWidget *extraArea() const;
+ virtual int extraAreaWidth(int *markWidthPtr = 0) const;
+ virtual void extraAreaPaintEvent(QPaintEvent *);
+ virtual void extraAreaMouseEvent(QMouseEvent *);
+ virtual void extraAreaLeaveEvent(QEvent *);
+
+
+ const TabSettings &tabSettings() const;
+ const DisplaySettings &displaySettings() const;
+
+ void markBlocksAsChanged(QList<int> blockNumbers);
+
+ void ensureCursorVisible();
+
+ void setExtraExtraSelections(const QList<QTextEdit::ExtraSelection> &selections);
+ QList<QTextEdit::ExtraSelection> extraExtraSelections() const;
+
+ struct BlockRange {
+ BlockRange():first(0), last(-1){}
+ BlockRange(int first_position, int last_position):first(first_position), last(last_position){}
+ int first;
+ int last;
+ inline bool isNull() const { return last < first; }
+ };
+
+ // the blocks list must be sorted
+ void setIfdefedOutBlocks(const QList<BaseTextEditor::BlockRange> &blocks);
+
+
+public slots:
+ virtual void setTabSettings(const TextEditor::TabSettings &);
+ virtual void setDisplaySettings(const TextEditor::DisplaySettings &);
+
+protected:
+ bool viewportEvent(QEvent *event);
+
+ void resizeEvent(QResizeEvent *);
+ void paintEvent(QPaintEvent *);
+ void timerEvent(QTimerEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mousePressEvent(QMouseEvent *);
+
+ // Rertuns true if key triggers an indent.
+ virtual bool isElectricCharacter(const QChar &ch) const;
+ // Indent a text block based on previous line. Default does nothing
+ virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+ // Indent at cursor. Calls indentBlock for selection or current line.
+ virtual void indent(QTextDocument *doc, const QTextCursor &cursor, QChar typedChar);
+
+
+protected slots:
+ virtual void slotUpdateExtraAreaWidth();
+ virtual void slotModificationChanged(bool);
+ virtual void slotUpdateRequest(const QRect &r, int dy);
+ virtual void slotCursorPositionChanged();
+ virtual void slotUpdateBlockNotify(const QTextBlock &);
+
+
+
+signals:
+ void markRequested(TextEditor::ITextEditor *editor, int line);
+ void requestBlockUpdate(const QTextBlock &);
+ void requestAutoCompletion(ITextEditable *editor, bool forced);
+
+private:
+ void indentOrUnindent(bool doIndent);
+ void handleHomeKey(bool anchor);
+ void handleBackspaceKey();
+
+ void toggleBlockVisible(const QTextBlock &block);
+ QRect collapseBox(const QTextBlock &block);
+
+ QTextBlock collapsedBlockAt(const QPoint &pos, QRect *box = 0) const;
+
+ // parentheses matcher
+private slots:
+ void _q_matchParentheses();
+ void slotSelectionChanged();
+};
+
+
+class TEXTEDITOR_EXPORT BaseTextEditorEditable
+ : public ITextEditable
+{
+ Q_OBJECT
+ friend class BaseTextEditor;
+public:
+ BaseTextEditorEditable(BaseTextEditor *editor);
+ ~BaseTextEditorEditable();
+
+ inline BaseTextEditor *editor() const { return e; }
+
+ // EditorInterface
+ inline QWidget *widget() { return e; }
+ inline Core::IFile * file() { return e->file(); }
+ inline bool createNew(const QString &contents) { return e->createNew(contents); }
+ inline bool open(const QString &fileName = QString())
+ {
+ return e->open(fileName);
+ }
+ inline QString displayName() const { return e->displayName(); }
+ inline void setDisplayName(const QString &title) { e->setDisplayName(title); }
+
+ inline QByteArray saveState() const { return e->saveState(); }
+ inline bool restoreState(const QByteArray &state) { return e->restoreState(state); }
+ QToolBar *toolBar();
+
+ // ITextEditor
+ int find(const QString &string) const;
+
+ int currentLine() const;
+ int currentColumn() const;
+ inline void gotoLine(int line, int column = 0) { e->gotoLine(line, column); }
+
+ inline int position(
+ ITextEditor::PositionOperation posOp = ITextEditor::Current
+ , int at = -1) const { return e->position(posOp, at); }
+ inline void convertPosition(int pos, int *line, int *column) const { e->convertPosition(pos, line, column); }
+ QRect cursorRect(int pos = -1) const;
+
+ QString contents() const;
+ QString selectedText() const;
+ QString textAt(int pos, int length) const;
+ inline QChar characterAt(int pos) const { return e->characterAt(pos); }
+
+ inline void triggerCompletions() { e->triggerCompletions(); } // slot?
+ inline ITextMarkable *markableInterface() { return e->markableInterface(); }
+
+ void setContextHelpId(const QString &id) { m_contextHelpId = id; }
+ QString contextHelpId() const; // from IContext
+
+ inline void setTextCodec(QTextCodec *codec) { e->setTextCodec(codec); }
+ inline QTextCodec *textCodec() const { return e->textCodec(); }
+
+
+ // ITextEditable
+ void remove(int length);
+ void insert(const QString &string);
+ void replace(int length, const QString &string);
+ void setCurPos(int pos);
+ void select(int toPos);
+
+private slots:
+ void updateCursorPosition();
+
+private:
+ BaseTextEditor *e;
+ mutable QString m_contextHelpId;
+ QToolBar *m_toolBar;
+ Core::Utils::LineColumnLabel *m_cursorPositionLabel;
+};
+
+} // namespace TextEditor
+
+#endif // BASETEXTEDITOR_H
diff --git a/src/plugins/texteditor/basetexteditor_p.h b/src/plugins/texteditor/basetexteditor_p.h
new file mode 100644
index 0000000000..4bb0de7070
--- /dev/null
+++ b/src/plugins/texteditor/basetexteditor_p.h
@@ -0,0 +1,225 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTEDITOR_P_H
+#define BASETEXTEDITOR_P_H
+
+#include "basetexteditor.h"
+
+#include <QtCore/QBasicTimer>
+#include <QtCore/QTimeLine>
+#include <QtCore/QSharedData>
+
+#include <QtGui/QTextEdit>
+#include <QtGui/QPixmap>
+
+namespace TextEditor {
+
+class BaseTextDocument;
+
+namespace Internal {
+
+//========== Pointers with reference count ==========
+
+template <class T> class QRefCountData : public QSharedData
+{
+public:
+ QRefCountData(T *data) { m_data = data; }
+
+ ~QRefCountData() { delete m_data; }
+
+ T *m_data;
+};
+
+/* MOSTLY COPIED FROM QSHAREDDATA(-POINTER) */
+template <class T> class QRefCountPointer
+{
+public:
+ inline T &operator*() { return d ? *(d->m_data) : 0; }
+ inline const T &operator*() const { return d ? *(d->m_data) : 0; }
+ inline T *operator->() { return d ? d->m_data : 0; }
+ inline const T *operator->() const { return d ? d->m_data : 0; }
+ inline operator T *() { return d ? d->m_data : 0; }
+ inline operator const T *() const { return d ? d->m_data : 0; }
+
+ inline bool operator==(const QRefCountPointer<T> &other) const { return d == other.d; }
+ inline bool operator!=(const QRefCountPointer<T> &other) const { return d != other.d; }
+
+ inline QRefCountPointer() { d = 0; }
+ inline ~QRefCountPointer() { if (d && !d->ref.deref()) delete d; }
+
+ explicit QRefCountPointer(T *data) {
+ if (data) {
+ d = new QRefCountData<T>(data);
+ d->ref.ref();
+ }
+ else {
+ d = 0;
+ }
+ }
+ inline QRefCountPointer(const QRefCountPointer<T> &o) : d(o.d) { if (d) d->ref.ref(); }
+ inline QRefCountPointer<T> & operator=(const QRefCountPointer<T> &o) {
+ if (o.d != d) {
+ if (d && !d->ref.deref())
+ delete d;
+ //todo: atomic assign of pointers
+ d = o.d;
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+ }
+ inline QRefCountPointer &operator=(T *o) {
+ if (d == 0 || d->m_data != o) {
+ if (d && !d->ref.deref())
+ delete d;
+ d = new QRefCountData<T>(o);
+ if (d)
+ d->ref.ref();
+ }
+ return *this;
+ }
+
+ inline bool operator!() const { return !d; }
+
+private:
+ QRefCountData<T> *d;
+};
+
+//================BaseTextEditorPrivate==============
+
+class BaseTextEditorPrivate
+{
+ BaseTextEditorPrivate(const BaseTextEditorPrivate &);
+ BaseTextEditorPrivate &operator=(const BaseTextEditorPrivate &);
+
+public:
+ BaseTextEditorPrivate();
+ ~BaseTextEditorPrivate();
+
+#ifndef TEXTEDITOR_STANDALONE
+ void setupBasicEditActions(TextEditorActionHandler *actionHandler);
+#endif
+ void setupDocumentSignals(BaseTextDocument *document);
+ void updateLineSelectionColor();
+#ifndef TEXTEDITOR_STANDALONE
+ bool needMakeWritableCheck() const;
+#endif
+
+ void print(QPrinter *printer);
+
+ QTextBlock m_firstVisible;
+ int m_lastScrollPos;
+ int m_lineNumber;
+
+ BaseTextEditor *q;
+ bool m_contentsChanged;
+
+ QList<QTextEdit::ExtraSelection> m_syntaxHighlighterSelections;
+ QTextEdit::ExtraSelection m_lineSelection;
+
+ QRefCountPointer<BaseTextDocument> m_document;
+ QByteArray m_tempState;
+
+ QString m_displayName;
+ bool m_parenthesesMatchingEnabled;
+ QTimer *m_updateTimer;
+
+ // parentheses matcher
+ bool m_formatRange;
+ QTextCharFormat m_matchFormat;
+ QTextCharFormat m_mismatchFormat;
+ QTextCharFormat m_rangeFormat;
+ QTimer *m_parenthesesMatchingTimer;
+ // end parentheses matcher
+
+ QWidget *m_extraArea;
+ DisplaySettings m_displaySettings;
+
+ int extraAreaSelectionAnchorBlockNumber;
+ int extraAreaToggleMarkBlockNumber;
+ int extraAreaHighlightCollapseBlockNumber;
+ int extraAreaCollapseAlpha;
+ int extraAreaHighlightFadingBlockNumber;
+ QTimeLine *extraAreaTimeLine;
+
+ QBasicTimer collapsedBlockTimer;
+ int visibleCollapsedBlockNumber;
+ int suggestedVisibleCollapsedBlockNumber;
+ void clearVisibleCollapsedBlock();
+
+ QBasicTimer autoScrollTimer;
+ void updateMarksLineNumber();
+ void updateMarksBlock(const QTextBlock &block);
+ uint m_marksVisible : 1;
+ uint m_codeFoldingVisible : 1;
+ uint m_revisionsVisible : 1;
+ uint m_lineNumbersVisible : 1;
+ uint m_highlightCurrentLine : 1;
+ uint m_requestMarkEnabled : 1;
+ uint m_lineSeparatorsAllowed : 1;
+ int m_visibleWrapColumn;
+
+ QTextCharFormat m_ifdefedOutFormat;
+
+ QRegExp m_searchExpr;
+ QTextDocument::FindFlags m_findFlags;
+ QTextCharFormat m_searchResultFormat;
+ QTextCharFormat m_searchScopeFormat;
+ QTextCharFormat m_currentLineFormat;
+ void highlightSearchResults(const QTextBlock &block,
+ QVector<QTextLayout::FormatRange> *selections);
+
+ BaseTextEditorEditable *m_editable;
+
+ QObject *m_actionHack;
+
+ QList<QTextEdit::ExtraSelection> m_extraSelections;
+ QList<QTextEdit::ExtraSelection> m_extraExtraSelections;
+
+ // block selection mode
+ bool m_inBlockSelectionMode;
+ bool m_lastEventWasBlockSelectionEvent;
+ int m_blockSelectionExtraX;
+ void clearBlockSelection();
+ QString copyBlockSelection();
+ void removeBlockSelection(const QString &text = QString());
+
+ QTextCursor m_findScope;
+
+ void moveCursorVisible();
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // BASETEXTEDITOR_P_H
diff --git a/src/plugins/texteditor/basetextmark.cpp b/src/plugins/texteditor/basetextmark.cpp
new file mode 100644
index 0000000000..4110480332
--- /dev/null
+++ b/src/plugins/texteditor/basetextmark.cpp
@@ -0,0 +1,136 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "basetextmark.h"
+#include <coreplugin/editormanager/editormanager.h>
+#include <extensionsystem/pluginmanager.h>
+#include <coreplugin/icore.h>
+#include <QtCore/QTimer>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+BaseTextMark::BaseTextMark()
+ : m_markableInterface(0), m_internalMark(0), m_init(false)
+{
+
+}
+
+BaseTextMark::BaseTextMark(const QString &filename, int line)
+ : m_markableInterface(0), m_internalMark(0), m_fileName(filename), m_line(line), m_init(false)
+{
+ // Why is this?
+ QTimer::singleShot(0, this, SLOT(init()));
+}
+
+void BaseTextMark::init()
+{
+ m_init = true;
+ Core::EditorManager *em = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->editorManager();
+ connect(em, SIGNAL(editorOpened(Core::IEditor *)), this, SLOT(editorOpened(Core::IEditor *)));
+
+ foreach(Core::IEditor *editor, em->openedEditors()) {
+ editorOpened(editor);
+ }
+}
+
+void BaseTextMark::editorOpened(Core::IEditor *editor)
+{
+ if (editor->file()->fileName() != m_fileName)
+ return;
+ if (ITextEditor *textEditor = qobject_cast<ITextEditor *>(editor)) {
+ if (m_markableInterface == 0) { // We aren't added to something
+ m_markableInterface = textEditor->markableInterface();
+ m_internalMark = new InternalMark(this);
+ m_markableInterface->addMark(m_internalMark, m_line);
+ }
+ }
+}
+
+void BaseTextMark::childRemovedFromEditor(InternalMark *mark)
+{
+ Q_UNUSED(mark)
+ // m_internalMark was removed from the editor
+ delete m_internalMark;
+ m_markableInterface = 0;
+ m_internalMark = 0;
+ removedFromEditor();
+}
+
+void BaseTextMark::documentClosingFor(InternalMark *mark)
+{
+ Q_UNUSED(mark)
+ // the document is closing
+ delete m_internalMark;
+ m_markableInterface = 0;
+ m_internalMark = 0;
+}
+
+BaseTextMark::~BaseTextMark()
+{
+ // oha we are deleted
+ if (m_markableInterface)
+ m_markableInterface->removeMark(m_internalMark);
+ delete m_internalMark;
+ m_internalMark = 0;
+ m_markableInterface = 0;
+}
+
+//#include <QDebug>
+
+void BaseTextMark::updateMarker()
+{
+ //qDebug()<<"BaseTextMark::updateMarker()"<<m_markableInterface<<m_internalMark;
+ if (m_markableInterface)
+ m_markableInterface->updateMark(m_internalMark);
+}
+
+void BaseTextMark::moveMark(const QString & /* filename */, int /* line */)
+{
+ Core::EditorManager *em = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>()->editorManager();
+ if (!m_init) {
+ connect(em, SIGNAL(editorOpened(Core::IEditor *)), this, SLOT(editorOpened(Core::IEditor *)));
+ m_init = true;
+ }
+
+
+ if (m_markableInterface)
+ m_markableInterface->removeMark(m_internalMark);
+ m_markableInterface = 0;
+ // This is only necessary since m_internalMark is created in ediorOpened
+ delete m_internalMark;
+ m_internalMark = 0;
+
+ foreach(Core::IEditor *editor, em->openedEditors()) {
+ editorOpened(editor);
+ }
+}
diff --git a/src/plugins/texteditor/basetextmark.h b/src/plugins/texteditor/basetextmark.h
new file mode 100644
index 0000000000..763e3eec47
--- /dev/null
+++ b/src/plugins/texteditor/basetextmark.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef BASETEXTMARK_H
+#define BASETEXTMARK_H
+
+#include "itexteditor.h"
+
+namespace TextEditor {
+
+class ITextMarkable;
+
+namespace Internal {
+class InternalMark;
+}
+
+class TEXTEDITOR_EXPORT BaseTextMark : public QObject
+{
+ friend class Internal::InternalMark;
+ Q_OBJECT
+public:
+ BaseTextMark();
+ BaseTextMark(const QString &filename, int line);
+ ~BaseTextMark();
+
+ // return your icon here
+ virtual QIcon icon() const = 0;
+
+ // called if the linenumber changes
+ virtual void updateLineNumber(int lineNumber) = 0;
+
+ // called whenever the text of the block for the marker changed
+ virtual void updateBlock(const QTextBlock &block) = 0;
+
+ // called if the block containing this mark has been removed
+ // if this also removes your mark call this->deleteLater();
+ virtual void removedFromEditor() = 0;
+ // call this if the icon has changed.
+ void updateMarker();
+ // access to internal data
+ QString fileName() const { return m_fileName; }
+ int lineNumber() const { return m_line; }
+
+ void moveMark(const QString &filename, int line);
+private slots:
+ void editorOpened(Core::IEditor *editor);
+ void init();
+private:
+ void childRemovedFromEditor(Internal::InternalMark *mark);
+ void documentClosingFor(Internal::InternalMark *mark);
+
+ ITextMarkable *m_markableInterface;
+ Internal::InternalMark *m_internalMark;
+
+ QString m_fileName;
+ int m_line;
+ bool m_init;
+};
+
+namespace Internal {
+
+class InternalMark : public ITextMark
+{
+public:
+ InternalMark(BaseTextMark *parent)
+ : m_parent(parent)
+ {
+ }
+
+ ~InternalMark()
+ {
+ }
+
+ virtual QIcon icon() const
+ {
+ return m_parent->icon();
+ }
+
+ virtual void updateLineNumber(int lineNumber)
+ {
+ return m_parent->updateLineNumber(lineNumber);
+ }
+
+ virtual void updateBlock(const QTextBlock &block)
+ {
+ return m_parent->updateBlock(block);
+ }
+
+ virtual void removedFromEditor()
+ {
+ m_parent->childRemovedFromEditor(this);
+ }
+
+ virtual void documentClosing()
+ {
+ m_parent->documentClosingFor(this);
+ }
+private:
+ BaseTextMark *m_parent;
+};
+}
+}
+#endif // BASETEXTMARK_H
diff --git a/src/plugins/texteditor/codecselector.cpp b/src/plugins/texteditor/codecselector.cpp
new file mode 100644
index 0000000000..5893fa5b71
--- /dev/null
+++ b/src/plugins/texteditor/codecselector.cpp
@@ -0,0 +1,179 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "codecselector.h"
+#include "basetextdocument.h"
+
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QTextCodec>
+#include <QtGui/QPushButton>
+#include <QtGui/QScrollBar>
+#include <QtGui/QVBoxLayout>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+
+namespace TextEditor {
+ namespace Internal {
+
+ /* custom class to make sure the width is wide enough for the
+ * contents. Should be easier with Qt. */
+ class CodecListWidget : public QListWidget {
+ public:
+ CodecListWidget(QWidget *parent):QListWidget(parent){}
+ QSize sizeHint() const {
+ return QListWidget::sizeHint().expandedTo(
+ QSize(sizeHintForColumn(0) + verticalScrollBar()->sizeHint().width() + 4, 0));
+ }
+ };
+ }
+}
+
+CodecSelector::CodecSelector(QWidget *parent, BaseTextDocument *doc)
+ : QDialog(parent)
+{
+ m_hasDecodingError = doc->hasDecodingError();
+ m_isModified = doc->isModified();
+
+ QByteArray buf;
+ if (m_hasDecodingError)
+ buf = doc->decodingErrorSample();
+
+ setWindowTitle(tr("Text Encoding"));
+ m_label = new QLabel(this);
+ QString decodingErrorHint;
+ if (m_hasDecodingError)
+ decodingErrorHint = tr("\nThe following encodings are likely to fit:");
+ m_label->setText(tr("Select encoding for \"%1\".%2").arg(QFileInfo(doc->fileName()).fileName()).arg(decodingErrorHint));
+
+ m_listWidget = new CodecListWidget(this);
+
+ QStringList encodings;
+
+ QList<int> mibs = QTextCodec::availableMibs();
+ qSort(mibs);
+ QList<int> sortedMibs;
+ foreach(int mib, mibs)
+ if (mib >= 0)
+ sortedMibs += mib;
+ foreach(int mib, mibs)
+ if (mib < 0)
+ sortedMibs += mib;
+
+ int currentIndex = -1;
+ foreach(int mib, sortedMibs) {
+ QTextCodec *c = QTextCodec::codecForMib(mib);
+ if (!buf.isEmpty()) {
+
+ // slow, should use a feature from QTextCodec or QTextDecoder (but those are broken currently)
+ QByteArray verifyBuf = c->fromUnicode(c->toUnicode(buf));
+ // the minSize trick lets us ignore unicode headers
+ int minSize = qMin(verifyBuf.size(), buf.size());
+ if (minSize < buf.size() - 4
+ || memcmp(verifyBuf.constData() + verifyBuf.size() - minSize,
+ buf.constData() + buf.size() - minSize, minSize))
+ continue;
+ }
+ QString names = QString::fromLatin1(c->name());
+ foreach(QByteArray alias, c->aliases()) {
+ names += QLatin1String(" / ") + QString::fromLatin1(alias);
+ }
+ if (doc->codec() == c)
+ currentIndex = encodings.count();
+ encodings << names;
+ }
+ m_listWidget->addItems(encodings);
+ if (currentIndex >= 0)
+ m_listWidget->setCurrentRow(currentIndex);
+
+ connect(m_listWidget, SIGNAL(itemSelectionChanged()), this, SLOT(updateButtons()));
+
+ m_dialogButtonBox = new QDialogButtonBox(this);
+ m_reloadButton = m_dialogButtonBox->addButton(tr("Reload with Encoding"), QDialogButtonBox::DestructiveRole);
+ m_saveButton = m_dialogButtonBox->addButton(tr("Save with Encoding"), QDialogButtonBox::DestructiveRole);
+ m_dialogButtonBox->addButton(QDialogButtonBox::Cancel);
+ connect(m_dialogButtonBox, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*)));
+
+ QVBoxLayout *vbox = new QVBoxLayout(this);
+ vbox->addWidget(m_label);
+ vbox->addWidget(m_listWidget);
+ vbox->addWidget(m_dialogButtonBox);
+
+ updateButtons();
+}
+
+
+
+CodecSelector::~CodecSelector()
+{
+}
+
+void CodecSelector::updateButtons()
+{
+ bool hasCodec = (selectedCodec() != 0);
+ m_reloadButton->setEnabled(!m_isModified && hasCodec);
+ m_saveButton->setEnabled(!m_hasDecodingError && hasCodec);
+}
+
+QTextCodec *CodecSelector::selectedCodec() const
+{
+ if (QListWidgetItem *item = m_listWidget->currentItem()) {
+ if (!item->isSelected())
+ return 0;
+ QString codecName = item->text();
+ if (codecName.contains(QLatin1String(" / ")))
+ codecName = codecName.left(codecName.indexOf(QLatin1String(" / ")));
+ return QTextCodec::codecForName(codecName.toLatin1());
+ }
+ return 0;
+}
+
+
+CodecSelector::Result CodecSelector::exec()
+{
+ return (Result) QDialog::exec();
+}
+
+
+void CodecSelector::buttonClicked(QAbstractButton *button)
+{
+ Result result = Cancel;
+ if (button == m_reloadButton)
+ result = Reload;
+ if (button == m_saveButton)
+ result = Save;
+ done(result);
+}
+
diff --git a/src/plugins/texteditor/codecselector.h b/src/plugins/texteditor/codecselector.h
new file mode 100644
index 0000000000..aa873b3a2b
--- /dev/null
+++ b/src/plugins/texteditor/codecselector.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef CODECSELECTOR_H
+#define CODECSELECTOR_H
+
+#include <QtGui/QDialog>
+#include <QtGui/QLabel>
+#include <QtGui/QDialogButtonBox>
+#include <QtGui/QListWidget>
+
+namespace TextEditor {
+
+class BaseTextDocument;
+
+namespace Internal {
+
+class CodecSelector : public QDialog
+{
+ Q_OBJECT
+
+public:
+
+ CodecSelector(QWidget *parent, BaseTextDocument *doc);
+ ~CodecSelector();
+
+ QTextCodec *selectedCodec() const;
+
+ enum Result {
+ Cancel, Reload, Save
+ };
+
+ Result exec();
+
+private slots:
+ void updateButtons();
+ void buttonClicked(QAbstractButton *button);
+
+private:
+ bool m_hasDecodingError;
+ bool m_isModified;
+ QLabel *m_label;
+ QListWidget *m_listWidget;
+ QDialogButtonBox *m_dialogButtonBox;
+ QAbstractButton *m_reloadButton;
+ QAbstractButton *m_saveButton;
+};
+
+
+
+
+
+}
+}
+
+#endif // CODECSELECTOR_H
diff --git a/src/plugins/texteditor/completionsupport.cpp b/src/plugins/texteditor/completionsupport.cpp
new file mode 100644
index 0000000000..6c9972d7eb
--- /dev/null
+++ b/src/plugins/texteditor/completionsupport.cpp
@@ -0,0 +1,171 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "completionsupport.h"
+#include "completionwidget.h"
+#include "icompletioncollector.h"
+
+#include <coreplugin/icore.h>
+#include <texteditor/itexteditable.h>
+
+#include <QString>
+#include <QList>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+
+CompletionSupport *CompletionSupport::instance(Core::ICore *core)
+{
+ static CompletionSupport *m_instance = 0;
+ if (!m_instance) {
+ m_instance = new CompletionSupport(core);
+ }
+ return m_instance;
+}
+
+CompletionSupport::CompletionSupport(Core::ICore *core)
+ : QObject(core),
+ m_completionList(0),
+ m_startPosition(0),
+ m_checkCompletionTrigger(false),
+ m_editor(0)
+{
+ m_completionCollector = core->pluginManager()->getObject<ICompletionCollector>();
+}
+
+void CompletionSupport::performCompletion(const CompletionItem &item)
+{
+ item.m_collector->complete(item);
+ m_checkCompletionTrigger = true;
+}
+
+void CompletionSupport::cleanupCompletions()
+{
+ if (m_completionList)
+ disconnect(m_completionList, SIGNAL(destroyed(QObject*)),
+ this, SLOT(cleanupCompletions()));
+
+ m_completionList = 0;
+ m_completionCollector->cleanup();
+
+ if (m_checkCompletionTrigger) {
+ m_checkCompletionTrigger = false;
+
+ // Only check for completion trigger when some text was entered
+ if (m_editor->position() > m_startPosition)
+ autoComplete(m_editor, false);
+ }
+}
+
+void CompletionSupport::autoComplete(ITextEditable *editor, bool forced)
+{
+ if (!m_completionCollector)
+ return;
+
+ m_editor = editor;
+ QList<CompletionItem> completionItems;
+
+ if (!m_completionList) {
+ if (!forced && !m_completionCollector->triggersCompletion(editor))
+ return;
+
+ m_startPosition = m_completionCollector->startCompletion(editor);
+ completionItems = getCompletions();
+
+ Q_ASSERT(m_startPosition != -1 || completionItems.size() == 0);
+
+ if (completionItems.isEmpty()) {
+ cleanupCompletions();
+ return;
+ }
+
+ m_completionList = new CompletionWidget(this, editor);
+
+ connect(m_completionList, SIGNAL(itemSelected(TextEditor::CompletionItem)),
+ this, SLOT(performCompletion(TextEditor::CompletionItem)));
+ connect(m_completionList, SIGNAL(completionListClosed()),
+ this, SLOT(cleanupCompletions()));
+
+ // Make sure to clean up the completions if the list is destroyed without
+ // emitting completionListClosed (can happen when no focus out event is received,
+ // for example when switching applications on the Mac)
+ connect(m_completionList, SIGNAL(destroyed(QObject*)),
+ this, SLOT(cleanupCompletions()));
+ } else {
+ completionItems = getCompletions();
+
+ if (completionItems.isEmpty()) {
+ m_completionList->closeList();
+ return;
+ }
+ }
+
+ m_completionList->setCompletionItems(completionItems);
+
+ // Partially complete when completion was forced
+ if (forced && m_completionCollector->partiallyComplete(completionItems)) {
+ m_checkCompletionTrigger = true;
+ m_completionList->closeList();
+ } else {
+ m_completionList->showCompletions(m_startPosition);
+ }
+}
+
+static bool completionItemLessThan(const CompletionItem &i1, const CompletionItem &i2)
+{
+ // The order is case-insensitive in principle, but case-sensitive when this would otherwise mean equality
+ const int c = i1.m_text.compare(i2.m_text, Qt::CaseInsensitive);
+ return c ? c < 0 : i1.m_text < i2.m_text;
+}
+
+QList<CompletionItem> CompletionSupport::getCompletions() const
+{
+ QList<CompletionItem> completionItems;
+
+ m_completionCollector->completions(&completionItems);
+
+ qStableSort(completionItems.begin(), completionItems.end(), completionItemLessThan);
+
+ // Remove duplicates
+ QString lastKey;
+ QList<CompletionItem> uniquelist;
+
+ foreach (const CompletionItem item, completionItems) {
+ if (item.m_text != lastKey) {
+ uniquelist.append(item);
+ lastKey = item.m_text;
+ }
+ }
+
+ return uniquelist;
+}
diff --git a/src/plugins/texteditor/completionsupport.h b/src/plugins/texteditor/completionsupport.h
new file mode 100644
index 0000000000..d3083630b6
--- /dev/null
+++ b/src/plugins/texteditor/completionsupport.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPLETIONSUPPORT_H
+#define COMPLETIONSUPPORT_H
+
+#include <texteditor/texteditor_global.h>
+#include <QtCore/QObject>
+
+namespace Core { class ICore; }
+
+namespace TextEditor {
+
+struct CompletionItem;
+class ICompletionCollector;
+class ITextEditable;
+
+namespace Internal {
+
+class CompletionWidget;
+
+/* Completion support is responsible for querying the list of completion collectors
+ and popping up the CompletionWidget with the available completions.
+ */
+class TEXTEDITOR_EXPORT CompletionSupport : public QObject
+{
+ Q_OBJECT
+
+public:
+ CompletionSupport(Core::ICore *core);
+
+ static CompletionSupport *instance(Core::ICore *core);
+public slots:
+ void autoComplete(ITextEditable *editor, bool forced);
+
+private slots:
+ void performCompletion(const TextEditor::CompletionItem &item);
+ void cleanupCompletions();
+
+private:
+ QList<CompletionItem> getCompletions() const;
+
+ CompletionWidget *m_completionList;
+ int m_startPosition;
+ bool m_checkCompletionTrigger; // Whether to check for completion trigger after cleanup
+ ITextEditable *m_editor;
+ ICompletionCollector *m_completionCollector;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // COMPLETIONSUPPORT_H
+
diff --git a/src/plugins/texteditor/completionwidget.cpp b/src/plugins/texteditor/completionwidget.cpp
new file mode 100644
index 0000000000..939123a5cf
--- /dev/null
+++ b/src/plugins/texteditor/completionwidget.cpp
@@ -0,0 +1,264 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "completionwidget.h"
+#include "completionsupport.h"
+#include "icompletioncollector.h"
+
+#include <texteditor/itexteditable.h>
+
+#include <QtCore/QEvent>
+#include <QtGui/QKeyEvent>
+#include <QtGui/QApplication>
+#include <QtGui/QVBoxLayout>
+
+#include <limits.h>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+#define NUMBER_OF_VISIBLE_ITEMS 10
+
+class AutoCompletionModel : public QAbstractListModel
+{
+public:
+ AutoCompletionModel(QObject *parent, const QList<CompletionItem> &items);
+
+ inline const CompletionItem &itemAt(const QModelIndex &index) const
+ { return m_items.at(index.row()); }
+
+ void setItems(const QList<CompletionItem> &items);
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+private:
+ QList<CompletionItem> m_items;
+};
+
+AutoCompletionModel::AutoCompletionModel(QObject *parent, const QList<CompletionItem> &items)
+ : QAbstractListModel(parent)
+{
+ m_items = items;
+}
+
+void AutoCompletionModel::setItems(const QList<CompletionItem> &items)
+{
+ m_items = items;
+ reset();
+}
+
+int AutoCompletionModel::rowCount(const QModelIndex &) const
+{
+ return m_items.count();
+}
+
+QVariant AutoCompletionModel::data(const QModelIndex &index, int role) const
+{
+ if (index.row() >= m_items.count())
+ return QVariant();
+
+ if (role == Qt::DisplayRole) {
+ return itemAt(index).m_text;
+ } else if (role == Qt::DecorationRole) {
+ return itemAt(index).m_icon;
+ } else if (role == Qt::ToolTipRole) {
+ return itemAt(index).m_details;
+ }
+
+ return QVariant();
+}
+
+CompletionWidget::CompletionWidget(CompletionSupport *support, ITextEditable *editor)
+ : QListView(),
+ m_blockFocusOut(false),
+ m_editor(editor),
+ m_editorWidget(editor->widget()),
+ m_model(0),
+ m_support(support)
+{
+ Q_ASSERT(m_editorWidget);
+
+ setUniformItemSizes(true);
+ setSelectionBehavior(QAbstractItemView::SelectItems);
+ setSelectionMode(QAbstractItemView::SingleSelection);
+
+ connect(this, SIGNAL(activated(const QModelIndex &)),
+ this, SLOT(completionActivated(const QModelIndex &)));
+
+ // We disable the frame on this list view and use a QFrame around it instead.
+ // This fixes the missing frame on Mac and improves the look with QGTKStyle.
+ m_popupFrame = new QFrame(0, Qt::Popup);
+ m_popupFrame->setFrameStyle(frameStyle());
+ setFrameStyle(QFrame::NoFrame);
+ setParent(m_popupFrame);
+ m_popupFrame->setObjectName("m_popupFrame");
+ m_popupFrame->setAttribute(Qt::WA_DeleteOnClose);
+ QVBoxLayout *layout = new QVBoxLayout(m_popupFrame);
+ layout->setMargin(0);
+ layout->addWidget(this);
+
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+}
+
+bool CompletionWidget::event(QEvent *e)
+{
+ if (m_blockFocusOut)
+ return QListView::event(e);
+
+ bool forwardKeys = true;
+ if (e->type() == QEvent::FocusOut) {
+ closeList();
+ return true;
+ } else if (e->type() == QEvent::KeyPress) {
+ QKeyEvent *ke = static_cast<QKeyEvent *>(e);
+ switch (ke->key()) {
+ case Qt::Key_Escape:
+ closeList();
+ return true;
+ case Qt::Key_Right:
+ case Qt::Key_Left:
+ break;
+ case Qt::Key_Tab:
+ case Qt::Key_Return:
+ //independently from style, accept current entry if return is pressed
+ closeList(currentIndex());
+ return true;
+ case Qt::Key_Up:
+ case Qt::Key_Down:
+ case Qt::Key_Enter:
+ case Qt::Key_PageDown:
+ case Qt::Key_PageUp:
+ forwardKeys = false;
+ break;
+ default:
+ break;
+ }
+
+ if (forwardKeys) {
+ m_blockFocusOut = true;
+ QApplication::sendEvent(m_editorWidget, e);
+ m_blockFocusOut = false;
+
+ // Have the completion support update the list of items
+ m_support->autoComplete(m_editor, false);
+
+ return true;
+ }
+ }
+ return QListView::event(e);
+}
+
+void CompletionWidget::keyboardSearch(const QString &search)
+{
+ Q_UNUSED(search);
+}
+
+void CompletionWidget::closeList(const QModelIndex &index)
+{
+ m_blockFocusOut = true;
+ if (index.isValid())
+ emit itemSelected(m_model->itemAt(index));
+
+ close();
+ if (m_popupFrame) {
+ m_popupFrame->close();
+ m_popupFrame = 0;
+ }
+
+ emit completionListClosed();
+
+ m_blockFocusOut = false;
+}
+
+void CompletionWidget::setCompletionItems(const QList<TextEditor::CompletionItem> &completionItems)
+{
+ if (!m_model) {
+ m_model = new AutoCompletionModel(this, completionItems);
+ setModel(m_model);
+ } else {
+ m_model->setItems(completionItems);
+ }
+
+ // Select the first of the most relevant completion items
+ int relevance = INT_MIN;
+ int mostRelevantIndex = 0;
+ for (int i = 0; i < completionItems.size(); ++i) {
+ const CompletionItem &item = completionItems.at(i);
+ if (item.m_relevance > relevance) {
+ relevance = item.m_relevance;
+ mostRelevantIndex = i;
+ }
+ }
+
+ setCurrentIndex(m_model->index(mostRelevantIndex));
+}
+
+void CompletionWidget::showCompletions(int startPos)
+{
+ const QPoint &pos = m_editor->cursorRect(startPos).bottomLeft();
+ m_popupFrame->move(pos.x() - 16, pos.y());
+ m_popupFrame->setMinimumSize(1, 1);
+ setMinimumSize(1, 1);
+
+ updateSize();
+
+ m_popupFrame->show();
+ show();
+ setFocus();
+}
+
+void CompletionWidget::updateSize()
+{
+ int visibleItems = m_model->rowCount();
+ if (visibleItems > NUMBER_OF_VISIBLE_ITEMS)
+ visibleItems = NUMBER_OF_VISIBLE_ITEMS;
+
+ const QStyleOptionViewItem &option = viewOptions();
+
+ QSize shint;
+ for (int i = 0; i < visibleItems; ++i) {
+ QSize tmp = itemDelegate()->sizeHint(option, m_model->index(i));
+ if (shint.width() < tmp.width())
+ shint = tmp;
+ }
+
+ const int width = (shint.width() + (m_popupFrame->frameWidth() * 2) + 30);
+ const int height = (shint.height() * visibleItems) + m_popupFrame->frameWidth() * 2;
+
+ m_popupFrame->resize(width, height);
+}
+
+void CompletionWidget::completionActivated(const QModelIndex &index)
+{
+ closeList(index);
+}
diff --git a/src/plugins/texteditor/completionwidget.h b/src/plugins/texteditor/completionwidget.h
new file mode 100644
index 0000000000..4a41ffad34
--- /dev/null
+++ b/src/plugins/texteditor/completionwidget.h
@@ -0,0 +1,90 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPLETIONWIDGET_H
+#define COMPLETIONWIDGET_H
+
+#include <QtGui/QListView>
+#include <QPointer>
+
+class AutoCompletionModel;
+
+namespace TextEditor {
+
+struct CompletionItem;
+class ITextEditable;
+
+namespace Internal {
+
+class CompletionSupport;
+
+/* The completion widget is responsible for showing a list of possible completions.
+ It is only used by the CompletionSupport.
+ */
+class CompletionWidget : public QListView
+{
+ Q_OBJECT
+
+public:
+ CompletionWidget(CompletionSupport *support, ITextEditable *editor);
+
+ void setCompletionItems(const QList<TextEditor::CompletionItem> &completionitems);
+ void showCompletions(int startPos);
+ void keyboardSearch(const QString &search);
+ void closeList(const QModelIndex &index = QModelIndex());
+
+protected:
+ bool event(QEvent *e);
+
+signals:
+ void itemSelected(const TextEditor::CompletionItem &item);
+ void completionListClosed();
+
+private slots:
+ void completionActivated(const QModelIndex &index);
+
+private:
+ void updateSize();
+
+ QPointer<QFrame> m_popupFrame;
+ bool m_blockFocusOut;
+ ITextEditable *m_editor;
+ QWidget *m_editorWidget;
+ AutoCompletionModel *m_model;
+ CompletionSupport *m_support;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // COMPLETIONWIDGET_H
+
diff --git a/src/plugins/texteditor/displaysettings.cpp b/src/plugins/texteditor/displaysettings.cpp
new file mode 100644
index 0000000000..af74e4b2ab
--- /dev/null
+++ b/src/plugins/texteditor/displaysettings.cpp
@@ -0,0 +1,108 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "displaysettings.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QString>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextDocument>
+
+static const char * const displayLineNumbersKey = "DisplayLineNumbers";
+static const char * const textWrappingKey = "TextWrapping";
+static const char * const showWrapColumnKey = "ShowWrapColumn";
+static const char * const wrapColumnKey = "WrapColumn";
+static const char * const visualizeWhitespaceKey = "VisualizeWhitespace";
+static const char * const displayFoldingMarkersKey = "DisplayFoldingMarkers";
+static const char * const highlightCurrentLineKey = "HighlightCurrentLineKey";
+static const char * const groupPostfix = "DisplaySettings";
+
+namespace TextEditor {
+
+DisplaySettings::DisplaySettings() :
+ m_displayLineNumbers(true),
+ m_textWrapping(false),
+ m_showWrapColumn(false),
+ m_wrapColumn(80),
+ m_visualizeWhitespace(false),
+ m_displayFoldingMarkers(true),
+ m_highlightCurrentLine(true)
+{
+}
+
+void DisplaySettings::toSettings(const QString &category, QSettings *s) const
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ s->beginGroup(group);
+ s->setValue(QLatin1String(displayLineNumbersKey), m_displayLineNumbers);
+ s->setValue(QLatin1String(textWrappingKey), m_textWrapping);
+ s->setValue(QLatin1String(showWrapColumnKey), m_showWrapColumn);
+ s->setValue(QLatin1String(wrapColumnKey), m_wrapColumn);
+ s->setValue(QLatin1String(visualizeWhitespaceKey), m_visualizeWhitespace);
+ s->setValue(QLatin1String(displayFoldingMarkersKey), m_displayFoldingMarkers);
+ s->setValue(QLatin1String(highlightCurrentLineKey), m_highlightCurrentLine);
+ s->endGroup();
+}
+
+void DisplaySettings::fromSettings(const QString &category, const QSettings *s)
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ group += QLatin1Char('/');
+
+ *this = DisplaySettings(); // Assign defaults
+
+ m_displayLineNumbers = s->value(group + QLatin1String(displayLineNumbersKey), m_displayLineNumbers).toBool();
+ m_textWrapping = s->value(group + QLatin1String(textWrappingKey), m_textWrapping).toBool();
+ m_showWrapColumn = s->value(group + QLatin1String(showWrapColumnKey), m_showWrapColumn).toBool();
+ m_wrapColumn = s->value(group + QLatin1String(wrapColumnKey), m_wrapColumn).toInt();
+ m_visualizeWhitespace = s->value(group + QLatin1String(visualizeWhitespaceKey), m_visualizeWhitespace).toBool();
+ m_displayFoldingMarkers = s->value(group + QLatin1String(displayFoldingMarkersKey), m_displayFoldingMarkers).toBool();
+ m_highlightCurrentLine = s->value(group + QLatin1String(highlightCurrentLineKey), m_highlightCurrentLine).toBool();
+}
+
+bool DisplaySettings::equals(const DisplaySettings &ds) const
+{
+ return m_displayLineNumbers == ds.m_displayLineNumbers
+ && m_textWrapping == ds.m_textWrapping
+ && m_showWrapColumn == ds.m_showWrapColumn
+ && m_wrapColumn == ds.m_wrapColumn
+ && m_visualizeWhitespace == ds.m_visualizeWhitespace
+ && m_displayFoldingMarkers == ds.m_displayFoldingMarkers
+ && m_highlightCurrentLine == ds.m_highlightCurrentLine
+ ;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/displaysettings.h b/src/plugins/texteditor/displaysettings.h
new file mode 100644
index 0000000000..7c70126e5d
--- /dev/null
+++ b/src/plugins/texteditor/displaysettings.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef DISPLAYSETTINGS_H
+#define DISPLAYSETTINGS_H
+
+#include "texteditor_global.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+struct TEXTEDITOR_EXPORT DisplaySettings
+{
+ DisplaySettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, const QSettings *s);
+
+ bool m_displayLineNumbers;
+ bool m_textWrapping;
+ bool m_showWrapColumn;
+ int m_wrapColumn;
+ bool m_visualizeWhitespace;
+ bool m_displayFoldingMarkers;
+ bool m_highlightCurrentLine;
+
+ bool equals(const DisplaySettings &ds) const;
+};
+
+inline bool operator==(const DisplaySettings &t1, const DisplaySettings &t2) { return t1.equals(t2); }
+inline bool operator!=(const DisplaySettings &t1, const DisplaySettings &t2) { return !t1.equals(t2); }
+
+} // namespace TextEditor
+
+#endif // DISPLAYSETTINGS_H
diff --git a/src/plugins/texteditor/findinfiles.cpp b/src/plugins/texteditor/findinfiles.cpp
new file mode 100644
index 0000000000..6e11e40017
--- /dev/null
+++ b/src/plugins/texteditor/findinfiles.cpp
@@ -0,0 +1,144 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "findinfiles.h"
+
+#include <QtDebug>
+#include <QtCore/QDirIterator>
+#include <QtGui/QPushButton>
+#include <QtGui/QFileDialog>
+#include <QtGui/QVBoxLayout>
+
+using namespace Find;
+using namespace TextEditor::Internal;
+
+FindInFiles::FindInFiles(Core::ICore *core, SearchResultWindow *resultWindow)
+ : BaseFileFind(core, resultWindow),
+ m_configWidget(0),
+ m_directory(0)
+{
+}
+
+QString FindInFiles::name() const
+{
+ return tr("Files on Disk");
+}
+
+QKeySequence FindInFiles::defaultShortcut() const
+{
+ return QKeySequence();
+}
+
+void FindInFiles::findAll(const QString &txt, QTextDocument::FindFlags findFlags)
+{
+ updateComboEntries(m_directory, true);
+ BaseFileFind::findAll(txt, findFlags);
+}
+
+QStringList FindInFiles::files()
+{
+ QStringList fileList;
+ QDirIterator it(m_directory->currentText(),
+ fileNameFilters(),
+ QDir::Files|QDir::Readable,
+ QDirIterator::Subdirectories);
+ while (it.hasNext()) {
+ it.next();
+ fileList << it.filePath();
+ }
+ return fileList;
+}
+
+QWidget *FindInFiles::createConfigWidget()
+{
+ if (!m_configWidget) {
+ m_configWidget = new QWidget;
+ QGridLayout * const gridLayout = new QGridLayout(m_configWidget);
+ gridLayout->setMargin(0);
+ m_configWidget->setLayout(gridLayout);
+ gridLayout->addWidget(createRegExpWidget(), 0, 1, 1, 2);
+
+ gridLayout->addWidget(new QLabel(tr("Directory:")), 1, 0, Qt::AlignRight);
+ m_directory = new QComboBox;
+ m_directory->setEditable(true);
+ m_directory->setMaxCount(30);
+ m_directory->setMinimumContentsLength(10);
+ m_directory->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon);
+ m_directory->setInsertPolicy(QComboBox::InsertAtTop);
+ m_directory->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ m_directory->setModel(&m_directoryStrings);
+ syncComboWithSettings(m_directory, m_directorySetting);
+ gridLayout->addWidget(m_directory, 1, 1);
+ QPushButton *browseButton = new QPushButton(tr("Browse"));
+ gridLayout->addWidget(browseButton, 1, 2);
+ connect(browseButton, SIGNAL(clicked()), this, SLOT(openFileBrowser()));
+
+ QLabel * const filePatternLabel = new QLabel(tr("File pattern:"));
+ filePatternLabel->setMinimumWidth(80);
+ filePatternLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
+ filePatternLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
+ gridLayout->addWidget(filePatternLabel, 2, 0);
+ gridLayout->addWidget(createPatternWidget(), 2, 1, 1, 2);
+ m_configWidget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ }
+ return m_configWidget;
+}
+
+void FindInFiles::openFileBrowser()
+{
+ if (!m_directory)
+ return;
+ QString dir = QFileDialog::getExistingDirectory(m_configWidget,
+ tr("Directory to search"));
+ if (!dir.isEmpty())
+ m_directory->setEditText(dir);
+}
+
+void FindInFiles::writeSettings(QSettings *settings)
+{
+ settings->beginGroup("FindInFiles");
+ writeCommonSettings(settings);
+ settings->setValue("directories", m_directoryStrings.stringList());
+ if (m_directory)
+ settings->setValue("currentDirectory", m_directory->currentText());
+ settings->endGroup();
+}
+
+void FindInFiles::readSettings(QSettings *settings)
+{
+ settings->beginGroup("FindInFiles");
+ readCommonSettings(settings, "*.cpp,*.h");
+ m_directoryStrings.setStringList(settings->value("directories").toStringList());
+ m_directorySetting = settings->value("currentDirectory").toString();
+ settings->endGroup();
+ syncComboWithSettings(m_directory, m_directorySetting);
+}
diff --git a/src/plugins/texteditor/findinfiles.h b/src/plugins/texteditor/findinfiles.h
new file mode 100644
index 0000000000..3d5bf0c940
--- /dev/null
+++ b/src/plugins/texteditor/findinfiles.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FINDINFILES_H
+#define FINDINFILES_H
+
+#include "basefilefind.h"
+
+#include <coreplugin/icore.h>
+#include <find/ifindfilter.h>
+#include <find/searchresultwindow.h>
+
+#include <QtCore/QPointer>
+#include <QtGui/QLabel>
+#include <QtGui/QComboBox>
+#include <QtGui/QStringListModel>
+
+
+namespace TextEditor {
+namespace Internal {
+
+class FindInFiles : public BaseFileFind
+{
+ Q_OBJECT
+
+public:
+ FindInFiles(Core::ICore *core, Find::SearchResultWindow *resultWindow);
+
+ QString name() const;
+
+ QKeySequence defaultShortcut() const;
+
+ void findAll(const QString &txt, QTextDocument::FindFlags findFlags);
+ QWidget *createConfigWidget();
+ void writeSettings(QSettings *settings);
+ void readSettings(QSettings *settings);
+
+protected:
+ QStringList files();
+
+private slots:
+ void openFileBrowser();
+
+private:
+ QStringListModel m_directoryStrings;
+ QString m_directorySetting;
+ QPointer<QWidget> m_configWidget;
+ QPointer<QComboBox> m_directory;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // FINDINFILES_H
diff --git a/src/plugins/texteditor/fontsettings.cpp b/src/plugins/texteditor/fontsettings.cpp
new file mode 100644
index 0000000000..1ced2cafd6
--- /dev/null
+++ b/src/plugins/texteditor/fontsettings.cpp
@@ -0,0 +1,277 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fontsettings.h"
+#include "fontsettingspage.h"
+
+#include <QtCore/QSettings>
+#include <QtGui/QTextCharFormat>
+
+static const char *fontFamilyKey = "FontFamily";
+static const char *fontSizeKey = "FontSize";
+static const char *trueString = "true";
+static const char *falseString = "false";
+
+namespace {
+#ifdef Q_WS_MAC
+ enum { DEFAULT_FONT_SIZE = 12 };
+ static const char *DEFAULT_FONT_FAMILY = "Monaco";
+#else
+#ifdef Q_OS_UNIX
+ enum { DEFAULT_FONT_SIZE = 9 };
+ static const char *DEFAULT_FONT_FAMILY = "Monospace";
+#else
+ enum { DEFAULT_FONT_SIZE = 10 };
+ static const char *DEFAULT_FONT_FAMILY = "Courier";
+#endif
+#endif
+} // anonymous namespace
+
+namespace TextEditor {
+
+// Format --
+Format::Format() :
+ m_foreground(Qt::black),
+ m_background(Qt::white),
+ m_bold(false),
+ m_italic(false)
+{
+}
+
+void Format::setForeground(const QColor &foreground)
+{
+ m_foreground = foreground;
+}
+
+void Format::setBackground(const QColor &background)
+{
+ m_background = background;
+}
+
+void Format::setBold(bool bold)
+{
+ m_bold = bold;
+}
+
+void Format::setItalic(bool italic)
+{
+ m_italic = italic;
+}
+
+static QString colorToString(const QColor &color) {
+ if (color.isValid())
+ return color.name();
+ return QLatin1String("invalid");
+}
+
+static QColor stringToColor(const QString &string) {
+ if (string == QLatin1String("invalid"))
+ return QColor();
+ return QColor(string);
+}
+
+QString Format::toString() const
+{
+ const QChar delimiter = QLatin1Char(';');
+ QString s = colorToString(m_foreground);
+ s += delimiter;
+ s += colorToString(m_background);
+ s += delimiter;
+ s += m_bold ? QLatin1String(trueString) : QLatin1String(falseString);
+ s += delimiter;
+ s += m_italic ? QLatin1String(trueString) : QLatin1String(falseString);
+ return s;
+}
+
+bool Format::fromString(const QString &str)
+{
+ *this = Format();
+
+ const QStringList lst = str.split(QLatin1Char(';'));
+ if (lst.count() != 4)
+ return false;
+
+ m_foreground = stringToColor(lst.at(0));
+ m_background = stringToColor(lst.at(1));
+ m_bold = lst.at(2) == QLatin1String(trueString);
+ m_italic = lst.at(3) == QLatin1String(trueString);
+ return true;
+}
+
+bool Format::equals(const Format &f) const
+{
+ return m_foreground == f.m_foreground && m_background == f.m_background &&
+ m_bold == f.m_bold && m_italic == f.m_italic;
+}
+// -- FontSettings
+FontSettings::FontSettings(const FormatDescriptions &fd) :
+ m_family(defaultFixedFontFamily()),
+ m_fontSize(DEFAULT_FONT_SIZE)
+{
+}
+
+void FontSettings::clear()
+{
+ m_family = defaultFixedFontFamily();
+ m_fontSize = DEFAULT_FONT_SIZE;
+ qFill(m_formats.begin(), m_formats.end(), Format());
+}
+
+void FontSettings::toSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ QSettings *s) const
+{
+ const int numFormats = m_formats.size();
+ Q_ASSERT(descriptions.size() == numFormats);
+ s->beginGroup(category);
+ if (m_family != defaultFixedFontFamily() || s->contains(QLatin1String(fontFamilyKey)))
+ s->setValue(QLatin1String(fontFamilyKey), m_family);
+
+ if (m_fontSize != DEFAULT_FONT_SIZE || s->contains(QLatin1String(fontSizeKey)))
+ s->setValue(QLatin1String(fontSizeKey), m_fontSize);
+
+ const Format defaultFormat;
+
+ foreach (const FormatDescription &desc, descriptions) {
+ QMap<QString, Format>::const_iterator i = m_formats.find(desc.name());
+ if (i != m_formats.end() && ((*i) != defaultFormat || s->contains(desc.name()))) {
+ s->setValue(desc.name(), (*i).toString());
+ }
+ }
+ s->endGroup();
+}
+
+bool FontSettings::fromSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ const QSettings *s)
+{
+ clear();
+
+ if (!s->childGroups().contains(category))
+ return false;
+
+ QString group = category;
+ group += QLatin1Char('/');
+
+ m_family = s->value(group + QLatin1String(fontFamilyKey), defaultFixedFontFamily()).toString();
+ m_fontSize = s->value(group + QLatin1String(QLatin1String(fontSizeKey)), m_fontSize).toInt();
+
+ foreach (const FormatDescription &desc, descriptions) {
+ const QString name = desc.name();
+ const QString fmt = s->value(group + name, QString()).toString();
+ if (fmt.isEmpty()) {
+ m_formats[name].setForeground(desc.foreground());
+ m_formats[name].setBackground(desc.background());
+ } else {
+ m_formats[name].fromString(fmt);
+ }
+ }
+ return true;
+}
+
+bool FontSettings::equals(const FontSettings &f) const
+{
+ return m_family == f.m_family
+ && m_fontSize == f.m_fontSize
+ && m_formats == f.m_formats;
+}
+
+QTextCharFormat FontSettings::toTextCharFormat(const QString &category) const
+{
+ const Format f = m_formats.value(category);
+ QTextCharFormat tf;
+ if (category == QLatin1String("Text")) {
+ tf.setFontFamily(m_family);
+ tf.setFontPointSize(m_fontSize);
+ }
+
+ if (f.foreground().isValid())
+ tf.setForeground(f.foreground());
+ if (f.background().isValid() && (category == QLatin1String("Text") || f.background() != m_formats.value(QLatin1String("Text")).background()))
+ tf.setBackground(f.background());
+ tf.setFontWeight(f.bold() ? QFont::Bold : QFont::Normal);
+ tf.setFontItalic(f.italic());
+ return tf;
+}
+
+QVector<QTextCharFormat> FontSettings::toTextCharFormats(const QVector<QString> &categories) const
+{
+ QVector<QTextCharFormat> rc;
+ const int size = categories.size();
+ rc.reserve(size);
+ for (int i = 0; i < size; i++)
+ rc.push_back(toTextCharFormat(categories.at(i)));
+ return rc;
+}
+
+QString FontSettings::family() const
+{
+ return m_family;
+}
+
+void FontSettings::setFamily(const QString &family)
+{
+ m_family = family;
+}
+
+int FontSettings::fontSize() const
+{
+ return m_fontSize;
+}
+
+void FontSettings::setFontSize(int size)
+{
+ m_fontSize = size;
+}
+
+Format &FontSettings::formatFor(const QString &category)
+{
+ return m_formats[category];
+}
+
+QString FontSettings::defaultFixedFontFamily()
+{
+ static QString rc;
+ if (rc.isEmpty()) {
+ QFont f(DEFAULT_FONT_FAMILY);
+ f.setStyleHint(QFont::TypeWriter);
+ rc = f.family();
+ }
+ return rc;
+}
+
+int FontSettings::defaultFontSize()
+{
+ return DEFAULT_FONT_SIZE;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/fontsettings.h b/src/plugins/texteditor/fontsettings.h
new file mode 100644
index 0000000000..1b9088b621
--- /dev/null
+++ b/src/plugins/texteditor/fontsettings.h
@@ -0,0 +1,149 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FONTSETTINGS_H
+#define FONTSETTINGS_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QMap>
+#include <QtCore/QVector>
+#include <QtGui/QColor>
+
+QT_BEGIN_NAMESPACE
+class QTextCharFormat;
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+class FormatDescription;
+
+// Format for a particular piece of text (text/comment, etc).
+class TEXTEDITOR_EXPORT Format
+{
+public:
+ Format();
+
+ QColor foreground() const { return m_foreground; }
+ void setForeground(const QColor &foreground);
+
+ QColor background() const { return m_background; }
+ void setBackground(const QColor &background);
+
+ bool bold() const { return m_bold; }
+ void setBold(bool bold);
+
+ bool italic() const { return m_italic; }
+ void setItalic(bool italic);
+
+ bool equals(const Format &f) const;
+
+ QString toString() const;
+ bool fromString(const QString &str);
+
+private:
+ QColor m_foreground;
+ QColor m_background;
+ bool m_bold;
+ bool m_italic;
+};
+
+inline bool operator==(const Format &f1, const Format &f2) { return f1.equals(f2); }
+inline bool operator!=(const Format &f1, const Format &f2) { return !f1.equals(f2); }
+
+/**
+ * Font settings (default font and enumerated list of formats).
+ */
+class TEXTEDITOR_EXPORT FontSettings
+{
+public:
+ typedef QList<FormatDescription> FormatDescriptions;
+
+ FontSettings(const FormatDescriptions &fd);
+ void clear();
+
+ void toSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ QSettings *s) const;
+
+ bool fromSettings(const QString &category,
+ const FormatDescriptions &descriptions,
+ const QSettings *s);
+
+ /**
+ * Returns the list of QTextCharFormats that corresponds to the list of
+ * requested format categories.
+ */
+ QVector<QTextCharFormat> toTextCharFormats(const QVector<QString> &categories) const;
+
+ /**
+ * Returns the QTextCharFormat of the given format category.
+ */
+ QTextCharFormat toTextCharFormat(const QString &category) const;
+
+ /**
+ * Returns the configured font family.
+ */
+ QString family() const;
+ void setFamily(const QString &family);
+
+ /**
+ * Returns the configured font size.
+ */
+ int fontSize() const;
+ void setFontSize(int size);
+
+ /**
+ * Returns the format for the given font category.
+ */
+ Format &formatFor(const QString &category);
+
+ bool equals(const FontSettings &f) const;
+
+ static QString defaultFixedFontFamily();
+ static int defaultFontSize();
+
+private:
+ QString m_family;
+ int m_fontSize;
+ QMap<QString, Format> m_formats;
+};
+
+inline bool operator==(const FontSettings &f1, const FontSettings &f2) { return f1.equals(f2); }
+inline bool operator!=(const FontSettings &f1, const FontSettings &f2) { return !f1.equals(f2); }
+
+} // namespace TextEditor
+
+#endif // FONTSETTINGS_H
diff --git a/src/plugins/texteditor/fontsettingspage.cpp b/src/plugins/texteditor/fontsettingspage.cpp
new file mode 100644
index 0000000000..1583328fc2
--- /dev/null
+++ b/src/plugins/texteditor/fontsettingspage.cpp
@@ -0,0 +1,465 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "fontsettingspage.h"
+#include "fontsettings.h"
+#include "texteditorconstants.h"
+#include "ui_fontsettingspage.h"
+
+#include <utils/settingsutils.h>
+
+#include <QtCore/QSettings>
+#include <QtCore/QTimer>
+#include <QtGui/QListWidget>
+#include <QtGui/QToolButton>
+#include <QtGui/QPalette>
+#include <QtGui/QCheckBox>
+#include <QtGui/QColorDialog>
+#include <QtGui/QTextEdit>
+#include <QtGui/QTextCharFormat>
+#include <QtGui/QComboBox>
+#include <QtGui/QFontDatabase>
+#include <QtGui/QPalette>
+
+static inline QString colorButtonStyleSheet(const QColor &bgColor)
+{
+ if (bgColor.isValid()) {
+ QString rc = QLatin1String("border: 2px solid black; border-radius: 2px; background:");
+ rc += bgColor.name();
+ return rc;
+ }
+ return QLatin1String("border: 2px dotted black; border-radius: 2px;");
+}
+
+namespace TextEditor {
+namespace Internal {
+
+class FontSettingsPagePrivate
+{
+public:
+ FontSettingsPagePrivate(const TextEditor::FormatDescriptions &fd,
+ const QString &name,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core);
+
+ Core::ICore *m_core;
+ const QString m_name;
+ const QString m_settingsGroup;
+ const QString m_category;
+ const QString m_trCategory;
+
+ TextEditor::FormatDescriptions m_descriptions;
+ FontSettings m_value;
+ FontSettings m_lastValue;
+ int m_curItem;
+ Ui::FontSettingsPage ui;
+};
+
+FontSettingsPagePrivate::FontSettingsPagePrivate(const TextEditor::FormatDescriptions &fd,
+ const QString &name,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core) :
+ m_core(core),
+ m_name(name),
+ m_settingsGroup(Core::Utils::settingsKey(category)),
+ m_category(category),
+ m_trCategory(trCategory),
+ m_descriptions(fd),
+ m_value(fd),
+ m_lastValue(fd),
+ m_curItem(-1)
+{
+ bool settingsFound = false;
+ if (m_core)
+ if (const QSettings *settings = m_core->settings())
+ settingsFound = m_value.fromSettings(m_settingsGroup, m_descriptions, settings);
+ if (!settingsFound) { // Apply defaults
+ foreach (const FormatDescription &f, m_descriptions) {
+ const QString name = f.name();
+ m_lastValue.formatFor(name).setForeground(f.foreground());
+ m_lastValue.formatFor(name).setBackground(f.background());
+ m_value.formatFor(name).setForeground(f.foreground());
+ m_value.formatFor(name).setBackground(f.background());
+ }
+ }
+
+ m_lastValue = m_value;
+}
+
+} // namespace Internal
+} // namespace TextEditor
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+// ------- FormatDescription
+FormatDescription::FormatDescription(const QString &name, const QString &trName, const QColor &color) :
+ m_name(name),
+ m_trName(trName)
+{
+ m_format.setForeground(color);
+}
+
+QString FormatDescription::name() const
+{
+ return m_name;
+}
+
+QString FormatDescription::trName() const
+{
+ return m_trName;
+}
+
+QColor FormatDescription::foreground() const
+{
+ if (m_name == QLatin1String("LineNumber"))
+ return QApplication::palette().dark().color();
+ if (m_name == QLatin1String("Parentheses"))
+ return QColor(Qt::red);
+ return m_format.foreground();
+}
+
+void FormatDescription::setForeground(const QColor &foreground)
+{
+ m_format.setForeground(foreground);
+}
+
+QColor FormatDescription::background() const
+{
+ if (m_name == QLatin1String(Constants::C_TEXT))
+ return Qt::white;
+ else if (m_name == QLatin1String(Constants::C_LINE_NUMBER))
+ return QApplication::palette().background().color();
+ else if (m_name == QLatin1String(Constants::C_SEARCH_RESULT))
+ return QColor(0xffef0b);
+ else if (m_name == QLatin1String(Constants::C_PARENTHESES))
+ return QColor(0xb4, 0xee, 0xb4);
+ else if (m_name == QLatin1String(Constants::C_CURRENT_LINE)
+ || m_name == QLatin1String(Constants::C_SEARCH_SCOPE)) {
+ const QPalette palette = QApplication::palette();
+ const QColor &fg = palette.color(QPalette::Highlight);
+ const QColor &bg = palette.color(QPalette::Base);
+
+ qreal smallRatio;
+ qreal largeRatio;
+ if (m_name == QLatin1String(Constants::C_CURRENT_LINE)) {
+ smallRatio = .15;
+ largeRatio = .3;
+ } else {
+ smallRatio = .05;
+ largeRatio = .4;
+ }
+ const qreal ratio = ((palette.color(QPalette::Text).value() < 128)
+ ^ (palette.color(QPalette::HighlightedText).value() < 128)) ? smallRatio : largeRatio;
+
+ const QColor &col = QColor::fromRgbF(fg.redF() * ratio + bg.redF() * (1 - ratio),
+ fg.greenF() * ratio + bg.greenF() * (1 - ratio),
+ fg.blueF() * ratio + bg.blueF() * (1 - ratio));
+ return col;
+ } else if (m_name == QLatin1String(Constants::C_SELECTION)) {
+ const QPalette palette = QApplication::palette();
+ return palette.color(QPalette::Highlight);
+ }
+ return QColor(); // invalid color
+}
+
+
+// ------------ FontSettingsPage
+FontSettingsPage::FontSettingsPage(const FormatDescriptions &fd,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core,
+ QObject *parent) :
+ Core::IOptionsPage(parent),
+ d_ptr(new FontSettingsPagePrivate(fd, tr("Font & Colors"), category, trCategory, core))
+{
+}
+
+FontSettingsPage::~FontSettingsPage()
+{
+ delete d_ptr;
+}
+
+QString FontSettingsPage::name() const
+{
+ return d_ptr->m_name;
+}
+
+QString FontSettingsPage::category() const
+{
+ return d_ptr->m_category;
+}
+
+QString FontSettingsPage::trCategory() const
+{
+ return d_ptr->m_trCategory;
+}
+
+QWidget *FontSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ d_ptr->ui.setupUi(w);
+
+
+ d_ptr->ui.itemListWidget->setSelectionMode(QAbstractItemView::ExtendedSelection);
+
+ foreach (const FormatDescription &d, d_ptr->m_descriptions)
+ d_ptr->ui.itemListWidget->addItem(d.trName());
+
+ QFontDatabase db;
+ const QStringList families = db.families();
+ d_ptr->ui.familyComboBox->addItems(families);
+ const int idx = families.indexOf(d_ptr->m_value.family());
+ d_ptr->ui.familyComboBox->setCurrentIndex(idx);
+
+ connect(d_ptr->ui.familyComboBox, SIGNAL(activated(int)), this, SLOT(updatePointSizes()));
+ connect(d_ptr->ui.sizeComboBox, SIGNAL(activated(int)), this, SLOT(updatePreview()));
+ connect(d_ptr->ui.itemListWidget, SIGNAL(itemSelectionChanged()),
+ this, SLOT(itemChanged()));
+ connect(d_ptr->ui.foregroundToolButton, SIGNAL(clicked()),
+ this, SLOT(changeForeColor()));
+ connect(d_ptr->ui.backgroundToolButton, SIGNAL(clicked()),
+ this, SLOT(changeBackColor()));
+ connect(d_ptr->ui.eraseBackgroundToolButton, SIGNAL(clicked()),
+ this, SLOT(eraseBackColor()));
+ connect(d_ptr->ui.boldCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkCheckBoxes()));
+ connect(d_ptr->ui.italicCheckBox, SIGNAL(toggled(bool)), this, SLOT(checkCheckBoxes()));
+
+ if (!d_ptr->m_descriptions.empty())
+ d_ptr->ui.itemListWidget->setCurrentRow(0);
+
+ updatePointSizes();
+ d_ptr->m_lastValue = d_ptr->m_value;
+ return w;
+}
+
+void FontSettingsPage::itemChanged()
+{
+ QListWidgetItem *item = d_ptr->ui.itemListWidget->currentItem();
+ if (!item)
+ return;
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ if (d_ptr->m_descriptions[i].trName() == item->text()) {
+ d_ptr->m_curItem = i;
+ const Format &format = d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name());
+ d_ptr->ui.foregroundToolButton->setStyleSheet(colorButtonStyleSheet(format.foreground()));
+ d_ptr->ui.backgroundToolButton->setStyleSheet(colorButtonStyleSheet(format.background()));
+
+ d_ptr->ui.eraseBackgroundToolButton->setEnabled(i > 0 && format.background().isValid());
+
+ const bool boldBlocked = d_ptr->ui.boldCheckBox->blockSignals(true);
+ d_ptr->ui.boldCheckBox->setChecked(format.bold());
+ d_ptr->ui.boldCheckBox->blockSignals(boldBlocked);
+ const bool italicBlocked = d_ptr->ui.italicCheckBox->blockSignals(true);
+ d_ptr->ui.italicCheckBox->setChecked(format.italic());
+ d_ptr->ui.italicCheckBox->blockSignals(italicBlocked);
+ updatePreview();
+ break;
+ }
+ }
+}
+
+void FontSettingsPage::changeForeColor()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ QColor color = d_ptr->m_value.formatFor(d_ptr->m_descriptions[d_ptr->m_curItem].name()).foreground();
+ const QColor newColor = QColorDialog::getColor(color, d_ptr->ui.boldCheckBox->window());
+ if (!newColor.isValid())
+ return;
+ QPalette p = d_ptr->ui.foregroundToolButton->palette();
+ p.setColor(QPalette::Active, QPalette::Button, newColor);
+ d_ptr->ui.foregroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor));
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected())
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setForeground(newColor);
+ }
+
+ updatePreview();
+}
+
+void FontSettingsPage::changeBackColor()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ QColor color = d_ptr->m_value.formatFor(d_ptr->m_descriptions[d_ptr->m_curItem].name()).background();
+ const QColor newColor = QColorDialog::getColor(color, d_ptr->ui.boldCheckBox->window());
+ if (!newColor.isValid())
+ return;
+ d_ptr->ui.backgroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor));
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected())
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setBackground(newColor);
+ }
+
+ updatePreview();
+}
+
+void FontSettingsPage::eraseBackColor()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ QColor newColor;
+ d_ptr->ui.backgroundToolButton->setStyleSheet(colorButtonStyleSheet(newColor));
+
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected())
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setBackground(newColor);
+ }
+
+ updatePreview();
+}
+
+void FontSettingsPage::checkCheckBoxes()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+ const int numFormats = d_ptr->m_descriptions.size();
+ for (int i = 0; i < numFormats; i++) {
+ QList<QListWidgetItem*> items = d_ptr->ui.itemListWidget->findItems(d_ptr->m_descriptions[i].trName(), Qt::MatchExactly);
+ if (!items.isEmpty() && items.first()->isSelected()) {
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setBold(d_ptr->ui.boldCheckBox->isChecked());
+ d_ptr->m_value.formatFor(d_ptr->m_descriptions[i].name()).setItalic(d_ptr->ui.italicCheckBox->isChecked());
+ }
+ }
+ updatePreview();
+}
+
+void FontSettingsPage::updatePreview()
+{
+ if (d_ptr->m_curItem == -1)
+ return;
+
+ const Format &currentFormat = d_ptr->m_value.formatFor(d_ptr->m_descriptions[d_ptr->m_curItem].name());
+ const Format &baseFormat = d_ptr->m_value.formatFor(QLatin1String("Text"));
+
+ QPalette pal = QApplication::palette();
+ if (baseFormat.foreground().isValid()) {
+ pal.setColor(QPalette::Text, baseFormat.foreground());
+ pal.setColor(QPalette::Foreground, baseFormat.foreground());
+ }
+ if (baseFormat.background().isValid())
+ pal.setColor(QPalette::Base, baseFormat.background());
+
+ d_ptr->ui.previewTextEdit->setPalette(pal);
+
+ QTextCharFormat format;
+ if (currentFormat.foreground().isValid())
+ format.setForeground(QBrush(currentFormat.foreground()));
+ if (currentFormat.background().isValid())
+ format.setBackground(QBrush(currentFormat.background()));
+ format.setFontFamily(d_ptr->ui.familyComboBox->currentText());
+ bool ok;
+ int size = d_ptr->ui.sizeComboBox->currentText().toInt(&ok);
+ if (!ok) {
+ size = QFont().pointSize();
+ }
+ format.setFontPointSize(size);
+ format.setFontItalic(currentFormat.italic());
+ if (currentFormat.bold())
+ format.setFontWeight(QFont::Bold);
+ d_ptr->ui.previewTextEdit->setCurrentCharFormat(format);
+
+ d_ptr->ui.previewTextEdit->setPlainText(tr("\n\tThis is only an example."));
+}
+
+void FontSettingsPage::updatePointSizes()
+{
+ const int oldSize = d_ptr->m_value.fontSize();
+ if (d_ptr->ui.sizeComboBox->count()) {
+ const QString curSize = d_ptr->ui.sizeComboBox->currentText();
+ bool ok = true;
+ int oldSize = curSize.toInt(&ok);
+ if (!ok)
+ oldSize = d_ptr->m_value.fontSize();
+ d_ptr->ui.sizeComboBox->clear();
+ }
+ QFontDatabase db;
+ const QList<int> sizeLst = db.pointSizes(d_ptr->ui.familyComboBox->currentText());
+ int idx = 0;
+ int i = 0;
+ for (; i<sizeLst.count(); ++i) {
+ if (idx == 0 && sizeLst.at(i) >= oldSize)
+ idx = i;
+ d_ptr->ui.sizeComboBox->addItem(QString::number(sizeLst.at(i)));
+ }
+ if (d_ptr->ui.sizeComboBox->count())
+ d_ptr->ui.sizeComboBox->setCurrentIndex(idx);
+ updatePreview();
+}
+
+void FontSettingsPage::delayedChange()
+{
+ emit changed(d_ptr->m_value);
+}
+
+void FontSettingsPage::finished(bool accepted)
+{
+ if (!accepted) {
+ d_ptr->m_value = d_ptr->m_lastValue;
+ return;
+ }
+
+ d_ptr->m_value.setFamily(d_ptr->ui.familyComboBox->currentText());
+
+ bool ok = true;
+ const int size = d_ptr->ui.sizeComboBox->currentText().toInt(&ok);
+ if (ok)
+ d_ptr->m_value.setFontSize(size);
+
+
+ if (d_ptr->m_value != d_ptr->m_lastValue) {
+ d_ptr->m_lastValue = d_ptr->m_value;
+ if (d_ptr->m_core)
+ if (QSettings *settings = d_ptr->m_core->settings())
+ d_ptr->m_value.toSettings(d_ptr->m_settingsGroup, d_ptr->m_descriptions, settings);
+
+ QTimer::singleShot(0, this, SLOT(delayedChange()));
+ }
+}
+
+const FontSettings &FontSettingsPage::fontSettings() const
+{
+ return d_ptr->m_value;
+}
diff --git a/src/plugins/texteditor/fontsettingspage.h b/src/plugins/texteditor/fontsettingspage.h
new file mode 100644
index 0000000000..86599e70d4
--- /dev/null
+++ b/src/plugins/texteditor/fontsettingspage.h
@@ -0,0 +1,124 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef FONTSETTINGSPAGE_H
+#define FONTSETTINGSPAGE_H
+
+#include "texteditor_global.h"
+
+#include "fontsettings.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtGui/QColor>
+#include <QtGui/QTextCharFormat>
+#include <QtCore/QString>
+#include <QtCore/QVector>
+
+QT_BEGIN_NAMESPACE
+class QWidget;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+namespace Internal {
+class FontSettingsPagePrivate;
+} // namespace Internal
+
+// GUI description of a format consisting of name (settings key)
+// and trName to be displayed
+class TEXTEDITOR_EXPORT FormatDescription
+{
+public:
+ FormatDescription(const QString &name, const QString &trName,
+ const QColor &foreground = Qt::black);
+
+ QString name() const;
+
+ QString trName() const;
+
+ QColor foreground() const;
+ void setForeground(const QColor &foreground);
+
+ QColor background() const;
+
+private:
+ QString m_name; // Name of the category
+ QString m_trName; // Displayed name of the category
+ Format m_format; // Default format
+};
+
+typedef QList<FormatDescription> FormatDescriptions;
+
+class TEXTEDITOR_EXPORT FontSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ FontSettingsPage(const FormatDescriptions &fd,
+ const QString &category,
+ const QString &trCategory,
+ Core::ICore *core,
+ QObject *parent = 0);
+
+ ~FontSettingsPage();
+
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ const FontSettings &fontSettings() const;
+
+signals:
+ void changed(const TextEditor::FontSettings&);
+
+private slots:
+ void delayedChange();
+ void itemChanged();
+ void changeForeColor();
+ void changeBackColor();
+ void eraseBackColor();
+ void checkCheckBoxes();
+ void updatePointSizes();
+ void updatePreview();
+
+private:
+ Internal::FontSettingsPagePrivate *d_ptr;
+};
+
+} // namespace TextEditor
+
+#endif // FONTSETTINGSPAGE_H
diff --git a/src/plugins/texteditor/fontsettingspage.ui b/src/plugins/texteditor/fontsettingspage.ui
new file mode 100644
index 0000000000..770d5e2935
--- /dev/null
+++ b/src/plugins/texteditor/fontsettingspage.ui
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TextEditor::Internal::FontSettingsPage</class>
+ <widget class="QWidget" name="TextEditor::Internal::FontSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>572</width>
+ <height>471</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>General Font Settings</string>
+ </property>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="label_5">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Family:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="familyComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>2</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Preferred</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_6">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Size:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="sizeComboBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="title">
+ <string>Item Specific Settings</string>
+ </property>
+ <layout class="QHBoxLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <property name="margin">
+ <number>9</number>
+ </property>
+ <item>
+ <widget class="QListWidget" name="itemListWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>1</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QGridLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="boldCheckBox">
+ <property name="text">
+ <string>Bold</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="QCheckBox" name="italicCheckBox">
+ <property name="text">
+ <string>Italic</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QToolButton" name="foregroundToolButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Background:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Foreground:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QToolButton" name="backgroundToolButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="eraseBackgroundToolButton">
+ <property name="toolTip">
+ <string>Erase background</string>
+ </property>
+ <property name="text">
+ <string>x</string>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::LeftArrow</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Preview:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextEdit" name="previewTextEdit">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src/plugins/texteditor/generalsettingspage.cpp b/src/plugins/texteditor/generalsettingspage.cpp
new file mode 100644
index 0000000000..7f056d8ca4
--- /dev/null
+++ b/src/plugins/texteditor/generalsettingspage.cpp
@@ -0,0 +1,217 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "displaysettings.h"
+#include "generalsettingspage.h"
+#include "storagesettings.h"
+#include "tabsettings.h"
+#include "ui_generalsettingspage.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QDebug>
+
+using namespace TextEditor;
+
+struct GeneralSettingsPage::GeneralSettingsPagePrivate {
+ GeneralSettingsPagePrivate(Core::ICore *core,
+ const GeneralSettingsPageParameters &p);
+
+ Core::ICore *m_core;
+ const GeneralSettingsPageParameters m_parameters;
+ Ui::generalSettingsPage m_page;
+ TabSettings m_tabSettings;
+ StorageSettings m_storageSettings;
+ DisplaySettings m_displaySettings;
+};
+
+GeneralSettingsPage::GeneralSettingsPagePrivate::GeneralSettingsPagePrivate(Core::ICore *core,
+ const GeneralSettingsPageParameters &p) :
+ m_core(core),
+ m_parameters(p)
+{
+ if (m_core)
+ if (const QSettings *s = m_core->settings()) {
+ m_tabSettings.fromSettings(m_parameters.settingsPrefix, s);
+ m_storageSettings.fromSettings(m_parameters.settingsPrefix, s);
+ m_displaySettings.fromSettings(m_parameters.settingsPrefix, s);
+ }
+}
+
+GeneralSettingsPage::GeneralSettingsPage(Core::ICore *core,
+ const GeneralSettingsPageParameters &p,
+ QObject *parent) :
+ Core::IOptionsPage(parent),
+ m_d(new GeneralSettingsPagePrivate(core, p))
+{
+}
+
+GeneralSettingsPage::~GeneralSettingsPage()
+{
+ delete m_d;
+}
+
+QString GeneralSettingsPage::name() const
+{
+ return m_d->m_parameters.name;
+}
+
+QString GeneralSettingsPage::category() const
+{
+ return m_d->m_parameters.category;
+}
+
+QString GeneralSettingsPage::trCategory() const
+{
+ return m_d->m_parameters.trCategory;
+}
+
+QWidget *GeneralSettingsPage::createPage(QWidget *parent)
+{
+ QWidget *w = new QWidget(parent);
+ m_d->m_page.setupUi(w);
+
+ settingsToUI();
+
+ return w;
+}
+
+void GeneralSettingsPage::finished(bool accepted)
+{
+ if (!accepted)
+ return;
+
+ TabSettings newTabSettings;
+ StorageSettings newStorageSettings;
+ DisplaySettings newDisplaySettings;
+ settingsFromUI(newTabSettings, newStorageSettings, newDisplaySettings);
+
+ if (newTabSettings != m_d->m_tabSettings) {
+ m_d->m_tabSettings = newTabSettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_tabSettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit tabSettingsChanged(newTabSettings);
+ }
+
+ if (newStorageSettings != m_d->m_storageSettings) {
+ m_d->m_storageSettings = newStorageSettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_storageSettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit storageSettingsChanged(newStorageSettings);
+ }
+
+ if (newDisplaySettings != m_d->m_displaySettings) {
+ m_d->m_displaySettings = newDisplaySettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_displaySettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit displaySettingsChanged(newDisplaySettings);
+ }
+}
+
+void GeneralSettingsPage::settingsFromUI(TabSettings &rc,
+ StorageSettings &storageSettings,
+ DisplaySettings &displaySettings) const
+{
+ rc.m_spacesForTabs = m_d->m_page.insertSpaces->isChecked();
+ rc.m_autoIndent = m_d->m_page.autoIndent->isChecked();
+ rc.m_smartBackspace = m_d->m_page.smartBackspace->isChecked();
+ rc.m_tabSize = m_d->m_page.tabSize->value();
+ rc.m_indentSize = m_d->m_page.indentSize->value();
+
+ storageSettings.m_cleanWhitespace = m_d->m_page.cleanWhitespace->isChecked();
+ storageSettings.m_inEntireDocument = m_d->m_page.inEntireDocument->isChecked();
+ storageSettings.m_addFinalNewLine = m_d->m_page.addFinalNewLine->isChecked();
+
+ displaySettings.m_displayLineNumbers = m_d->m_page.displayLineNumbers->isChecked();
+ displaySettings.m_textWrapping = m_d->m_page.enableTextWrapping->isChecked();
+ displaySettings.m_showWrapColumn = m_d->m_page.showWrapColumn->isChecked();
+ displaySettings.m_wrapColumn = m_d->m_page.wrapColumn->value();
+ displaySettings.m_visualizeWhitespace = m_d->m_page.visualizeWhitespace->isChecked();
+ displaySettings.m_displayFoldingMarkers = m_d->m_page.displayFoldingMarkers->isChecked();
+ displaySettings.m_highlightCurrentLine = m_d->m_page.highlightCurrentLine->isChecked();
+}
+
+void GeneralSettingsPage::settingsToUI()
+{
+ TabSettings rc = m_d->m_tabSettings;
+ m_d->m_page.insertSpaces->setChecked(rc.m_spacesForTabs);
+ m_d->m_page.autoIndent->setChecked(rc.m_autoIndent);
+ m_d->m_page.smartBackspace->setChecked(rc.m_smartBackspace);
+ m_d->m_page.tabSize->setValue(rc.m_tabSize);
+ m_d->m_page.indentSize->setValue(rc.m_indentSize);
+
+ StorageSettings storageSettings = m_d->m_storageSettings;
+ m_d->m_page.cleanWhitespace->setChecked(storageSettings.m_cleanWhitespace);
+ m_d->m_page.inEntireDocument->setChecked(storageSettings.m_inEntireDocument);
+ m_d->m_page.addFinalNewLine->setChecked(storageSettings.m_addFinalNewLine);
+
+ DisplaySettings displaySettings = m_d->m_displaySettings;
+ m_d->m_page.displayLineNumbers->setChecked(displaySettings.m_displayLineNumbers);
+ m_d->m_page.enableTextWrapping->setChecked(displaySettings.m_textWrapping);
+ m_d->m_page.showWrapColumn->setChecked(displaySettings.m_showWrapColumn);
+ m_d->m_page.wrapColumn->setValue(displaySettings.m_wrapColumn);
+ m_d->m_page.visualizeWhitespace->setChecked(displaySettings.m_visualizeWhitespace);
+ m_d->m_page.displayFoldingMarkers->setChecked(displaySettings.m_displayFoldingMarkers);
+ m_d->m_page.highlightCurrentLine->setChecked(displaySettings.m_highlightCurrentLine);
+}
+
+TabSettings GeneralSettingsPage::tabSettings() const
+{
+ return m_d->m_tabSettings;
+}
+
+StorageSettings GeneralSettingsPage::storageSettings() const
+{
+ return m_d->m_storageSettings;
+}
+
+DisplaySettings GeneralSettingsPage::displaySettings() const
+{
+ return m_d->m_displaySettings;
+}
+
+void GeneralSettingsPage::setDisplaySettings(const DisplaySettings &newDisplaySettings)
+{
+ if (newDisplaySettings != m_d->m_displaySettings) {
+ m_d->m_displaySettings = newDisplaySettings;
+ if (m_d->m_core)
+ if (QSettings *s = m_d->m_core->settings())
+ m_d->m_displaySettings.toSettings(m_d->m_parameters.settingsPrefix, s);
+
+ emit displaySettingsChanged(newDisplaySettings);
+ }
+}
diff --git a/src/plugins/texteditor/generalsettingspage.h b/src/plugins/texteditor/generalsettingspage.h
new file mode 100644
index 0000000000..184e3bace8
--- /dev/null
+++ b/src/plugins/texteditor/generalsettingspage.h
@@ -0,0 +1,98 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef GENERALSETTINGSPAGE_H
+#define GENERALSETTINGSPAGE_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/icore.h>
+#include <coreplugin/dialogs/ioptionspage.h>
+
+#include <QtCore/QObject>
+
+namespace TextEditor {
+
+struct TabSettings;
+struct StorageSettings;
+struct DisplaySettings;
+
+struct TEXTEDITOR_EXPORT GeneralSettingsPageParameters {
+ QString name;
+ QString category;
+ QString trCategory;
+ QString settingsPrefix;
+};
+
+class Ui_generalSettingsPage;
+
+class TEXTEDITOR_EXPORT GeneralSettingsPage : public Core::IOptionsPage
+{
+ Q_OBJECT
+
+public:
+ GeneralSettingsPage(Core::ICore *core,
+ const GeneralSettingsPageParameters &p,
+ QObject *parent);
+ virtual ~GeneralSettingsPage();
+
+ //IOptionsPage
+ QString name() const;
+ QString category() const;
+ QString trCategory() const;
+
+ QWidget *createPage(QWidget *parent);
+ void finished(bool accepted);
+
+ TabSettings tabSettings() const;
+ StorageSettings storageSettings() const;
+ DisplaySettings displaySettings() const;
+
+ void setDisplaySettings(const DisplaySettings &);
+
+signals:
+ void tabSettingsChanged(const TextEditor::TabSettings &);
+ void storageSettingsChanged(const TextEditor::StorageSettings &);
+ void displaySettingsChanged(const TextEditor::DisplaySettings &);
+
+private:
+ void settingsFromUI(TabSettings &rc,
+ StorageSettings &storageSettings,
+ DisplaySettings &displaySettings) const;
+ void settingsToUI();
+ struct GeneralSettingsPagePrivate;
+ GeneralSettingsPagePrivate *m_d;
+};
+
+} // namespace TextEditor
+
+#endif // GENERALSETTINGSPAGE_H
diff --git a/src/plugins/texteditor/generalsettingspage.ui b/src/plugins/texteditor/generalsettingspage.ui
new file mode 100644
index 0000000000..11f6b8b997
--- /dev/null
+++ b/src/plugins/texteditor/generalsettingspage.ui
@@ -0,0 +1,336 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>TextEditor::generalSettingsPage</class>
+ <widget class="QWidget" name="TextEditor::generalSettingsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>514</width>
+ <height>427</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QGroupBox" name="groupBox_3">
+ <property name="title">
+ <string>Tab/Indent Settings</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="autoIndent">
+ <property name="text">
+ <string>Enable automatic &amp;indentation</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="labelTabSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Ta&amp;b size:</string>
+ </property>
+ <property name="buddy">
+ <cstring>tabSize</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>5</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="tabSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="3">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="QCheckBox" name="insertSpaces">
+ <property name="text">
+ <string>Insert &amp;spaces instead of tabs</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <item>
+ <widget class="QLabel" name="labelIndentSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>&amp;Indent size:</string>
+ </property>
+ <property name="buddy">
+ <cstring>indentSize</cstring>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>5</width>
+ <height>5</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="indentSize">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Maximum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximum">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="smartBackspace">
+ <property name="text">
+ <string>&amp;Backspace follows indentation</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>10</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox_2">
+ <property name="title">
+ <string>Storage Settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="cleanWhitespace">
+ <property name="text">
+ <string>&amp;Clean whitespace</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Fixed</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>30</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="inEntireDocument">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>In entire &amp;document</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="addFinalNewLine">
+ <property name="text">
+ <string>&amp;Ensure newline at end of file</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Display Settings</string>
+ </property>
+ <layout class="QGridLayout">
+ <item row="0" column="1">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QCheckBox" name="showWrapColumn">
+ <property name="text">
+ <string>Display right &amp;margin at column</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QSpinBox" name="wrapColumn">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="maximum">
+ <number>999</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="enableTextWrapping">
+ <property name="text">
+ <string>Enable text &amp;wrapping</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="displayLineNumbers">
+ <property name="text">
+ <string>Display line &amp;numbers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QCheckBox" name="visualizeWhitespace">
+ <property name="text">
+ <string>&amp;Visualize whitespace</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QCheckBox" name="displayFoldingMarkers">
+ <property name="text">
+ <string>Display &amp;folding markers</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QCheckBox" name="highlightCurrentLine">
+ <property name="text">
+ <string>Highlight current &amp;line</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>351</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>cleanWhitespace</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>inEntireDocument</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>47</x>
+ <y>184</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>91</x>
+ <y>212</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>showWrapColumn</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>wrapColumn</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>399</x>
+ <y>308</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>474</x>
+ <y>308</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src/plugins/texteditor/icompletioncollector.h b/src/plugins/texteditor/icompletioncollector.h
new file mode 100644
index 0000000000..46dc3f8b3d
--- /dev/null
+++ b/src/plugins/texteditor/icompletioncollector.h
@@ -0,0 +1,114 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef COMPLETIONCOLLECTORINTERFACE_H
+#define COMPLETIONCOLLECTORINTERFACE_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QVariant>
+#include <QtGui/QIcon>
+#include <QtGui/QKeyEvent>
+
+namespace TextEditor {
+
+class ICompletionCollector;
+class ITextEditable;
+
+struct CompletionItem
+{
+ CompletionItem(ICompletionCollector *collector = 0)
+ : m_relevance(0),
+ m_collector(collector)
+ { }
+
+ bool isValid() const
+ { return m_collector != 0; }
+
+ operator bool() const
+ { return m_collector != 0; }
+
+ QString m_text;
+ QString m_details;
+ QIcon m_icon;
+ QVariant m_data;
+ int m_relevance;
+ ICompletionCollector *m_collector;
+};
+
+/* Defines the interface to completion collectors. A completion collector tells
+ * the completion support code when a completion is triggered and provides the
+ * list of possible completions. It keeps an internal state so that it can be
+ * polled for the list of completions, which is reset with a call to reset.
+ */
+class TEXTEDITOR_EXPORT ICompletionCollector : public QObject
+{
+ Q_OBJECT
+public:
+ ICompletionCollector(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ICompletionCollector() {}
+
+ /* This method should return whether the cursor is at a position which could
+ * trigger an autocomplete. It will be called each time a character is typed in
+ * the text editor.
+ */
+ virtual bool triggersCompletion(ITextEditable *editor) = 0;
+
+ // returns starting position
+ virtual int startCompletion(ITextEditable *editor) = 0;
+
+ /* This method should add all the completions it wants to show into the list,
+ * based on the given cursor position.
+ */
+ virtual void completions(QList<CompletionItem> *completions) = 0;
+
+ /* This method should complete the given completion item.
+ */
+ virtual void complete(const CompletionItem &item) = 0;
+
+ /* This method gives the completion collector a chance to partially complete
+ * based on a set of items. The general use case is to complete the common
+ * prefix shared by all possible completion items.
+ *
+ * Returns whether the completion popup should be closed.
+ */
+ virtual bool partiallyComplete(const QList<TextEditor::CompletionItem> &completionItems) = 0;
+
+ /* Called when it's safe to clean up the completion items.
+ */
+ virtual void cleanup() = 0;
+};
+
+} // namespace TextEditor
+
+#endif // COMPLETIONCOLLECTORINTERFACE_H
diff --git a/src/plugins/texteditor/images/finddirectory.png b/src/plugins/texteditor/images/finddirectory.png
new file mode 100644
index 0000000000..f20c7d013e
--- /dev/null
+++ b/src/plugins/texteditor/images/finddirectory.png
Binary files differ
diff --git a/src/plugins/texteditor/images/finddocuments.png b/src/plugins/texteditor/images/finddocuments.png
new file mode 100644
index 0000000000..a637456b58
--- /dev/null
+++ b/src/plugins/texteditor/images/finddocuments.png
Binary files differ
diff --git a/src/plugins/texteditor/itexteditable.h b/src/plugins/texteditor/itexteditable.h
new file mode 100644
index 0000000000..30ec5e1493
--- /dev/null
+++ b/src/plugins/texteditor/itexteditable.h
@@ -0,0 +1,64 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ITEXTEDITABLE_H
+#define ITEXTEDITABLE_H
+
+#include "texteditor_global.h"
+#include "itexteditor.h"
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT ITextEditable : public ITextEditor
+{
+ Q_OBJECT
+public:
+ ITextEditable() {}
+ virtual ~ITextEditable() {}
+
+ /* Removes 'length' characteres to the right of the cursor. */
+ virtual void remove(int length) = 0;
+
+ /* Inserts the given string to the right of the cursor. */
+ virtual void insert(const QString &string) = 0;
+
+ /* Replaces 'length' characters to the right of the cursor with the given string. */
+ virtual void replace(int length, const QString &string) = 0;
+
+ virtual void setCurPos(int pos) = 0;
+
+ virtual void select(int toPos) = 0;
+};
+
+} // namespace TextEditor
+
+#endif // ITEXTEDITABLE_H
diff --git a/src/plugins/texteditor/itexteditor.h b/src/plugins/texteditor/itexteditor.h
new file mode 100644
index 0000000000..ca517577a0
--- /dev/null
+++ b/src/plugins/texteditor/itexteditor.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef ITEXTEDITOR_H
+#define ITEXTEDITOR_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/editormanager/ieditor.h>
+
+#include <QtCore/QObject>
+#include <QtCore/QList>
+#include <QtGui/QColor>
+#include <QtGui/QIcon>
+
+QT_BEGIN_NAMESPACE
+class QTextBlock;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+class ITextEditor;
+
+class TEXTEDITOR_EXPORT ITextMark : public QObject
+{
+ Q_OBJECT
+public:
+ ITextMark(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ITextMark() {}
+
+ virtual QIcon icon() const = 0;
+
+ virtual void updateLineNumber(int lineNumber) = 0;
+ virtual void updateBlock(const QTextBlock &block) = 0;
+ virtual void removedFromEditor() = 0;
+ virtual void documentClosing() = 0;
+};
+
+typedef QList<ITextMark *> TextMarks;
+
+
+class TEXTEDITOR_EXPORT ITextMarkable : public QObject
+{
+ Q_OBJECT
+public:
+ ITextMarkable(QObject *parent = 0) : QObject(parent) {}
+ virtual ~ITextMarkable() {}
+ virtual bool addMark(ITextMark *mark, int line) = 0;
+
+ virtual TextMarks marksAt(int line) const = 0;
+ virtual void removeMark(ITextMark *mark) = 0;
+ virtual bool hasMark(ITextMark *mark) const = 0;
+ virtual void updateMark(ITextMark *mark) = 0;
+};
+
+class TEXTEDITOR_EXPORT ITextEditor : public Core::IEditor
+{
+ Q_OBJECT
+public:
+ enum PositionOperation {
+ Current = 1,
+ EndOfLine = 2,
+ StartOfLine = 3,
+ Anchor = 4,
+ EndOfDoc = 5
+ };
+
+ ITextEditor() {}
+ virtual ~ITextEditor() {}
+
+ virtual int find(const QString &string) const = 0;
+
+ virtual void gotoLine(int line, int column = 0) = 0;
+
+ virtual int position(PositionOperation posOp = Current, int at = -1) const = 0;
+ virtual void convertPosition(int pos, int *line, int *column) const = 0;
+ virtual QRect cursorRect(int pos = -1) const = 0;
+
+ virtual QString contents() const = 0;
+ virtual QString selectedText() const = 0;
+ virtual QString textAt(int pos, int length) const = 0;
+ virtual QChar characterAt(int pos) const = 0;
+
+ virtual void triggerCompletions() = 0;
+
+ virtual ITextMarkable *markableInterface() = 0;
+
+ virtual void setContextHelpId(const QString &) = 0;
+
+ virtual void setTextCodec(QTextCodec *) = 0;
+ virtual QTextCodec *textCodec() const = 0;
+
+
+signals:
+ void contentsChanged();
+ void markRequested(TextEditor::ITextEditor *editor, int line);
+ void tooltipRequested(TextEditor::ITextEditor *editor, const QPoint &globalPos, int position);
+ void contextHelpIdRequested(TextEditor::ITextEditor *editor, int position);
+};
+
+} // namespace TextEditor
+
+#endif // ITEXTEDITOR_H
diff --git a/src/plugins/texteditor/linenumberfilter.cpp b/src/plugins/texteditor/linenumberfilter.cpp
new file mode 100644
index 0000000000..ea079196f7
--- /dev/null
+++ b/src/plugins/texteditor/linenumberfilter.cpp
@@ -0,0 +1,80 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "linenumberfilter.h"
+#include "itexteditor.h"
+
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QVariant>
+
+using namespace Core;
+using namespace QuickOpen;
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+LineNumberFilter::LineNumberFilter(EditorManager *editorManager, QObject *parent):
+ IQuickOpenFilter(parent)
+{
+ m_editorManager = editorManager;
+ setShortcutString("l");
+ setIncludedByDefault(true);
+}
+
+QList<FilterEntry> LineNumberFilter::matchesFor(const QString &entry)
+{
+ bool ok;
+ QList<FilterEntry> value;
+ int line = entry.toInt(&ok);
+ if (line > 0 && currentTextEditor())
+ value.append(FilterEntry(this, QString("Line %1").arg(line), QVariant(line)));
+ return value;
+}
+
+void LineNumberFilter::accept(FilterEntry selection) const
+{
+ ITextEditor *editor = currentTextEditor();
+ if (editor) {
+ m_editorManager->ensureEditorManagerVisible();
+ m_editorManager->addCurrentPositionToNavigationHistory(true);
+ editor->gotoLine(selection.internalData.toInt());
+ m_editorManager->addCurrentPositionToNavigationHistory();
+ editor->widget()->setFocus();
+ }
+}
+
+ITextEditor *LineNumberFilter::currentTextEditor() const
+{
+ if (!m_editorManager->currentEditor())
+ return 0;
+ return qobject_cast<TextEditor::ITextEditor*>(m_editorManager->currentEditor());
+}
diff --git a/src/plugins/texteditor/linenumberfilter.h b/src/plugins/texteditor/linenumberfilter.h
new file mode 100644
index 0000000000..f20de8a718
--- /dev/null
+++ b/src/plugins/texteditor/linenumberfilter.h
@@ -0,0 +1,76 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef LINENUMBERFILTER_H
+#define LINENUMBERFILTER_H
+
+#include <quickopen/iquickopenfilter.h>
+
+#include <QtCore/QString>
+#include <QtCore/QList>
+#include <QtCore/QByteArray>
+#include <QtCore/QFutureInterface>
+#include <QtGui/QWidget>
+
+namespace Core {
+class EditorManager;
+}
+
+namespace TextEditor {
+
+class ITextEditor;
+
+namespace Internal {
+
+class LineNumberFilter : public QuickOpen::IQuickOpenFilter
+{
+ Q_OBJECT
+
+public:
+ LineNumberFilter(Core::EditorManager *editorManager, QObject *parent = 0);
+ QString trName() const { return tr("Line in current document"); }
+ QString name() const { return "Line in current document"; }
+ QuickOpen::IQuickOpenFilter::Priority priority() const { return QuickOpen::IQuickOpenFilter::High; }
+ QList<QuickOpen::FilterEntry> matchesFor(const QString &entry);
+ void accept(QuickOpen::FilterEntry selection) const;
+ void refresh(QFutureInterface<void> &) {}
+
+private:
+ ITextEditor *currentTextEditor() const;
+
+ Core::EditorManager *m_editorManager;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // LINENUMBERFILTER_H
diff --git a/src/plugins/texteditor/plaintexteditor.cpp b/src/plugins/texteditor/plaintexteditor.cpp
new file mode 100644
index 0000000000..6019d73b25
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditor.cpp
@@ -0,0 +1,129 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plaintexteditor.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/icore.h>
+#include <coreplugin/uniqueidmanager.h>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+PlainTextEditorEditable::PlainTextEditorEditable(PlainTextEditor *editor)
+ :BaseTextEditorEditable(editor)
+{
+ Core::ICore *core = TextEditorPlugin::core();
+ m_context << core->uniqueIDManager()->
+ uniqueIdentifier(Core::Constants::K_DEFAULT_TEXT_EDITOR);
+ m_context << core->uniqueIDManager()->
+ uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+}
+
+PlainTextEditor::PlainTextEditor(QWidget *parent) :
+ BaseTextEditor(parent)
+{
+
+ setRevisionsVisible(true);
+ setMarksVisible(true);
+ setRequestMarkEnabled(false);
+ setLineSeparatorsAllowed(true);
+
+ setMimeType(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT));
+}
+
+QList<int> PlainTextEditorEditable::context() const
+{
+ return m_context;
+}
+
+
+Core::IEditor *PlainTextEditorEditable::duplicate(QWidget *parent)
+{
+ PlainTextEditor *newEditor = new PlainTextEditor(parent);
+ newEditor->duplicateFrom(editor());
+ TextEditorPlugin::instance()->initializeEditor(newEditor);
+ return newEditor->editableInterface();
+}
+
+const char *PlainTextEditorEditable::kind() const
+{
+ return Core::Constants::K_DEFAULT_TEXT_EDITOR;
+}
+
+// Indent a text block based on previous line.
+// Simple text paragraph layout:
+// aaaa aaaa
+//
+// bbb bb
+// bbb bb
+//
+// - list
+// list line2
+//
+// - listn
+//
+// ccc
+//
+// @todo{Add formatting to wrap paragraphs. This requires some
+// hoops as the current indentation routines are not prepared
+// for additional block being inserted. It might be possible
+// to do in 2 steps (indenting/wrapping)}
+//
+
+void PlainTextEditor::indentBlock(QTextDocument *doc, QTextBlock block, QChar /* typedChar */)
+{
+ // At beginning: Leave as is.
+ if (block == doc->begin())
+ return;
+
+ const QTextBlock previous = block.previous();
+ const QString previousText = previous.text();
+ // Empty line indicates a start of a new paragraph. Leave as is.
+ if (previousText.isEmpty() || previousText.trimmed().isEmpty())
+ return;
+
+ // Just use previous line.
+ // Skip non-alphanumerical characters when determining the indentation
+ // to enable writing bulleted lists whose items span several lines.
+ int i = 0;
+ while (i < previousText.size()) {
+ if (previousText.at(i).isLetterOrNumber()) {
+ const TextEditor::TabSettings &ts = tabSettings();
+ ts.indentLine(block, ts.columnAt(previousText, i));
+ break;
+ }
+ ++i;
+ }
+}
diff --git a/src/plugins/texteditor/plaintexteditor.h b/src/plugins/texteditor/plaintexteditor.h
new file mode 100644
index 0000000000..7641580789
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditor.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLAINTEXTEDITOR_H
+#define PLAINTEXTEDITOR_H
+
+#include "basetexteditor.h"
+
+#include <QtCore/QList>
+
+namespace TextEditor {
+
+class PlainTextEditor;
+
+class TEXTEDITOR_EXPORT PlainTextEditorEditable : public BaseTextEditorEditable
+{
+public:
+ PlainTextEditorEditable(PlainTextEditor *);
+ QList<int> context() const;
+
+ bool duplicateSupported() const { return true; }
+ Core::IEditor *duplicate(QWidget *parent);
+ const char *kind() const;
+private:
+ QList<int> m_context;
+};
+
+class TEXTEDITOR_EXPORT PlainTextEditor : public BaseTextEditor
+{
+ Q_OBJECT
+
+public:
+ PlainTextEditor(QWidget *parent);
+
+protected:
+ BaseTextEditorEditable *createEditableInterface() { return new PlainTextEditorEditable(this); }
+ // Indent a text block based on previous line.
+ virtual void indentBlock(QTextDocument *doc, QTextBlock block, QChar typedChar);
+};
+
+} // namespace TextEditor
+
+#endif // PLAINTEXTEDITOR_H
diff --git a/src/plugins/texteditor/plaintexteditorfactory.cpp b/src/plugins/texteditor/plaintexteditorfactory.cpp
new file mode 100644
index 0000000000..24e36bfff6
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditorfactory.cpp
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "plaintexteditor.h"
+#include "plaintexteditorfactory.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+#include "texteditoractionhandler.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+PlainTextEditorFactory::PlainTextEditorFactory(QObject *parent) :
+ Core::IEditorFactory(parent),
+ m_kind(Core::Constants::K_DEFAULT_TEXT_EDITOR)
+{
+ m_actionHandler = new TextEditorActionHandler(TextEditorPlugin::core(),
+ QLatin1String(TextEditor::Constants::C_TEXTEDITOR),
+ TextEditorActionHandler::Format);
+ m_mimeTypes << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT)
+ << QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_XML);
+}
+
+PlainTextEditorFactory::~PlainTextEditorFactory()
+{
+ delete m_actionHandler;
+}
+
+QString PlainTextEditorFactory::kind() const
+{
+ return m_kind;
+}
+
+Core::IFile *PlainTextEditorFactory::open(const QString &fileName)
+{
+ Core::ICore *core = TextEditorPlugin::core();
+ Core::IEditor *iface = core->editorManager()->openEditor(fileName, kind());
+ return iface ? iface->file() : 0;
+}
+
+Core::IEditor *PlainTextEditorFactory::createEditor(QWidget *parent)
+{
+ PlainTextEditor *rc = new PlainTextEditor(parent);
+ TextEditorPlugin::instance()->initializeEditor(rc);
+ return rc->editableInterface();
+}
+
+QStringList PlainTextEditorFactory::mimeTypes() const
+{
+ return m_mimeTypes;
+}
diff --git a/src/plugins/texteditor/plaintexteditorfactory.h b/src/plugins/texteditor/plaintexteditorfactory.h
new file mode 100644
index 0000000000..0e225c942e
--- /dev/null
+++ b/src/plugins/texteditor/plaintexteditorfactory.h
@@ -0,0 +1,73 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef PLAINTEXTEDITORFACTORY_H
+#define PLAINTEXTEDITORFACTORY_H
+
+#include <coreplugin/editormanager/ieditorfactory.h>
+#include <QtCore/QStringList>
+
+namespace Core {
+class IEditor;
+class IFile;
+}
+
+namespace TextEditor {
+class TextEditorActionHandler;
+namespace Internal {
+
+class PlainTextEditorFactory : public Core::IEditorFactory
+{
+ Q_OBJECT
+
+public:
+ PlainTextEditorFactory(QObject *parent = 0);
+ virtual ~PlainTextEditorFactory();
+
+ virtual QStringList mimeTypes() const;
+ //Core::IEditorFactory
+ QString kind() const;
+ Core::IFile *open(const QString &fileName);
+ Core::IEditor *createEditor(QWidget *parent);
+
+ TextEditor::TextEditorActionHandler *actionHandler() const { return m_actionHandler; }
+
+private:
+ const QString m_kind;
+ QStringList m_mimeTypes;
+ TextEditor::TextEditorActionHandler *m_actionHandler;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // PLAINTEXTEDITORFACTORY_H
diff --git a/src/plugins/texteditor/storagesettings.cpp b/src/plugins/texteditor/storagesettings.cpp
new file mode 100644
index 0000000000..906215bf81
--- /dev/null
+++ b/src/plugins/texteditor/storagesettings.cpp
@@ -0,0 +1,81 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "storagesettings.h"
+#include <QSettings>
+#include <QString>
+
+namespace TextEditor {
+
+static const char * const cleanWhitespaceKey = "cleanWhitespace";
+static const char * const inEntireDocumentKey = "inEntireDocument";
+static const char * const addFinalNewLineKey = "addFinalNewLine";
+static const char * const groupPostfix = "StorageSettings";
+
+StorageSettings::StorageSettings()
+ : m_cleanWhitespace(true),
+ m_inEntireDocument(false),
+ m_addFinalNewLine(true)
+{
+}
+
+void StorageSettings::toSettings(const QString &category, QSettings *s) const
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ s->beginGroup(group);
+ s->setValue(QLatin1String(cleanWhitespaceKey), m_cleanWhitespace);
+ s->setValue(QLatin1String(inEntireDocumentKey), m_inEntireDocument);
+ s->setValue(QLatin1String(addFinalNewLineKey), m_addFinalNewLine);
+ s->endGroup();
+}
+
+void StorageSettings::fromSettings(const QString &category, const QSettings *s)
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ group += QLatin1Char('/');
+ m_cleanWhitespace = s->value(group + QLatin1String(cleanWhitespaceKey), m_cleanWhitespace).toBool();
+ m_inEntireDocument = s->value(group + QLatin1String(inEntireDocumentKey), m_inEntireDocument).toBool();
+ m_addFinalNewLine = s->value(group + QLatin1String(addFinalNewLineKey), m_addFinalNewLine).toBool();
+}
+
+bool StorageSettings::equals(const StorageSettings &ts) const
+{
+ return m_addFinalNewLine == ts.m_addFinalNewLine
+ && m_cleanWhitespace == ts.m_cleanWhitespace
+ && m_inEntireDocument == ts.m_inEntireDocument;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/storagesettings.h b/src/plugins/texteditor/storagesettings.h
new file mode 100644
index 0000000000..dc3310094a
--- /dev/null
+++ b/src/plugins/texteditor/storagesettings.h
@@ -0,0 +1,62 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef STORAGESETTINGS_H
+#define STORAGESETTINGS_H
+
+#include "texteditor_global.h"
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+struct TEXTEDITOR_EXPORT StorageSettings {
+ StorageSettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, const QSettings *s);
+
+ bool equals(const StorageSettings &ts) const;
+
+ bool m_cleanWhitespace;
+ bool m_inEntireDocument;
+ bool m_addFinalNewLine;
+};
+
+inline bool operator==(const StorageSettings &t1, const StorageSettings &t2) { return t1.equals(t2); }
+inline bool operator!=(const StorageSettings &t1, const StorageSettings &t2) { return !t1.equals(t2); }
+
+} // namespace TextEditor
+
+#endif // STORAGESETTINGS_H
diff --git a/src/plugins/texteditor/tabsettings.cpp b/src/plugins/texteditor/tabsettings.cpp
new file mode 100644
index 0000000000..daaee1a562
--- /dev/null
+++ b/src/plugins/texteditor/tabsettings.cpp
@@ -0,0 +1,241 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "tabsettings.h"
+
+#include <QtCore/QSettings>
+#include <QtCore/QString>
+#include <QtGui/QTextCursor>
+#include <QtGui/QTextDocument>
+#include <QDebug>
+
+static const char* spacesForTabsKey = "SpacesForTabs";
+static const char* smartBackspaceKey = "SmartBackspace";
+static const char* autoIndentKey = "AutoIndent";
+static const char* tabSizeKey = "TabSize";
+static const char* indentSizeKey = "IndentSize";
+static const char* groupPostfix = "TabSettings";
+
+namespace TextEditor {
+
+TabSettings::TabSettings() :
+ m_spacesForTabs(true),
+ m_autoIndent(true),
+ m_smartBackspace(false),
+ m_tabSize(8),
+ m_indentSize(4)
+{
+}
+
+void TabSettings::toSettings(const QString &category, QSettings *s) const
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ s->beginGroup(group);
+ s->setValue(QLatin1String(spacesForTabsKey), m_spacesForTabs);
+ s->setValue(QLatin1String(autoIndentKey), m_autoIndent);
+ s->setValue(QLatin1String(smartBackspaceKey), m_smartBackspace);
+ s->setValue(QLatin1String(tabSizeKey), m_tabSize);
+ s->setValue(QLatin1String(indentSizeKey), m_indentSize);
+ s->endGroup();
+}
+
+void TabSettings::fromSettings(const QString &category, const QSettings *s)
+{
+ QString group = QLatin1String(groupPostfix);
+ if (!category.isEmpty())
+ group.insert(0, category);
+ group += QLatin1Char('/');
+
+ *this = TabSettings(); // Assign defaults
+
+ m_spacesForTabs = s->value(group + QLatin1String(spacesForTabsKey), m_spacesForTabs).toBool();
+ m_autoIndent = s->value(group + QLatin1String(autoIndentKey), m_autoIndent).toBool();
+ m_smartBackspace = s->value(group + QLatin1String(smartBackspaceKey), m_smartBackspace).toBool();
+ m_tabSize = s->value(group + QLatin1String(tabSizeKey), m_tabSize).toInt();
+ m_indentSize = s->value(group + QLatin1String(indentSizeKey), m_indentSize).toInt();
+}
+
+
+
+int TabSettings::lineIndentPosition(const QString &text) const
+{
+ int i = 0;
+ while (i < text.size()) {
+ if (!text.at(i).isSpace())
+ break;
+ ++i;
+ }
+ int column = columnAt(text, i);
+ return i - (column % m_indentSize);
+}
+
+int TabSettings::firstNonSpace(const QString &text) const
+{
+ int i = 0;
+ while (i < text.size()) {
+ if (!text.at(i).isSpace())
+ return i;
+ ++i;
+ }
+ return i;
+}
+
+int TabSettings::trailingWhitespaces(const QString &text) const
+{
+ int i = 0;
+ while (i < text.size()) {
+ if (!text.at(text.size()-1-i).isSpace())
+ return i;
+ ++i;
+ }
+ return i;
+}
+
+bool TabSettings::isIndentationClean(const QString &text) const
+{
+ int i = 0;
+ int spaceCount = 0;
+ while (i < text.size()) {
+ QChar c = text.at(i);
+ if (!c.isSpace())
+ return true;
+
+ if (c == QLatin1Char(' ')) {
+ ++spaceCount;
+ if (spaceCount == m_tabSize)
+ return false;
+ } else if (c == QLatin1Char('\t')) {
+ if (m_spacesForTabs || spaceCount != m_indentSize)
+ return false;
+ spaceCount = 0;
+ }
+ ++i;
+ }
+ return true;
+}
+
+
+int TabSettings::columnAt(const QString &text, int position) const
+{
+ int column = 0;
+ for (int i = 0; i < position; ++i) {
+ if (text.at(i) == QLatin1Char('\t'))
+ column = column - (column % m_tabSize) + m_tabSize;
+ else
+ ++column;
+ }
+ return column;
+}
+
+int TabSettings::spacesLeftFromPosition(const QString &text, int position) const
+{
+ int i = position;
+ while (i > 0) {
+ if (!text.at(i-1).isSpace())
+ break;
+ --i;
+ }
+ return position - i;
+}
+
+int TabSettings::indentedColumn(int column, bool doIndent) const
+{
+ int aligned = (column / m_indentSize) * m_indentSize;
+ if (doIndent)
+ return aligned + m_indentSize;
+ if (aligned < column)
+ return aligned;
+ return qMax(0, aligned - m_indentSize);
+}
+
+QString TabSettings::indentationString(int startColumn, int targetColumn) const
+{
+ targetColumn = qMax(startColumn, targetColumn);
+ if (m_spacesForTabs)
+ return QString(targetColumn - startColumn, QLatin1Char(' '));
+
+ QString s;
+ int alignedStart = startColumn - (startColumn % m_tabSize) + m_tabSize;
+ if (alignedStart > startColumn && alignedStart <= targetColumn) {
+ s += QLatin1Char('\t');
+ startColumn = alignedStart;
+ }
+ if (int columns = targetColumn - startColumn) {
+ int tabs = columns / m_tabSize;
+ s += QString(tabs, QLatin1Char('\t'));
+ s += QString(columns - tabs * m_tabSize, QLatin1Char(' '));
+ }
+ return s;
+}
+
+void TabSettings::indentLine(QTextBlock block, int newIndent) const
+{
+ const QString text = block.text();
+ const int oldBlockLength = text.size();
+
+ // Quickly check whether indenting is required.
+ if (oldBlockLength == 0 && newIndent == 0)
+ return;
+
+ const QString indentString = indentationString(0, newIndent);
+ newIndent = indentString.length();
+
+ if (oldBlockLength == indentString.length() && text == indentString)
+ return;
+
+ if (oldBlockLength > indentString.length() &&
+ text.startsWith(indentString) &&
+ !text.at(indentString.length()).isSpace()) {
+ return;
+ }
+
+ QTextCursor cursor(block);
+ cursor.beginEditBlock();
+ cursor.movePosition(QTextCursor::StartOfBlock);
+ cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, firstNonSpace(text));
+ cursor.removeSelectedText();
+ cursor.insertText(indentString);
+ cursor.endEditBlock();
+}
+
+bool TabSettings::equals(const TabSettings &ts) const
+{
+ return m_spacesForTabs == ts.m_spacesForTabs
+ && m_autoIndent == ts.m_autoIndent
+ && m_smartBackspace == ts.m_smartBackspace
+ && m_tabSize == ts.m_tabSize
+ && m_indentSize == ts.m_indentSize;
+}
+
+} // namespace TextEditor
diff --git a/src/plugins/texteditor/tabsettings.h b/src/plugins/texteditor/tabsettings.h
new file mode 100644
index 0000000000..8b326fadc4
--- /dev/null
+++ b/src/plugins/texteditor/tabsettings.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TABSETTINGS_H
+#define TABSETTINGS_H
+
+#include "texteditor_global.h"
+
+#include <QtGui/QTextBlock>
+
+QT_BEGIN_NAMESPACE
+class QSettings;
+QT_END_NAMESPACE
+
+namespace TextEditor {
+
+// Tab settings: Data type the GeneralSettingsPage acts on
+// with some convenience functions for formatting.
+struct TEXTEDITOR_EXPORT TabSettings
+{
+ TabSettings();
+
+ void toSettings(const QString &category, QSettings *s) const;
+ void fromSettings(const QString &category, const QSettings *s);
+
+
+ int lineIndentPosition(const QString &text) const;
+ int firstNonSpace(const QString &text) const;
+ int columnAt(const QString &text, int position) const;
+ int spacesLeftFromPosition(const QString &text, int position) const;
+ int indentedColumn(int column, bool doIndent = true) const;
+ QString indentationString(int startColumn, int targetColumn) const;
+
+ void indentLine(QTextBlock block, int newIndent) const;
+
+ int trailingWhitespaces(const QString &text) const;
+ bool isIndentationClean(const QString &text) const;
+
+
+ bool m_spacesForTabs;
+ bool m_autoIndent;
+ bool m_smartBackspace;
+ int m_tabSize;
+ int m_indentSize;
+
+ bool equals(const TabSettings &ts) const;
+};
+
+inline bool operator==(const TabSettings &t1, const TabSettings &t2) { return t1.equals(t2); }
+inline bool operator!=(const TabSettings &t1, const TabSettings &t2) { return !t1.equals(t2); }
+
+} // namespace TextEditor
+
+#endif // TABSETTINGS_H
diff --git a/src/plugins/texteditor/textblockiterator.cpp b/src/plugins/texteditor/textblockiterator.cpp
new file mode 100644
index 0000000000..51c894d9fc
--- /dev/null
+++ b/src/plugins/texteditor/textblockiterator.cpp
@@ -0,0 +1,96 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "textblockiterator.h"
+
+#include <QtGui/QTextDocument>
+
+using namespace TextEditor;
+
+TextBlockIterator::TextBlockIterator()
+ : m_document(0),
+ m_initialized(false)
+{ }
+
+TextBlockIterator::TextBlockIterator(const QTextBlock &block)
+ : m_document(block.document()),
+ m_block(block),
+ m_initialized(false)
+{ }
+
+bool TextBlockIterator::equals(const TextBlockIterator &other) const
+{
+ if (m_document != other.m_document)
+ return false;
+ return m_block == other.m_block;
+}
+
+QString TextBlockIterator::operator*() const
+{
+ if (! m_initialized)
+ read();
+ return m_text;
+}
+
+void TextBlockIterator::read() const
+{
+ m_initialized = true;
+ m_text = m_block.text();
+}
+
+TextBlockIterator &TextBlockIterator::operator++()
+{
+ m_initialized = false;
+ m_block = m_block.next();
+ return *this;
+}
+
+TextBlockIterator &TextBlockIterator::operator--()
+{
+ m_initialized = false;
+ m_block = m_block.previous();
+ return *this;
+}
+
+TextBlockIterator TextBlockIterator::operator++(int)
+{
+ TextBlockIterator prev;
+ ++*this;
+ return prev;
+}
+
+TextBlockIterator TextBlockIterator::operator--(int)
+{
+ TextBlockIterator prev;
+ --*this;
+ return prev;
+}
diff --git a/src/plugins/texteditor/textblockiterator.h b/src/plugins/texteditor/textblockiterator.h
new file mode 100644
index 0000000000..0f9c585a6f
--- /dev/null
+++ b/src/plugins/texteditor/textblockiterator.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef _TEXTBLOCKITERATOR_H
+#define _TEXTBLOCKITERATOR_H
+
+#include "texteditor_global.h"
+
+#include <QtGui/QTextBlock>
+
+namespace TextEditor {
+
+/* Iterator for the text blocks of a document. */
+class TEXTEDITOR_EXPORT TextBlockIterator {
+public:
+ TextBlockIterator();
+ TextBlockIterator(const QTextBlock &block);
+
+ bool equals(const TextBlockIterator &o) const;
+
+ QString operator*() const;
+ TextBlockIterator &operator++();
+ TextBlockIterator &operator--();
+ TextBlockIterator operator++(int);
+ TextBlockIterator operator--(int);
+
+private:
+ void read() const;
+
+private:
+ const QTextDocument *m_document;
+ QTextBlock m_block;
+ mutable QString m_text;
+ mutable bool m_initialized;
+};
+
+inline bool operator==(const TextBlockIterator &i1, const TextBlockIterator &i2) { return i1.equals(i2); }
+inline bool operator!=(const TextBlockIterator &i1, const TextBlockIterator &i2) { return !i1.equals(i2); }
+
+} // namespace TextEditor
+
+#endif // _TEXTBLOCKITERATOR_H
diff --git a/src/plugins/texteditor/texteditor.pri b/src/plugins/texteditor/texteditor.pri
new file mode 100644
index 0000000000..9d3789b825
--- /dev/null
+++ b/src/plugins/texteditor/texteditor.pri
@@ -0,0 +1,3 @@
+include(texteditor_dependencies.pri)
+
+LIBS *= -l$$qtLibraryTarget(TextEditor)
diff --git a/src/plugins/texteditor/texteditor.pro b/src/plugins/texteditor/texteditor.pro
new file mode 100644
index 0000000000..59c9cc4bb4
--- /dev/null
+++ b/src/plugins/texteditor/texteditor.pro
@@ -0,0 +1,58 @@
+TEMPLATE = lib
+TARGET = TextEditor
+DEFINES += TEXTEDITOR_LIBRARY
+include(../../qworkbenchplugin.pri)
+include(texteditor_dependencies.pri)
+SOURCES += texteditorplugin.cpp \
+ textfilewizard.cpp \
+ plaintexteditor.cpp \
+ plaintexteditorfactory.cpp \
+ basetextdocument.cpp \
+ basetexteditor.cpp \
+ texteditoractionhandler.cpp \
+ completionsupport.cpp \
+ completionwidget.cpp \
+ fontsettingspage.cpp \
+ tabsettings.cpp \
+ storagesettings.cpp \
+ displaysettings.cpp \
+ fontsettings.cpp \
+ textblockiterator.cpp \
+ linenumberfilter.cpp \
+ generalsettingspage.cpp \
+ basetextmark.cpp \
+ findinfiles.cpp \
+ basefilefind.cpp \
+ texteditorsettings.cpp \
+ codecselector.cpp
+HEADERS += texteditorplugin.h \
+ textfilewizard.h \
+ plaintexteditor.h \
+ plaintexteditorfactory.h \
+ basetexteditor_p.h \
+ basetextdocument.h \
+ completionsupport.h \
+ completionwidget.h \
+ basetexteditor.h \
+ texteditoractionhandler.h \
+ fontsettingspage.h \
+ icompletioncollector.h \
+ texteditorconstants.h \
+ tabsettings.h \
+ storagesettings.h \
+ displaysettings.h \
+ fontsettings.h \
+ textblockiterator.h \
+ itexteditable.h \
+ itexteditor.h \
+ linenumberfilter.h \
+ texteditor_global.h \
+ generalsettingspage.h \
+ basetextmark.h \
+ findinfiles.h \
+ basefilefind.h \
+ texteditorsettings.h \
+ codecselector.h
+FORMS += fontsettingspage.ui \
+ generalsettingspage.ui
+RESOURCES += texteditor.qrc
diff --git a/src/plugins/texteditor/texteditor.qrc b/src/plugins/texteditor/texteditor.qrc
new file mode 100644
index 0000000000..191343ce0e
--- /dev/null
+++ b/src/plugins/texteditor/texteditor.qrc
@@ -0,0 +1,7 @@
+<RCC>
+ <qresource prefix="/texteditor" >
+ <file>images/finddocuments.png</file>
+ <file>images/finddirectory.png</file>
+ <file>TextEditor.mimetypes.xml</file>
+ </qresource>
+</RCC>
diff --git a/src/plugins/texteditor/texteditor_dependencies.pri b/src/plugins/texteditor/texteditor_dependencies.pri
new file mode 100644
index 0000000000..87f23e9eed
--- /dev/null
+++ b/src/plugins/texteditor/texteditor_dependencies.pri
@@ -0,0 +1,4 @@
+include(../../libs/utils/utils.pri)
+include(../../plugins/find/find.pri)
+include(../../plugins/quickopen/quickopen.pri)
+include(../../plugins/coreplugin/coreplugin.pri)
diff --git a/src/plugins/texteditor/texteditor_global.h b/src/plugins/texteditor/texteditor_global.h
new file mode 100644
index 0000000000..ef7f01c641
--- /dev/null
+++ b/src/plugins/texteditor/texteditor_global.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+/****************************************************************************
+**
+** Copyright (C) 1992-$THISYEAR$ Trolltech AS. All rights reserved.
+**
+** This file is part of the $MODULE$ of the Qt Toolkit.
+**
+** $LICENSE$
+**
+** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
+** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+**
+****************************************************************************/
+
+#ifndef TEXTEDITOR_GLOBAL_H
+#define TEXTEDITOR_GLOBAL_H
+
+#include <QtCore/qglobal.h>
+
+#if defined(TEXTEDITOR_LIBRARY)
+# define TEXTEDITOR_EXPORT Q_DECL_EXPORT
+#else
+# define TEXTEDITOR_EXPORT Q_DECL_IMPORT
+#endif
+
+#endif // TEXTEDITOR_GLOBAL_H
diff --git a/src/plugins/texteditor/texteditoractionhandler.cpp b/src/plugins/texteditor/texteditoractionhandler.cpp
new file mode 100644
index 0000000000..91246dcc8c
--- /dev/null
+++ b/src/plugins/texteditor/texteditoractionhandler.cpp
@@ -0,0 +1,459 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditoractionhandler.h"
+#include "texteditorconstants.h"
+#include "basetexteditor.h"
+#include "texteditorplugin.h"
+#include "linenumberfilter.h"
+
+#include <quickopen/quickopenmanager.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/editormanager/editormanager.h>
+
+#include <QtCore/QSet>
+#include <QtCore/QtDebug>
+#include <QtGui/QAction>
+#include <QtGui/QTextCursor>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+TextEditorActionHandler::TextEditorActionHandler(Core::ICore *core,
+ const QString &context,
+ uint optionalActions) :
+ QObject(core),
+ m_optionalActions(optionalActions),
+ m_currentEditor(0),
+ m_core(core),
+ m_initialized(false)
+{
+ m_undoAction = m_redoAction = m_copyAction = m_cutAction = m_pasteAction
+ = m_selectAllAction = m_gotoAction = m_printAction = m_formatAction
+ = m_visualizeWhitespaceAction = m_textWrappingAction
+ = m_unCommentSelectionAction = m_unCollapseAllAction
+ = m_collapseAction = m_expandAction
+ = m_deleteLineAction = m_selectEncodingAction
+ = m_increaseFontSizeAction = m_decreaseFontSizeAction
+ = 0;
+
+ m_contextId << m_core->uniqueIDManager()->uniqueIdentifier(context);
+
+ connect(m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
+ this, SLOT(updateCurrentEditor(Core::IContext *)));
+}
+
+void TextEditorActionHandler::setupActions(BaseTextEditor *editor)
+{
+ initializeActions();
+ editor->setActionHack(this);
+ QObject::connect(editor, SIGNAL(undoAvailable(bool)), this, SLOT(updateUndoAction()));
+ QObject::connect(editor, SIGNAL(redoAvailable(bool)), this, SLOT(updateRedoAction()));
+ QObject::connect(editor, SIGNAL(copyAvailable(bool)), this, SLOT(updateCopyAction()));
+}
+
+
+void TextEditorActionHandler::initializeActions()
+{
+ if (!m_initialized) {
+ createActions();
+ m_initialized = true;
+ }
+}
+
+void TextEditorActionHandler::createActions()
+{
+ m_undoAction = registerNewAction(QLatin1String(Core::Constants::UNDO), this, SLOT(undoAction()),
+ tr("&Undo"));
+ m_redoAction = registerNewAction(QLatin1String(Core::Constants::REDO), this, SLOT(redoAction()),
+ tr("&Redo"));
+ m_copyAction = registerNewAction(QLatin1String(Core::Constants::COPY), this, SLOT(copyAction()));
+ m_cutAction = registerNewAction(QLatin1String(Core::Constants::CUT), this, SLOT(cutAction()));
+ m_pasteAction = registerNewAction(QLatin1String(Core::Constants::PASTE), this, SLOT(pasteAction()));
+ m_selectAllAction = registerNewAction(QLatin1String(Core::Constants::SELECTALL), this, SLOT(selectAllAction()));
+ m_gotoAction = registerNewAction(QLatin1String(Core::Constants::GOTO), this, SLOT(gotoAction()));
+ m_printAction = registerNewAction(QLatin1String(Core::Constants::PRINT), this, SLOT(printAction()));
+
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ Core::IActionContainer *medit = am->actionContainer(Core::Constants::M_EDIT);
+ Core::IActionContainer *advancedMenu = am->actionContainer(Core::Constants::M_EDIT_ADVANCED);
+
+ m_selectEncodingAction = new QAction(tr("Select Encoding..."), this);
+ Core::ICommand *command = am->registerAction(m_selectEncodingAction, Constants::SELECT_ENCODING, m_contextId);
+ connect(m_selectEncodingAction, SIGNAL(triggered()), this, SLOT(selectEncoding()));
+ medit->addAction(command, Core::Constants::G_EDIT_OTHER);
+
+
+ m_formatAction = new QAction(tr("Auto-&indent Selection"), this);
+ command = am->registerAction(m_formatAction, TextEditor::Constants::AUTO_INDENT_SELECTION, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+I")));
+ advancedMenu->addAction(command);
+ connect(m_formatAction, SIGNAL(triggered(bool)), this, SLOT(formatAction()));
+
+
+ m_visualizeWhitespaceAction = new QAction(tr("Visualize &Whitespace"), this);
+ m_visualizeWhitespaceAction->setCheckable(true);
+ command = am->registerAction(m_visualizeWhitespaceAction,
+ TextEditor::Constants::VISUALIZE_WHITESPACE, m_contextId);
+#ifndef Q_OS_MAC
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+E, Ctrl+V")));
+#endif
+
+ advancedMenu->addAction(command);
+ connect(m_visualizeWhitespaceAction, SIGNAL(triggered(bool)), this, SLOT(setVisualizeWhitespace(bool)));
+
+ m_textWrappingAction = new QAction(tr("Enable Text &Wrapping"), this);
+ m_textWrappingAction->setCheckable(true);
+ command = am->registerAction(m_textWrappingAction,
+ TextEditor::Constants::TEXT_WRAPPING, m_contextId);
+#ifndef Q_OS_MAC
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+E, Ctrl+W")));
+#endif
+ advancedMenu->addAction(command);
+ connect(m_textWrappingAction, SIGNAL(triggered(bool)), this, SLOT(setTextWrapping(bool)));
+
+
+ m_unCommentSelectionAction = new QAction(tr("(Un)Comment &Selection"), this);
+ command = am->registerAction(m_unCommentSelectionAction, Constants::UN_COMMENT_SELECTION, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+/")));
+ connect(m_unCommentSelectionAction, SIGNAL(triggered()), this, SLOT(unCommentSelection()));
+ advancedMenu->addAction(command);
+
+ m_deleteLineAction = new QAction(tr("Delete &Line"), this);
+ command = am->registerAction(m_deleteLineAction, Constants::DELETE_LINE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Shift+Del")));
+ connect(m_deleteLineAction, SIGNAL(triggered()), this, SLOT(deleteLine()));
+
+ m_collapseAction = new QAction(tr("Collapse"), this);
+ command = am->registerAction(m_collapseAction, Constants::COLLAPSE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+<")));
+ connect(m_collapseAction, SIGNAL(triggered()), this, SLOT(collapse()));
+ advancedMenu->addAction(command);
+
+ m_expandAction = new QAction(tr("Expand"), this);
+ command = am->registerAction(m_expandAction, Constants::EXPAND, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+>")));
+ connect(m_expandAction, SIGNAL(triggered()), this, SLOT(expand()));
+ advancedMenu->addAction(command);
+
+ m_unCollapseAllAction = new QAction(tr("(Un)&Collapse All"), this);
+ command = am->registerAction(m_unCollapseAllAction, Constants::UN_COLLAPSE_ALL, m_contextId);
+ connect(m_unCollapseAllAction, SIGNAL(triggered()), this, SLOT(unCollapseAll()));
+ advancedMenu->addAction(command);
+
+ m_increaseFontSizeAction = new QAction(tr("Increase Font Size"), this);
+ command = am->registerAction(m_increaseFontSizeAction, Constants::INCREASE_FONT_SIZE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl++")));
+ connect(m_increaseFontSizeAction, SIGNAL(triggered()), this, SLOT(increaseFontSize()));
+ advancedMenu->addAction(command);
+
+ m_decreaseFontSizeAction = new QAction(tr("Decrease Font Size"), this);
+ command = am->registerAction(m_decreaseFontSizeAction, Constants::DECREASE_FONT_SIZE, m_contextId);
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+-")));
+ connect(m_decreaseFontSizeAction, SIGNAL(triggered()), this, SLOT(decreaseFontSize()));
+ advancedMenu->addAction(command);
+}
+
+bool TextEditorActionHandler::supportsAction(const QString & /*id */) const
+{
+ return true;
+}
+
+QAction *TextEditorActionHandler::registerNewAction(const QString &id, const QString &title)
+{
+ if (!supportsAction(id))
+ return 0;
+
+ QAction *result = new QAction(title, this);
+ m_core->actionManager()->registerAction(result, id, m_contextId);
+ return result;
+}
+
+QAction *TextEditorActionHandler::registerNewAction(const QString &id,
+ QObject *receiver,
+ const char *slot,
+ const QString &title)
+{
+ QAction *rc = registerNewAction(id, title);
+ if (!rc)
+ return 0;
+
+ connect(rc, SIGNAL(triggered()), receiver, slot);
+ return rc;
+}
+
+TextEditorActionHandler::UpdateMode TextEditorActionHandler::updateMode() const
+{
+ if (!m_currentEditor)
+ return NoEditor;
+ return m_currentEditor->file()->isReadOnly() ? ReadOnlyMode : WriteMode;
+}
+
+void TextEditorActionHandler::updateActions()
+{
+ updateActions(updateMode());
+}
+
+void TextEditorActionHandler::updateActions(UpdateMode um)
+{
+ if (m_pasteAction)
+ m_pasteAction->setEnabled(um != NoEditor);
+ if (m_selectAllAction)
+ m_selectAllAction->setEnabled(um != NoEditor);
+ if (m_gotoAction)
+ m_gotoAction->setEnabled(um != NoEditor);
+ if (m_selectEncodingAction)
+ m_selectEncodingAction->setEnabled(um != NoEditor);
+ if (m_printAction)
+ m_printAction->setEnabled(um != NoEditor);
+ if (m_formatAction)
+ m_formatAction->setEnabled((m_optionalActions & Format) && um != NoEditor);
+ if (m_unCommentSelectionAction)
+ m_unCommentSelectionAction->setEnabled((m_optionalActions & UnCommentSelection) && um != NoEditor);
+ if (m_collapseAction)
+ m_collapseAction->setEnabled(um != NoEditor);
+ if (m_expandAction)
+ m_expandAction->setEnabled(um != NoEditor);
+ if (m_unCollapseAllAction)
+ m_unCollapseAllAction->setEnabled((m_optionalActions & UnCollapseAll) && um != NoEditor);
+ if (m_decreaseFontSizeAction)
+ m_decreaseFontSizeAction->setEnabled(um != NoEditor);
+ if (m_increaseFontSizeAction)
+ m_increaseFontSizeAction->setEnabled(um != NoEditor);
+ if (m_visualizeWhitespaceAction) {
+ m_visualizeWhitespaceAction->setEnabled(um != NoEditor);
+ if (m_currentEditor)
+ m_visualizeWhitespaceAction->setChecked(m_currentEditor->displaySettings().m_visualizeWhitespace);
+ }
+ if (m_textWrappingAction) {
+ m_textWrappingAction->setEnabled(um != NoEditor);
+ if (m_currentEditor)
+ m_textWrappingAction->setChecked(m_currentEditor->displaySettings().m_textWrapping);
+ }
+
+ updateRedoAction();
+ updateUndoAction();
+ updateCopyAction();
+}
+
+void TextEditorActionHandler::updateRedoAction()
+{
+ if (m_redoAction)
+ m_redoAction->setEnabled(m_currentEditor && m_currentEditor->document()->isRedoAvailable());
+}
+
+void TextEditorActionHandler::updateUndoAction()
+{
+ if (m_undoAction)
+ m_undoAction->setEnabled(m_currentEditor && m_currentEditor->document()->isUndoAvailable());
+}
+
+void TextEditorActionHandler::updateCopyAction()
+{
+ const bool hasCopyableText = m_currentEditor && m_currentEditor->textCursor().hasSelection();
+ if (m_cutAction)
+ m_cutAction->setEnabled(hasCopyableText && updateMode() == WriteMode);
+ if (m_copyAction)
+ m_copyAction->setEnabled(hasCopyableText);
+}
+
+void TextEditorActionHandler::undoAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->undo();
+}
+
+void TextEditorActionHandler::redoAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->redo();
+}
+
+void TextEditorActionHandler::copyAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->copy();
+}
+
+void TextEditorActionHandler::cutAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->cut();
+}
+
+void TextEditorActionHandler::pasteAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->paste();
+}
+
+void TextEditorActionHandler::selectAllAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->selectAll();
+}
+
+void TextEditorActionHandler::gotoAction()
+{
+ QuickOpen::QuickOpenManager *quickopen = QuickOpen::QuickOpenManager::instance();
+ Q_ASSERT(quickopen);
+ QString shortcut = TextEditorPlugin::instance()->lineNumberFilter()->shortcutString();
+ quickopen->show(shortcut + " <line number>", 2, 13);
+}
+
+void TextEditorActionHandler::printAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->print(m_core->printer());
+}
+
+void TextEditorActionHandler::formatAction()
+{
+ if (m_currentEditor)
+ m_currentEditor->format();
+}
+
+
+void TextEditorActionHandler::setVisualizeWhitespace(bool checked)
+{
+ if (m_currentEditor) {
+ DisplaySettings ds = m_currentEditor->displaySettings();
+ ds.m_visualizeWhitespace = checked;
+ m_currentEditor->setDisplaySettings(ds);
+ }
+}
+
+void TextEditorActionHandler::setTextWrapping(bool checked)
+{
+ if (m_currentEditor) {
+ DisplaySettings ds = m_currentEditor->displaySettings();
+ ds.m_textWrapping = checked;
+ m_currentEditor->setDisplaySettings(ds);
+ }
+}
+
+void TextEditorActionHandler::unCommentSelection()
+{
+ if (m_currentEditor)
+ m_currentEditor->unCommentSelection();
+}
+
+void TextEditorActionHandler::deleteLine()
+{
+ if (m_currentEditor)
+ m_currentEditor->deleteLine();
+}
+
+void TextEditorActionHandler::unCollapseAll()
+{
+ if (m_currentEditor)
+ m_currentEditor->unCollapseAll();
+}
+
+void TextEditorActionHandler::collapse()
+{
+ if (m_currentEditor)
+ m_currentEditor->collapse();
+}
+
+void TextEditorActionHandler::expand()
+{
+ if (m_currentEditor)
+ m_currentEditor->expand();
+}
+
+void TextEditorActionHandler::selectEncoding()
+{
+ if (m_currentEditor)
+ m_currentEditor->selectEncoding();
+}
+
+void TextEditorActionHandler::increaseFontSize()
+{
+ if (m_currentEditor)
+ m_currentEditor->zoomIn();
+}
+
+void TextEditorActionHandler::decreaseFontSize()
+{
+ if (m_currentEditor)
+ m_currentEditor->zoomOut();
+}
+
+
+void TextEditorActionHandler::updateCurrentEditor(Core::IContext *object)
+{
+ do {
+ if (!object) {
+ if (!m_currentEditor)
+ return;
+
+ m_currentEditor = 0;
+ break;
+ }
+ BaseTextEditor *editor = qobject_cast<BaseTextEditor *>(object->widget());
+ if (!editor) {
+ if (!m_currentEditor)
+ return;
+
+ m_currentEditor = 0;
+ break;
+ }
+
+ if (editor == m_currentEditor)
+ return;
+
+ if (editor->actionHack() != this) {
+ m_currentEditor = 0;
+ break;
+ }
+
+ m_currentEditor = editor;
+
+ } while (false);
+ updateActions();
+}
+
+
+const QPointer<BaseTextEditor> &TextEditorActionHandler::currentEditor() const
+{
+ return m_currentEditor;
+}
+
+Core::ICore *TextEditorActionHandler::core() const
+{
+ return m_core;
+}
+
diff --git a/src/plugins/texteditor/texteditoractionhandler.h b/src/plugins/texteditor/texteditoractionhandler.h
new file mode 100644
index 0000000000..d0c222f848
--- /dev/null
+++ b/src/plugins/texteditor/texteditoractionhandler.h
@@ -0,0 +1,143 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORACTIONHANDLER_H
+#define TEXTEDITORACTIONHANDLER_H
+
+#include "texteditor_global.h"
+#include "basetexteditor.h"
+
+#include "coreplugin/icontext.h"
+#include "coreplugin/icore.h"
+
+#include <QtCore/QObject>
+#include <QtCore/QPointer>
+#include <QtCore/QList>
+
+namespace TextEditor {
+
+class BaseTextEditor;
+
+// Redirects slots from global actions to the respective editor.
+
+class TEXTEDITOR_EXPORT TextEditorActionHandler : public QObject
+{
+ Q_OBJECT
+
+public:
+ enum OptionalActionsMask {
+ None = 0,
+ Format = 1,
+ UnCommentSelection = 2,
+ UnCollapseAll = 4
+ };
+
+ TextEditorActionHandler(Core::ICore *core,
+ const QString &context,
+ uint optionalActions = None);
+ void setupActions(BaseTextEditor *editor);
+
+ void initializeActions();
+
+public slots:
+ void updateActions();
+ void updateRedoAction();
+ void updateUndoAction();
+ void updateCopyAction();
+
+protected:
+ const QPointer<BaseTextEditor> &currentEditor() const;
+ QAction *registerNewAction(const QString &id, const QString &title = QString());
+ QAction *registerNewAction(const QString &id, QObject *receiver, const char *slot,
+ const QString &title = QString());
+ Core::ICore *core() const;
+
+ enum UpdateMode { NoEditor , ReadOnlyMode, WriteMode };
+ UpdateMode updateMode() const;
+
+ virtual void createActions();
+ virtual bool supportsAction(const QString &id) const;
+ virtual void updateActions(UpdateMode um);
+
+private slots:
+ void undoAction();
+ void redoAction();
+ void copyAction();
+ void cutAction();
+ void pasteAction();
+ void selectAllAction();
+ void gotoAction();
+ void printAction();
+ void formatAction();
+ void setVisualizeWhitespace(bool);
+ void setTextWrapping(bool);
+ void unCommentSelection();
+ void unCollapseAll();
+ void collapse();
+ void expand();
+ void deleteLine();
+ void selectEncoding();
+ void increaseFontSize();
+ void decreaseFontSize();
+ void updateCurrentEditor(Core::IContext *object);
+
+private:
+ QAction *m_undoAction;
+ QAction *m_redoAction;
+ QAction *m_copyAction;
+ QAction *m_cutAction;
+ QAction *m_pasteAction;
+ QAction *m_selectAllAction;
+ QAction *m_gotoAction;
+ QAction *m_printAction;
+ QAction *m_formatAction;
+ QAction *m_visualizeWhitespaceAction;
+ QAction *m_textWrappingAction;
+ QAction *m_unCommentSelectionAction;
+ QAction *m_unCollapseAllAction;
+ QAction *m_collapseAction;
+ QAction *m_expandAction;
+ QAction *m_deleteLineAction;
+ QAction *m_selectEncodingAction;
+ QAction *m_increaseFontSizeAction;
+ QAction *m_decreaseFontSizeAction;
+
+ uint m_optionalActions;
+ QPointer<BaseTextEditor> m_currentEditor;
+ Core::ICore *m_core;
+ QList<int> m_contextId;
+ bool m_initialized;
+};
+
+} // namespace TextEditor
+
+#endif // TEXTEDITORACTIONHANDLER_H
diff --git a/src/plugins/texteditor/texteditorconstants.h b/src/plugins/texteditor/texteditorconstants.h
new file mode 100644
index 0000000000..5133a2c148
--- /dev/null
+++ b/src/plugins/texteditor/texteditorconstants.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORCONSTANTS_H
+#define TEXTEDITORCONSTANTS_H
+
+namespace TextEditor {
+namespace Constants {
+
+const char * const C_TEXTEDITOR = "Text Editor";
+const char * const COMPLETE_THIS = "TextEditor.CompleteThis";
+const char * const VISUALIZE_WHITESPACE = "TextEditor.VisualizeWhitespace";
+const char * const TEXT_WRAPPING = "TextEditor.TextWrapping";
+const char * const UN_COMMENT_SELECTION = "TextEditor.UnCommentSelection";
+const char * const COLLAPSE = "TextEditor.Collapse";
+const char * const EXPAND = "TextEditor.Expand";
+const char * const UN_COLLAPSE_ALL = "TextEditor.UnCollapseAll";
+const char * const AUTO_INDENT_SELECTION = "TextEditor.AutoIndentSelection";
+const char * const INCREASE_FONT_SIZE = "TextEditor.IncreaseFontSize";
+const char * const DECREASE_FONT_SIZE = "TextEditor.DecreaseFontSize";
+const char * const DELETE_LINE = "TextEditor.DeleteLine";
+const char * const DELETE_WORD = "TextEditor.DeleteWord";
+const char * const SELECT_ENCODING = "TextEditor.SelectEncoding";
+const char * const C_TEXTEDITOR_MIMETYPE_TEXT = "text/plain";
+const char * const C_TEXTEDITOR_MIMETYPE_XML = "application/xml";
+
+
+// Text color and style categories
+const char * const C_TEXT = "Text";
+
+const char * const C_SELECTION = "Selection";
+const char * const C_LINE_NUMBER = "LineNumber";
+const char * const C_SEARCH_RESULT = "SearchResult";
+const char * const C_SEARCH_SCOPE = "SearchScope";
+const char * const C_PARENTHESES = "Parentheses";
+const char * const C_CURRENT_LINE = "CurrentLine";
+
+const char * const C_NUMBER = "Number";
+const char * const C_STRING = "String";
+const char * const C_TYPE = "Type";
+const char * const C_KEYWORD = "Keyword";
+const char * const C_OPERATOR = "Operator";
+const char * const C_PREPROCESSOR = "Preprocessor";
+const char * const C_LABEL = "Label";
+const char * const C_COMMENT = "Comment";
+const char * const C_DISABLED_CODE = "DisabledCode";
+
+const char * const C_ADDED_LINE = "AddedLine";
+const char * const C_REMOVED_LINE = "RemovedLine";
+const char * const C_DIFF_FILE = "DiffFile";
+const char * const C_DIFF_LOCATION = "DiffLocation";
+
+const char * const C_VARIABLE = "Variable";
+const char * const C_FUNCTION = "Function";
+
+} // namespace Constants
+} // namespace TextEditor
+
+#endif // TEXTEDITORCONSTANTS_H
diff --git a/src/plugins/texteditor/texteditorplugin.cpp b/src/plugins/texteditor/texteditorplugin.cpp
new file mode 100644
index 0000000000..5e943bd70c
--- /dev/null
+++ b/src/plugins/texteditor/texteditorplugin.cpp
@@ -0,0 +1,180 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditorplugin.h"
+
+#include "findinfiles.h"
+#include "fontsettings.h"
+#include "linenumberfilter.h"
+#include "texteditorconstants.h"
+#include "texteditorsettings.h"
+#include "textfilewizard.h"
+#include "plaintexteditorfactory.h"
+#include "plaintexteditor.h"
+#include "storagesettings.h"
+
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/mimedatabase.h>
+#include <coreplugin/uniqueidmanager.h>
+#include <coreplugin/actionmanager/actionmanagerinterface.h>
+#include <coreplugin/actionmanager/icommand.h>
+#include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/texteditoractionhandler.h>
+
+#include <QtCore/qplugin.h>
+#include <QtGui/QShortcut>
+#include <QtGui/QMainWindow>
+
+using namespace TextEditor;
+using namespace TextEditor::Internal;
+
+TextEditorPlugin *TextEditorPlugin::m_instance = 0;
+
+TextEditorPlugin::TextEditorPlugin() :
+ m_core(0),
+ m_settings(0),
+ m_wizard(0),
+ m_editorFactory(0),
+ m_lineNumberFilter(0)
+{
+ Q_ASSERT(!m_instance);
+ m_instance = this;
+}
+
+TextEditorPlugin::~TextEditorPlugin()
+{
+ m_instance = 0;
+}
+
+TextEditorPlugin *TextEditorPlugin::instance()
+{
+ return m_instance;
+}
+
+Core::ICore *TextEditorPlugin::core()
+{
+ return m_instance->m_core;
+}
+
+//ExtensionSystem::PluginInterface
+bool TextEditorPlugin::initialize(const QStringList & /*arguments*/, QString *errorMessage)
+{
+ m_core = ExtensionSystem::PluginManager::instance()->getObject<Core::ICore>();
+
+ if (!m_core->mimeDatabase()->addMimeTypes(QLatin1String(":/texteditor/TextEditor.mimetypes.xml"), errorMessage))
+ return false;
+
+ Core::BaseFileWizardParameters wizardParameters(Core::IWizard::FileWizard);
+ wizardParameters.setDescription(tr("This creates a new text file (.txt)"));
+ wizardParameters.setName(tr("Text File"));
+ wizardParameters.setCategory(QLatin1String("General"));
+ wizardParameters.setTrCategory(tr("General"));
+ m_wizard = new TextFileWizard(QLatin1String(TextEditor::Constants::C_TEXTEDITOR_MIMETYPE_TEXT),
+ QLatin1String(Core::Constants::K_DEFAULT_TEXT_EDITOR),
+ QLatin1String("text$"),
+ wizardParameters, m_core);
+ // Add text file wizard
+ addAutoReleasedObject(m_wizard);
+
+
+ m_settings = new TextEditorSettings(this, this);
+
+ // Add plain text editor factory
+ m_editorFactory = new PlainTextEditorFactory;
+ addAutoReleasedObject(m_editorFactory);
+
+ // Goto line functionality for quick open
+ m_lineNumberFilter = new LineNumberFilter(m_core->editorManager());
+ addAutoReleasedObject(m_lineNumberFilter);
+
+ int contextId = m_core->uniqueIDManager()->uniqueIdentifier(TextEditor::Constants::C_TEXTEDITOR);
+ QList<int> context = QList<int>() << contextId;
+ Core::ActionManagerInterface *am = m_core->actionManager();
+
+ // Add shortcut for invoking automatic completion
+ QShortcut *completionShortcut = new QShortcut(m_core->mainWindow());
+ completionShortcut->setWhatsThis(tr("Triggers a completion in this scope"));
+ // Make sure the shortcut still works when the completion widget is active
+ completionShortcut->setContext(Qt::ApplicationShortcut);
+ Core::ICommand *command = am->registerShortcut(completionShortcut, Constants::COMPLETE_THIS, context);
+#ifndef Q_OS_MAC
+ command->setDefaultKeySequence(QKeySequence(tr("Ctrl+Space")));
+#else
+ command->setDefaultKeySequence(QKeySequence(tr("Meta+Space")));
+#endif
+ connect(completionShortcut, SIGNAL(activated()), this, SLOT(invokeCompletion()));
+
+ addAutoReleasedObject(new FindInFiles(m_core, m_core->pluginManager()->getObject<Find::SearchResultWindow>()));
+
+ return true;
+}
+
+void TextEditorPlugin::extensionsInitialized()
+{
+ m_editorFactory->actionHandler()->initializeActions();
+}
+
+void TextEditorPlugin::initializeEditor(TextEditor::PlainTextEditor *editor)
+{
+ // common actions
+ m_editorFactory->actionHandler()->setupActions(editor);
+
+ // settings
+ connect(m_settings, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)),
+ editor, SLOT(setFontSettings(TextEditor::FontSettings)));
+ connect(m_settings, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
+ editor, SLOT(setTabSettings(TextEditor::TabSettings)));
+ connect(m_settings, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)),
+ editor, SLOT(setStorageSettings(TextEditor::StorageSettings)));
+ connect(m_settings, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)),
+ editor, SLOT(setDisplaySettings(TextEditor::DisplaySettings)));
+
+ // tab settings rely on font settings
+ editor->setFontSettings(m_settings->fontSettings());
+ editor->setTabSettings(m_settings->tabSettings());
+ editor->setStorageSettings(m_settings->storageSettings());
+ editor->setDisplaySettings(m_settings->displaySettings());
+}
+
+void TextEditorPlugin::invokeCompletion()
+{
+ if (!m_core)
+ return;
+
+ Core::IEditor *iface = m_core->editorManager()->currentEditor();
+ ITextEditor *editor = qobject_cast<ITextEditor *>(iface);
+ if (editor)
+ editor->triggerCompletions();
+}
+
+
+Q_EXPORT_PLUGIN(TextEditorPlugin)
diff --git a/src/plugins/texteditor/texteditorplugin.h b/src/plugins/texteditor/texteditorplugin.h
new file mode 100644
index 0000000000..578095f609
--- /dev/null
+++ b/src/plugins/texteditor/texteditorplugin.h
@@ -0,0 +1,94 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORPLUGIN_H
+#define TEXTEDITORPLUGIN_H
+
+#include <extensionsystem/iplugin.h>
+
+QT_BEGIN_NAMESPACE
+class QAction;
+QT_END_NAMESPACE
+
+namespace Core {
+class ICore;
+class IEditor;
+}
+
+namespace TextEditor {
+
+class FontSettings;
+class FontSettingsPage;
+class TextEditorSettings;
+class TextFileWizard;
+class PlainTextEditor;
+
+namespace Internal {
+
+class LineNumberFilter;
+class PlainTextEditorFactory;
+
+class TextEditorPlugin : public ExtensionSystem::IPlugin
+{
+ Q_OBJECT
+
+public:
+ TextEditorPlugin();
+ virtual ~TextEditorPlugin();
+
+ static TextEditorPlugin *instance();
+ static Core::ICore *core();
+
+ // ExtensionSystem::PluginInterface
+ bool initialize(const QStringList &arguments, QString *);
+ void extensionsInitialized();
+
+ void initializeEditor(PlainTextEditor *editor);
+
+ LineNumberFilter *lineNumberFilter() { return m_lineNumberFilter; }
+
+private slots:
+ void invokeCompletion();
+
+private:
+ static TextEditorPlugin *m_instance;
+ Core::ICore *m_core;
+ TextEditorSettings *m_settings;
+ TextFileWizard *m_wizard;
+ PlainTextEditorFactory *m_editorFactory;
+ LineNumberFilter *m_lineNumberFilter;
+};
+
+} // namespace Internal
+} // namespace TextEditor
+
+#endif // TEXTEDITORPLUGIN_H
diff --git a/src/plugins/texteditor/texteditorsettings.cpp b/src/plugins/texteditor/texteditorsettings.cpp
new file mode 100644
index 0000000000..0292215f99
--- /dev/null
+++ b/src/plugins/texteditor/texteditorsettings.cpp
@@ -0,0 +1,152 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "texteditorsettings.h"
+
+#include "displaysettings.h"
+#include "generalsettingspage.h"
+#include "fontsettingspage.h"
+#include "storagesettings.h"
+#include "tabsettings.h"
+#include "texteditorconstants.h"
+#include "texteditorplugin.h"
+
+#include <QApplication>
+
+using namespace TextEditor;
+using namespace TextEditor::Constants;
+
+TextEditorSettings *TextEditorSettings::m_instance = 0;
+
+TextEditorSettings::TextEditorSettings(Internal::TextEditorPlugin *plugin,
+ QObject *parent)
+ : QObject(parent)
+{
+ Q_ASSERT(!m_instance);
+ m_instance = this;
+
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+
+ // Note: default background colors are coming from FormatDescription::background()
+
+ // Add font preference page
+ FormatDescriptions formatDescriptions;
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_TEXT), tr("Text")));
+
+ // Special categories
+ const QPalette p = QApplication::palette();
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_SELECTION), tr("Selection"), p.color(QPalette::HighlightedText)));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_LINE_NUMBER), tr("Line Number")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_SEARCH_RESULT), tr("Search Result")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_SEARCH_SCOPE), tr("Search Scope")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_PARENTHESES), tr("Parentheses")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_CURRENT_LINE), tr("Current Line")));
+
+ // Standard categories
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_NUMBER), tr("Number"), Qt::darkBlue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_STRING), tr("String"), Qt::darkGreen));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_TYPE), tr("Type"), Qt::darkMagenta));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_KEYWORD), tr("Keyword"), Qt::darkYellow));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_OPERATOR), tr("Operator")));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_PREPROCESSOR), tr("Preprocessor"), Qt::darkBlue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_LABEL), tr("Label"), Qt::darkRed));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_COMMENT), tr("Comment"), Qt::darkGreen));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_DISABLED_CODE), tr("Disabled Code"), Qt::lightGray));
+
+ // Diff categories
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_ADDED_LINE), tr("Added Line"), Qt::blue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_REMOVED_LINE), tr("Removed Line"), Qt::red));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_DIFF_FILE), tr("Diff File"), Qt::black));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_DIFF_LOCATION), tr("Diff Location"), Qt::green));
+
+ // Pro file categories
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_VARIABLE), tr("Variable"), Qt::blue));
+ formatDescriptions.push_back(FormatDescription(QLatin1String(C_FUNCTION), tr("Function"), Qt::green));
+
+ m_fontSettingsPage = new FontSettingsPage(formatDescriptions,
+ QLatin1String("TextEditor"),
+ tr("Text Editor"),
+ plugin->core());
+ pm->addObject(m_fontSettingsPage);
+
+ // Add the GUI used to configure the tab, storage and display settings
+ TextEditor::GeneralSettingsPageParameters generalSettingsPageParameters;
+ generalSettingsPageParameters.name = tr("General");
+ generalSettingsPageParameters.category = QLatin1String("TextEditor");
+ generalSettingsPageParameters.trCategory = tr("Text Editor");
+ generalSettingsPageParameters.settingsPrefix = QLatin1String("text");
+ m_generalSettingsPage = new GeneralSettingsPage(plugin->core(), generalSettingsPageParameters, this);
+ pm->addObject(m_generalSettingsPage);
+
+ connect(m_fontSettingsPage, SIGNAL(changed(TextEditor::FontSettings)),
+ this, SIGNAL(fontSettingsChanged(TextEditor::FontSettings)));
+ connect(m_generalSettingsPage, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)),
+ this, SIGNAL(tabSettingsChanged(TextEditor::TabSettings)));
+ connect(m_generalSettingsPage, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)),
+ this, SIGNAL(storageSettingsChanged(TextEditor::StorageSettings)));
+ connect(m_generalSettingsPage, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)),
+ this, SIGNAL(displaySettingsChanged(TextEditor::DisplaySettings)));
+}
+
+TextEditorSettings::~TextEditorSettings()
+{
+ ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
+ pm->removeObject(m_generalSettingsPage);
+ pm->removeObject(m_fontSettingsPage);
+
+ m_instance = 0;
+}
+
+TextEditorSettings *TextEditorSettings::instance()
+{
+ return m_instance;
+}
+
+FontSettings TextEditorSettings::fontSettings() const
+{
+ return m_fontSettingsPage->fontSettings();
+}
+
+TabSettings TextEditorSettings::tabSettings() const
+{
+ return m_generalSettingsPage->tabSettings();
+}
+
+StorageSettings TextEditorSettings::storageSettings() const
+{
+ return m_generalSettingsPage->storageSettings();
+}
+
+DisplaySettings TextEditorSettings::displaySettings() const
+{
+ return m_generalSettingsPage->displaySettings();
+}
diff --git a/src/plugins/texteditor/texteditorsettings.h b/src/plugins/texteditor/texteditorsettings.h
new file mode 100644
index 0000000000..1b5a08e966
--- /dev/null
+++ b/src/plugins/texteditor/texteditorsettings.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTEDITORSETTINGS_H
+#define TEXTEDITORSETTINGS_H
+
+#include "texteditor_global.h"
+
+#include <QtCore/QObject>
+
+namespace TextEditor {
+
+class GeneralSettingsPage;
+class FontSettingsPage;
+class FontSettings;
+struct TabSettings;
+struct StorageSettings;
+struct DisplaySettings;
+
+namespace Internal {
+class TextEditorPlugin;
+}
+
+/**
+ * This class provides a central place for basic text editor settings. These
+ * settings include font settings, tab settings, storage settings and display
+ * settings.
+ */
+class TEXTEDITOR_EXPORT TextEditorSettings : public QObject
+{
+ Q_OBJECT
+
+public:
+ TextEditorSettings(Internal::TextEditorPlugin *plugin, QObject *parent);
+ ~TextEditorSettings();
+
+ static TextEditorSettings *instance();
+
+ FontSettings fontSettings() const;
+ TabSettings tabSettings() const;
+ StorageSettings storageSettings() const;
+ DisplaySettings displaySettings() const;
+
+signals:
+ void fontSettingsChanged(const TextEditor::FontSettings &);
+ void tabSettingsChanged(const TextEditor::TabSettings &);
+ void storageSettingsChanged(const TextEditor::StorageSettings &);
+ void displaySettingsChanged(const TextEditor::DisplaySettings &);
+
+private:
+ TextEditor::FontSettingsPage *m_fontSettingsPage;
+ TextEditor::GeneralSettingsPage *m_generalSettingsPage;
+
+ static TextEditorSettings *m_instance;
+};
+
+} // namespace TextEditor
+
+#endif // TEXTEDITORSETTINGS_H
diff --git a/src/plugins/texteditor/textfilewizard.cpp b/src/plugins/texteditor/textfilewizard.cpp
new file mode 100644
index 0000000000..b40201044c
--- /dev/null
+++ b/src/plugins/texteditor/textfilewizard.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#include "textfilewizard.h"
+#include "basetexteditor.h"
+#include "texteditorconstants.h"
+
+namespace TextEditor {
+
+TextFileWizard::TextFileWizard(const QString &mimeType,
+ const QString &editorKind,
+ const QString &suggestedFileName,
+ const BaseFileWizardParameters &parameters,
+ Core::ICore *core,
+ QObject *parent) :
+ Core::StandardFileWizard(parameters, core, parent),
+ m_mimeType(mimeType),
+ m_editorKind(editorKind),
+ m_suggestedFileName(suggestedFileName)
+{
+}
+
+Core::GeneratedFiles
+ TextFileWizard::generateFilesFromPath(const QString &path, const QString &name,
+ QString * /*errorMessage*/) const
+{
+ const QString suffix = preferredSuffix(m_mimeType);
+ const QString fileName = Core::BaseFileWizard::buildFileName(path, name, suffix);
+ Core::GeneratedFile file(fileName);
+ file.setEditorKind(m_editorKind);
+ return Core::GeneratedFiles() << file;
+}
+
+}
diff --git a/src/plugins/texteditor/textfilewizard.h b/src/plugins/texteditor/textfilewizard.h
new file mode 100644
index 0000000000..a3cb379733
--- /dev/null
+++ b/src/plugins/texteditor/textfilewizard.h
@@ -0,0 +1,67 @@
+/***************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Qt Software Information (qt-info@nokia.com)
+**
+**
+** Non-Open Source Usage
+**
+** Licensees may use this file in accordance with the Qt Beta Version
+** License Agreement, Agreement version 2.2 provided with the Software or,
+** alternatively, in accordance with the terms contained in a written
+** agreement between you and Nokia.
+**
+** GNU General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License versions 2.0 or 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the packaging
+** of this file. Please review the following information to ensure GNU
+** General Public Licensing requirements will be met:
+**
+** http://www.fsf.org/licensing/licenses/info/GPLv2.html and
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt GPL Exception version
+** 1.2, included in the file GPL_EXCEPTION.txt in this package.
+**
+***************************************************************************/
+#ifndef TEXTFILEWIZARD_H
+#define TEXTFILEWIZARD_H
+
+#include "texteditor_global.h"
+
+#include <coreplugin/basefilewizard.h>
+
+namespace TextEditor {
+
+class TEXTEDITOR_EXPORT TextFileWizard : public Core::StandardFileWizard
+{
+ Q_OBJECT
+
+public:
+ typedef Core::BaseFileWizardParameters BaseFileWizardParameters;
+ TextFileWizard(const QString &mimeType,
+ const QString &editorKind,
+ const QString &suggestedFileName,
+ const BaseFileWizardParameters &parameters,
+ Core::ICore *core,
+ QObject *parent = 0);
+
+protected:
+ virtual Core::GeneratedFiles
+ generateFilesFromPath(const QString &path, const QString &name,
+ QString *errorMessage) const;
+private:
+ const QString m_mimeType;
+ const QString m_editorKind;
+ const QString m_suggestedFileName;
+};
+
+} // namespace TextEditor
+
+#endif // TEXTFILEWIZARD_H