aboutsummaryrefslogtreecommitdiffstats
path: root/src/modules/editor/ScriptEditorImplementation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/modules/editor/ScriptEditorImplementation.cpp')
-rw-r--r--src/modules/editor/ScriptEditorImplementation.cpp1137
1 files changed, 1137 insertions, 0 deletions
diff --git a/src/modules/editor/ScriptEditorImplementation.cpp b/src/modules/editor/ScriptEditorImplementation.cpp
new file mode 100644
index 000000000..6bd4bed4a
--- /dev/null
+++ b/src/modules/editor/ScriptEditorImplementation.cpp
@@ -0,0 +1,1137 @@
+//=============================================================================
+//
+// File : ScriptEditorImplementation.cpp
+// Creation date : Sun Mar 28 1999 16:11:48 CEST by Szymon Stefanek
+//
+// This file is part of the KVIrc IRC client distribution
+// Copyright (C) 1999 Szymon Stefanek <pragma at kvirc dot net>
+// Copyright (C) 2005 Tonino Imbesi
+// Copyright (C) 2005-2008 Alessandro Carbone (elfonol at gmail dot com)
+//
+// This program is FREE software. You can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your opinion) any later version.
+//
+// This program is distributed in the HOPE that it will be USEFUL,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+// See the GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, write to the Free Software Foundation,
+// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+//
+//=============================================================================
+
+#include "ScriptEditorImplementation.h"
+
+#include "KviFileUtils.h"
+#include "kvi_fileextensions.h"
+#include "KviLocale.h"
+#include "KviFileDialog.h"
+#include "KviQString.h"
+#include "KviConfigurationFile.h"
+#include "KviModule.h"
+#include "KviPointerList.h"
+#include "KviApplication.h"
+#include "KviConsoleWindow.h"
+#include "KviWindow.h"
+#include "KviIconManager.h"
+#include "KviKvsKernel.h"
+#include "KviModuleManager.h"
+#include "KviConfigurationFile.h"
+#include "KviTalVBox.h"
+#include "KviTalHBox.h"
+#include "KviTalGroupBox.h"
+
+#include <QScrollBar>
+#include <QLayout>
+#include <QMessageBox>
+#include <QTimer>
+#include <QCursor>
+#include <QFont>
+#include <QRect>
+#include <QEvent>
+#include <QKeyEvent>
+#include <QMenu>
+#include <QListWidget>
+#include <QPainter>
+
+extern KVIRC_API KviModuleManager * g_pModuleManager;
+extern KviPointerList<ScriptEditorImplementation> * g_pScriptEditorWindowList;
+extern KviModule * g_pEditorModulePointer;
+
+static QColor g_clrBackground(0,0,0);
+static QColor g_clrNormalText(100,255,0);
+static QColor g_clrBracket(255,0,0);
+static QColor g_clrComment(0,120,0);
+static QColor g_clrFunction(255,255,0);
+static QColor g_clrKeyword(120,120,150);
+static QColor g_clrVariable(200,200,200);
+static QColor g_clrPunctuation(180,180,0);
+static QColor g_clrFind(255,0,0);
+
+#if defined(COMPILE_ON_WINDOWS) || defined(COMPILE_ON_MINGW)
+ #define KVI_SCRIPTEDITOR_DEFAULT_FONT "Courier New"
+#else
+ #define KVI_SCRIPTEDITOR_DEFAULT_FONT "Monospace"
+#endif
+static QFont g_fntNormal(KVI_SCRIPTEDITOR_DEFAULT_FONT,8);
+
+static bool bSemaphore=false;
+static bool bCompleterReady=false;
+
+
+ScriptEditorWidget::ScriptEditorWidget(QWidget * pParent)
+: QTextEdit(pParent)
+{
+ m_pSyntaxHighlighter=0;
+ setTabStopWidth(48);
+ setAcceptRichText(false);
+ setWordWrapMode(QTextOption::NoWrap);
+ m_pParent = pParent;
+ m_szHelp = "Nothing";
+ updateOptions();
+ m_szFind = "";
+ m_pCompleter = 0;
+ QStringList szListFunctionsCommands;
+ QString tmp("kvscompleter.idx");
+ iModulesCount=0;
+ iIndex=0;
+ QString szPath;
+ g_pApp->getLocalKvircDirectory(szPath,KviApplication::ConfigPlugins,tmp);
+
+ if(!KviFileUtils::fileExists(szPath))
+ {
+ if (!bSemaphore){
+ bSemaphore=true;
+ m_pStartTimer = new QTimer();
+ m_pStartTimer->setInterval(1000);
+ connect(m_pStartTimer,SIGNAL(timeout()),this,SLOT(asyncCompleterCreation()));
+ m_pStartTimer->start(500);
+ }
+ else{
+ m_pStartTimer = new QTimer();
+ m_pStartTimer->setInterval(2000);
+ connect(m_pStartTimer,SIGNAL(timeout()),this,SLOT(checkReadyCompleter()));
+ m_pStartTimer->start(1000);
+ }
+ } else loadCompleterFromFile();
+}
+
+ScriptEditorWidget::~ScriptEditorWidget()
+{
+ if(m_pCompleter)
+ delete m_pCompleter;
+ disableSyntaxHighlighter();
+}
+
+void ScriptEditorWidget::checkReadyCompleter()
+{
+ if(bCompleterReady)
+ {
+ m_pStartTimer->stop();
+ delete m_pStartTimer;
+ m_pStartTimer=0;
+ loadCompleterFromFile();
+ }
+}
+
+void ScriptEditorWidget::asyncCompleterCreation()
+{
+ //static int iIndex = 0;
+ //static int iModulesCount = 0;
+ if(!iIndex)
+ {
+ m_pListCompletition = new QStringList();
+ QString szPath;
+
+ g_pApp->getGlobalKvircDirectory(szPath,KviApplication::Modules);
+
+ QDir d(szPath);
+
+#if defined(COMPILE_ON_WINDOWS)
+ d.setNameFilters(QStringList("kvi*.dll"));
+#elif defined(COMPILE_ON_MINGW)
+ d.setNameFilters(QStringList("libkvi*.dll"));
+#else
+ d.setNameFilters(QStringList("libkvi*.so"));
+#endif
+ m_pListModulesNames = new QStringList(d.entryList(QDir::Files | QDir::Readable));
+ iModulesCount = m_pListModulesNames->count();
+ }
+ QString szModuleName = m_pListModulesNames->at(iIndex);
+ iIndex++;
+
+#if defined(COMPILE_ON_WINDOWS)
+ szModuleName=szModuleName.replace("kvi","");
+ szModuleName=szModuleName.replace(".dll","");
+#elif defined(COMPILE_ON_MINGW)
+ szModuleName=szModuleName.replace("libkvi","");
+ szModuleName=szModuleName.replace(".dll","");
+#else
+ szModuleName=szModuleName.replace("libkvi","");
+ szModuleName=szModuleName.replace(".so","");
+#endif
+
+ KviModule * pModule = g_pModuleManager->getModule(szModuleName);
+ if(pModule)
+ {
+ pModule->getAllFunctionsCommandsModule(m_pListCompletition,szModuleName);
+ }
+
+ if(iIndex == iModulesCount)
+ {
+ m_pStartTimer->stop();
+ m_pStartTimer->deleteLater();
+ m_pStartTimer = 0;
+ QString szTmp("kvscompleter.idx");
+ QString szPath;
+ g_pApp->getLocalKvircDirectory(szPath,KviApplication::ConfigPlugins,szTmp);
+ KviKvsKernel::instance()->getAllFunctionsCommandsCore(m_pListCompletition);
+ QString szBuffer = m_pListCompletition->join(",");
+ QFile f(szPath);
+ f.open(QIODevice::WriteOnly);
+ f.write(szBuffer.toUtf8());
+ f.close();
+ createCompleter(*m_pListCompletition);
+ iIndex = 0;
+ iModulesCount = 0;
+ bCompleterReady=true;
+ delete m_pListCompletition;
+ delete m_pListModulesNames;
+ }
+}
+
+void ScriptEditorWidget::loadCompleterFromFile()
+{
+ QStringList szListFunctionsCommand;
+ QString szTmp("kvscompleter.idx");
+ QString szPath;
+ g_pApp->getLocalKvircDirectory(szPath,KviApplication::ConfigPlugins,szTmp);
+ QString szBuffer;
+ QFile f(szPath);
+ f.open(QIODevice::ReadOnly);
+ szBuffer = f.readAll();
+ f.close();
+ szListFunctionsCommand = szBuffer.split(',');
+ createCompleter(szListFunctionsCommand);
+}
+
+void ScriptEditorWidget::createCompleter(QStringList & list)
+{
+ m_pCompleter = new QCompleter(list);
+ m_pCompleter->setCaseSensitivity(Qt::CaseInsensitive);
+ m_pCompleter->setWrapAround(false);
+ m_pCompleter->setWidget(this);
+ m_pCompleter->setModelSorting(QCompleter::CaseSensitivelySortedModel);
+ m_pCompleter->setCompletionMode(QCompleter::PopupCompletion);
+ m_pCompleter->setCaseSensitivity(Qt::CaseInsensitive);
+ QObject::connect(m_pCompleter, SIGNAL(activated(const QString &)),this, SLOT(insertCompletion(const QString &)));
+}
+
+void ScriptEditorWidget::insertCompletion(const QString & szCompletion)
+{
+ QTextCursor tc = textCursor();
+ int iExtra = szCompletion.length() - m_pCompleter->completionPrefix().length();
+
+ tc.movePosition(QTextCursor::Left);
+ tc.movePosition(QTextCursor::EndOfWord);
+
+ QString szTmp = szCompletion.right(iExtra);
+ if(szCompletion.left(1)=="$")
+ szTmp.append("(");
+ else
+ szTmp.append(" ");
+
+ tc.insertText(szTmp);
+ setTextCursor(tc);
+}
+
+void ScriptEditorWidget::contextMenuEvent(QContextMenuEvent * e)
+{
+ QMenu * pMenu = createStandardContextMenu();
+ pMenu->addAction(__tr2qs_ctx("Context sensitive help","editor"),this,SLOT(slotHelp()),Qt::CTRL+Qt::Key_H);
+ pMenu->addAction(__tr2qs_ctx("&Replace","editor"),this,SLOT(slotReplace()),Qt::CTRL+Qt::Key_R);
+ pMenu->exec(e->globalPos());
+ delete pMenu;
+}
+
+void ScriptEditorWidget::slotFind()
+{
+ m_szFind = ((ScriptEditorImplementation*)m_pParent)->findLineEdit()->text();
+ setText(toPlainText());
+}
+
+void ScriptEditorWidget::slotReplace()
+{
+ ScriptEditorReplaceDialog * pDialog = new ScriptEditorReplaceDialog(this,__tr2qs_ctx("Find & Replace","editor"));
+ connect(pDialog,SIGNAL(replaceAll(const QString &,const QString &)),m_pParent,SLOT(slotReplaceAll(const QString &,const QString &)));
+ connect(pDialog,SIGNAL(initFind()),m_pParent,SLOT(slotInitFind()));
+ connect(pDialog,SIGNAL(nextFind(const QString &)),m_pParent,SLOT(slotNextFind(const QString &)));
+
+ if(pDialog->exec()){};
+}
+
+void ScriptEditorWidget::slotHelp()
+{
+ contextSensitiveHelp();
+}
+void ScriptEditorWidget::enableSyntaxHighlighter()
+{
+ // we currently delete and re-create the m_pSyntaxHighlighter
+ // as a trick to ensure proper re-highlightning to occur
+ if (!m_pSyntaxHighlighter)
+ m_pSyntaxHighlighter = new ScriptEditorSyntaxHighlighter(this);
+}
+void ScriptEditorWidget::disableSyntaxHighlighter()
+{
+ if (m_pSyntaxHighlighter) delete m_pSyntaxHighlighter;
+ m_pSyntaxHighlighter = 0;
+}
+
+void ScriptEditorWidget::updateOptions()
+{
+ QPalette p = palette();
+ p.setColor(QPalette::Base,g_clrBackground);
+ p.setColor(QPalette::Text,g_clrNormalText);
+ setPalette(p);
+ setFont(g_fntNormal);
+ setTextColor(g_clrNormalText);
+ disableSyntaxHighlighter();
+ enableSyntaxHighlighter();
+
+ p = ((ScriptEditorImplementation*)m_pParent)->findLineEdit()->palette();
+ p.setColor(foregroundRole(),g_clrFind);
+ ((ScriptEditorImplementation*)m_pParent)->findLineEdit()->setPalette(p);
+}
+
+void ScriptEditorWidget::keyPressEvent(QKeyEvent * e)
+{
+ if(m_pCompleter && m_pCompleter->popup()->isVisible())
+ {
+ switch(e->key())
+ {
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_Escape:
+ case Qt::Key_Tab:
+ case Qt::Key_Backtab:
+ e->ignore();
+ return;
+ default:
+ break;
+ }
+ }
+
+ if(e->modifiers() == Qt::ControlModifier)
+ {
+ switch(e->key())
+ {
+ case Qt::Key_B:
+ insertPlainText("$b");
+ return;
+ case Qt::Key_K:
+ insertPlainText("$k");
+ return;
+ case Qt::Key_O:
+ insertPlainText("$o");
+ return;
+ case Qt::Key_U:
+ insertPlainText("$u");
+ return;
+ case Qt::Key_Enter:
+ case Qt::Key_Return:
+ case Qt::Key_PageUp:
+ e->ignore(); // allow the parent to process it
+ return;
+ break;
+ }
+ }
+// Adapted from QT4 QCompleter example
+ bool isShortcut = ((e->modifiers() & Qt::ControlModifier) && e->key() == Qt::Key_E); // CTRL+E
+ if (!m_pCompleter || !isShortcut) // don't process the shortcut when we have a completer
+ QTextEdit::keyPressEvent(e);
+ const bool ctrlOrShift = e->modifiers() & (Qt::ControlModifier | Qt::ShiftModifier);
+ if (!m_pCompleter || (ctrlOrShift && e->text().isEmpty()))
+ return;
+ static QString eow("~!@#$%^&*()_+{}|:\"<>?,/;'[]\\-="); // end of word
+ bool hasModifier = (e->modifiers() != Qt::NoModifier) && !ctrlOrShift;
+ QString completionPrefix = textUnderCursor();
+ if (!isShortcut && (hasModifier || e->text().isEmpty()|| completionPrefix.length() < 3 || eow.contains(e->text().right(1))))
+ {
+ m_pCompleter->popup()->hide();
+ return;
+ }
+ if (completionPrefix != m_pCompleter->completionPrefix())
+ {
+ m_pCompleter->setCompletionPrefix(completionPrefix);
+ m_pCompleter->popup()->setCurrentIndex(m_pCompleter->completionModel()->index(0, 0));
+ }
+ QRect cr = cursorRect();
+ cr.setWidth(m_pCompleter->popup()->sizeHintForColumn(0)+ m_pCompleter->popup()->verticalScrollBar()->sizeHint().width());
+ m_pCompleter->complete(cr);
+}
+
+QString ScriptEditorWidget::textUnderCursor() const
+{
+ QString szWord;
+ QTextCursor tc = textCursor();
+ if(tc.atBlockStart())
+ return QString();
+ tc.clearSelection();
+ tc.movePosition(QTextCursor::StartOfWord,QTextCursor::KeepAnchor);
+ if(tc.atBlockStart())
+ {
+ szWord.append(tc.selectedText());
+ tc.movePosition(QTextCursor::EndOfWord,QTextCursor::KeepAnchor);
+ szWord.append(tc.selectedText());
+ if(tc.atBlockEnd()){
+ return szWord;
+ }
+ tc.movePosition(QTextCursor::NextCharacter,QTextCursor::KeepAnchor);
+ szWord.append(tc.selectedText());
+ if(szWord.right(1)!=".")
+ szWord.chop(1);
+ return szWord;
+ }
+
+ tc.movePosition(QTextCursor::PreviousCharacter,QTextCursor::KeepAnchor);
+ szWord=tc.selectedText();
+ if(szWord.left(1)==".")
+ {
+ tc.movePosition(QTextCursor::StartOfWord);
+ tc.movePosition(QTextCursor::PreviousCharacter);
+ tc.movePosition(QTextCursor::PreviousWord);
+ tc.movePosition(QTextCursor::EndOfWord,QTextCursor::KeepAnchor,1);
+ szWord.prepend(tc.selectedText());
+ } else szWord.remove(0,1);
+ return szWord;
+}
+/*
+void ScriptEditorWidget::mouseReleaseEvent(QMouseEvent * e)
+{
+
+ return;
+ QRect r = cursorRect();
+ QTextCursor cur = cursorForPosition(e->pos());
+ // cur.select(
+
+
+ //completelistbox->hide();
+ if (e->button() == Qt::RightButton)
+ {
+ QString szBuffer;
+ /\*
+ int iPara = paragraphAt(e->pos());
+ int iIndex=charAt(e->pos(),&iPara);
+ szBuffer = this->text(iPara);
+ getWordOnCursor(szBuffer,iIndex);
+ *\/
+ QRect r = cursorRect();
+ QTextCursor cur = cursorForPosition(e->pos());
+ cur.select(QTextCursor::WordUnderCursor);
+ szBuffer = cur.selectedText();
+ QString szTmp = szBuffer;
+ KviPointerList<QString> * pList;
+ if(szTmp.left(1) == "$")
+ {
+ szTmp.remove(0,1);
+ pList = KviKvsKernel::instance()->completeCommandAllocateResult(szTmp);
+ if (pList->count() != 1)
+ szBuffer = "";
+ else
+ szBuffer = *(pList->at(0));
+ } else {
+ pList = KviKvsKernel::instance()->completeCommandAllocateResult(szTmp);
+ if (pList->count() != 1)
+ szBuffer = "";
+ else
+ szBuffer = *(pList->at(0));
+ }
+
+ for (unsigned int i=0; i < pList->count(); i++)
+ QString str = *(pList->at(i));
+
+ KviKvsKernel::instance()->freeCompletionResult(pList);
+ m_szHelp = szBuffer;
+ }
+
+ QTextEdit::mouseReleaseEvent(e);
+}
+*/
+bool ScriptEditorWidget::contextSensitiveHelp() const
+{
+ /*
+ QString szBuffer;
+ int iPara, iIndex;
+ getCursorPosition(&iPara,&iIndex);
+ szBuffer = text(iPara);
+ getWordOnCursor(szBuffer,iIndex);
+ */
+
+ QRect r = cursorRect();
+ QTextCursor cur = cursorForPosition(QPoint(r.x(),r.y()));
+ cur.select(QTextCursor::WordUnderCursor);
+ QString szText = cur.selectedText();
+ QString szTmp = szText;
+ /*
+ KviPointerList<QString> * pList;
+ if(szTmp.left(1) == "$")
+ {
+ szTmp.remove(0,1);
+ pList = g_pUserParser->completeFunctionAllocateResult(szTmp);
+ } else {
+ pList = g_pUserParser->completeCommandAllocateResult(szTmp);
+ }
+ qDebug("command or func %s",szTmp.toUtf8().data());
+
+ bool bOk = false;
+ if(pList)
+ {
+ for(QString * s = pList->first(); s; s = pList->next())
+ {
+ if(KviQString::equalCI(*s,szBuffer))
+ {
+ pList->last();
+ bOk = true;
+ }
+ }
+ }
+
+ g_pUserParser->freeCompletionResult(pList);
+ if(!bOk)return false;
+
+ QString szParse;
+ KviQString::sprintf(szParse,"timer -s (help,0){ help -s %Q; }",&szBuffer);
+ qDebug("parsing %s",szParse.toLatin1());
+ KviKvsScript::run(szParse,(KviWindow*)g_pApp->activeConsole());
+ */
+
+ return true;
+}
+
+ScriptEditorWidgetColorOptions::ScriptEditorWidgetColorOptions(QWidget * pParent)
+: QDialog(pParent)
+{
+ m_pSelectorInterfaceList = new KviPointerList<KviSelectorInterface>;
+ m_pSelectorInterfaceList->setAutoDelete(false);
+ setWindowTitle(__tr2qs_ctx("Preferences","editor"));
+ QGridLayout * g = new QGridLayout(this);
+ KviTalVBox * box = new KviTalVBox(this);
+ g->addWidget(box,0,0);
+ box->setMargin(0);
+ box->setSpacing(0);
+ KviFontSelector * f = new KviFontSelector(box,__tr2qs_ctx("Font:","editor"),&g_fntNormal,true);
+ m_pSelectorInterfaceList->append(f);
+ KviTalGroupBox * gbox = new KviTalGroupBox(Qt::Horizontal,__tr2qs_ctx("Colors","editor"),box);
+ gbox->setInsideSpacing(0);
+
+ addColorSelector(gbox,__tr2qs_ctx("Background:","editor"),&g_clrBackground,true);
+ addColorSelector(gbox,__tr2qs_ctx("Normal text:","editor"),&g_clrNormalText,true);
+ addColorSelector(gbox,__tr2qs_ctx("Brackets:","editor"),&g_clrBracket,true);
+ addColorSelector(gbox,__tr2qs_ctx("Comments:","editor"),&g_clrComment,true);
+ addColorSelector(gbox,__tr2qs_ctx("Functions:","editor"),&g_clrFunction,true);
+ addColorSelector(gbox,__tr2qs_ctx("Keywords:","editor"),&g_clrKeyword,true);
+ addColorSelector(gbox,__tr2qs_ctx("Variables:","editor"),&g_clrVariable,true);
+ addColorSelector(gbox,__tr2qs_ctx("Punctuation:","editor"),&g_clrPunctuation,true);
+ addColorSelector(gbox,__tr2qs_ctx("Find:","editor"),&g_clrFind,true);
+
+ KviTalHBox * hbox = new KviTalHBox(box);
+
+ QPushButton * b = new QPushButton(__tr2qs_ctx("OK","editor"),hbox);
+ b->setDefault(true);
+ connect(b,SIGNAL(clicked()),this,SLOT(okClicked()));
+
+ b = new QPushButton(__tr2qs_ctx("Cancel","editor"),hbox);
+ connect(b,SIGNAL(clicked()),this,SLOT(reject()));
+}
+
+ScriptEditorWidgetColorOptions::~ScriptEditorWidgetColorOptions()
+{
+ delete m_pSelectorInterfaceList;
+}
+
+KviColorSelector * ScriptEditorWidgetColorOptions::addColorSelector(QWidget * pParent,const QString & txt,QColor * pOption,bool bEnabled)
+{
+ KviColorSelector * s = new KviColorSelector(pParent,txt,pOption,bEnabled);
+ m_pSelectorInterfaceList->append(s);
+ return s;
+}
+
+void ScriptEditorWidgetColorOptions::okClicked()
+{
+ for(KviSelectorInterface * i = m_pSelectorInterfaceList->first();i;i = m_pSelectorInterfaceList->next())
+ {
+ i->commit();
+ }
+ accept();
+}
+
+
+ScriptEditorSyntaxHighlighter::ScriptEditorSyntaxHighlighter(ScriptEditorWidget * pWidget)
+: QSyntaxHighlighter(pWidget),m_pTextEdit(pWidget)
+{
+ // code adpated from QT4 example
+
+ // FIX-ME: "function ..." - "function internal ..."
+ // FIX-ME: "@$"
+ // FIX-ME: "\" escape char
+ updateSyntaxtTextFormat();
+
+ KviScriptHighlightingRule rule;
+
+ rule.pattern=QRegExp("([=()[\\]!\"?<>;:.,+-])+");
+ rule.format=punctuationFormat;
+ highlightingRules.append(rule);
+
+ rule.pattern=QRegExp("[{};](|[a-zA-Z]|[a-zA-Z]+[a-zA-Z0-9_\\.:]*)");
+ rule.format=keywordFormat;
+ highlightingRules.append(rule);
+
+
+ rule.pattern=QRegExp("[$](|[a-zA-Z0-9]+[a-zA-Z0-9_\\.:]*)");
+ rule.format=functionFormat;
+ highlightingRules.append(rule);
+
+ rule.pattern=QRegExp("[%](|[a-zA-Z]|[a-zA-Z]+[a-zA-Z0-9_\\.]*)");
+ rule.format=variableFormat;
+ highlightingRules.append(rule);
+
+ rule.pattern=QRegExp("([{}])+");
+ rule.format=bracketFormat;
+ highlightingRules.append(rule);
+}
+
+ScriptEditorSyntaxHighlighter::~ScriptEditorSyntaxHighlighter()
+{
+}
+
+void ScriptEditorSyntaxHighlighter::updateSyntaxtTextFormat()
+{
+ punctuationFormat.setForeground(g_clrPunctuation);
+ keywordFormat.setForeground(g_clrKeyword);
+ functionFormat.setForeground(g_clrFunction);
+ variableFormat.setForeground(g_clrVariable);
+ bracketFormat.setForeground(g_clrBracket);
+ commentFormat.setForeground(g_clrComment);
+ findFormat.setForeground(g_clrFind);
+}
+
+#define SKIP_SPACES \
+ while(iIndexStart < szText.size()) \
+ { \
+ if(szText.at(iIndexStart).unicode()=='\t' || szText.at(iIndexStart).unicode()==' ') \
+ { \
+ iIndexStart++; \
+ } else { \
+ break; \
+ } \
+ } \
+
+void ScriptEditorSyntaxHighlighter::highlightBlock(const QString & szText)
+{
+ if(szText.isEmpty())
+ {
+ setCurrentBlockState(previousBlockState());
+ return;
+ }
+
+ int iIndexStart=0;
+ setCurrentBlockState(0);
+
+ if(previousBlockState() == 1)
+ {
+ // inside a multiline comment
+ int iCommentEnd = szText.indexOf("*/");
+ if(iCommentEnd < 0)
+ {
+ // not found: comment until the end of the block
+ setCurrentBlockState(1);
+ setFormat(iIndexStart,szText.length(),commentFormat);
+ return;
+ }
+ // skip 2 chars
+ iCommentEnd+=2;
+ // end of comment found
+ setFormat(iIndexStart,iCommentEnd - iIndexStart,commentFormat);
+ iIndexStart = iCommentEnd;
+ }
+
+ SKIP_SPACES
+
+ if (iIndexStart == szText.size())
+ return;
+
+ // check 'commands' and comments
+ int iCommandStart=iIndexStart;
+ if (szText.at(iIndexStart).unicode()!='$' && szText.at(iIndexStart).unicode()!='{' && szText.at(iIndexStart).unicode()!='}' && szText.at(iIndexStart).unicode()!='%')
+ {
+ switch(szText.at(iIndexStart).unicode())
+ {
+ case '#':
+ // single line comment, bash style
+ while(iIndexStart<szText.size() && szText.at(iIndexStart).unicode() != '\n')
+ iIndexStart++;
+ setFormat(iCommandStart,iIndexStart-iCommandStart,commentFormat);
+ break;
+ case '/':
+ if((iIndexStart+1)<szText.size())
+ {
+ if(szText.at(iIndexStart+1).unicode()=='/')
+ {
+ // single line comment, c++ style
+ iIndexStart++;
+ while(iIndexStart<szText.size() && szText.at(iIndexStart).unicode() != '\n')
+ iIndexStart++;
+ setFormat(iCommandStart,iIndexStart-iCommandStart,commentFormat);
+ break;
+ }
+
+ if(szText.at(iIndexStart+1).unicode()=='*')
+ {
+ // multi line comment, c style
+ iIndexStart++;
+ setCurrentBlockState(1);
+ while(iIndexStart<szText.size())
+ {
+ if((iIndexStart+1)<szText.size())
+ {
+ if(szText.at(iIndexStart).unicode() == '*' &&
+ szText.at(iIndexStart+1).unicode() == '/')
+ {
+ iIndexStart+=2;
+ setCurrentBlockState(0);
+ break;
+ }
+ }
+ iIndexStart++;
+ }
+ setFormat(iCommandStart,iIndexStart-iCommandStart,commentFormat);
+
+ SKIP_SPACES
+
+ if(currentBlockState()==0)
+ {
+ iCommandStart=iIndexStart;
+ } else {
+ break;
+ }
+ // else fallback to command (a command can start at the end of a /* comment */)
+ }
+ // else not a comment, fallback to command
+ }
+ default:
+ //command
+ while(iIndexStart<szText.size() && (szText.at(iIndexStart).isLetterOrNumber() || (szText.at(iIndexStart).unicode() == '.') || (szText.at(iIndexStart).unicode() == '_') || (szText.at(iIndexStart).unicode()== ':') ))
+ {
+ iIndexStart++;
+ }
+ setFormat(iCommandStart,iIndexStart-iCommandStart,keywordFormat);
+ break;
+ }
+ }
+
+ // code from QT4 example
+ int index=0;
+ foreach (KviScriptHighlightingRule rule, highlightingRules)
+ {
+ QRegExp expression(rule.pattern);
+ QString sz=expression.pattern();
+
+ index = szText.indexOf(expression,iIndexStart);
+
+ while (index >= 0)
+ {
+ int length = expression.matchedLength();
+ setFormat(index, length, rule.format);
+ index = szText.indexOf(expression, index + length);
+ }
+ }
+
+ // 'found matches' highlighting
+ ScriptEditorWidget * pEditor = ((ScriptEditorWidget *)textEdit());
+ QString szFind = pEditor->m_szFind;
+ if (!szFind.isEmpty())
+ {
+ index = szText.indexOf(szFind,0,Qt::CaseInsensitive);
+ int length=szFind.length();
+ while (index >= 0)
+ {
+ setFormat(index, length, findFormat);
+ index = szText.indexOf(szFind,index + length,Qt::CaseInsensitive);
+ }
+ }
+}
+
+
+ScriptEditorImplementation::ScriptEditorImplementation(QWidget * par)
+:KviScriptEditor(par)
+{
+ m_pOptionsDialog=0;
+ if(g_pScriptEditorWindowList->isEmpty())loadOptions();
+ g_pScriptEditorWindowList->append(this);
+ m_lastCursorPos = 0;
+ QGridLayout * g = new QGridLayout(this);
+
+ m_pFindLineEdit = new QLineEdit(" ",this);
+ m_pFindLineEdit->setText("");
+
+ QPalette p = m_pFindLineEdit->palette();
+ p.setColor(foregroundRole(), g_clrFind);
+ m_pFindLineEdit->setPalette(p);
+
+ m_pEditor = new ScriptEditorWidget(this);
+
+ g->addWidget(m_pEditor, 0, 0, 1,4);
+ g->setRowStretch(0,1);
+
+ QToolButton * b = new QToolButton(this);
+ b->setIcon(*(g_pIconManager->getSmallIcon(KVI_SMALLICON_OPTIONS)));
+
+ b->setObjectName("ToolButtonEditor");
+ b->setMinimumWidth(24);
+ g->addWidget(b,1,0);
+
+ KviTalPopupMenu * pop = new KviTalPopupMenu(b);
+ pop->insertItem(__tr2qs_ctx("&Open...","editor"),this,SLOT(loadFromFile()));
+ pop->insertItem(__tr2qs_ctx("&Save As...","editor"),this,SLOT(saveToFile()));
+ pop->insertSeparator();
+ pop->insertItem(__tr2qs_ctx("&Configure Editor...","editor"),this,SLOT(configureColors()));
+ b->setMenu(pop);
+ b->setPopupMode(QToolButton::InstantPopup);
+
+ g->setColumnStretch(1,1);
+ g->setColumnStretch(2,10);
+ g->addWidget(m_pFindLineEdit,1,2);
+
+ QLabel * pLab = new QLabel(this);
+ pLab->setText(__tr2qs_ctx("Find","editor"));
+ g->addWidget(pLab,1,1);
+
+ m_pRowColLabel = new QLabel("0",this);
+ m_pRowColLabel->setFrameStyle(QFrame::Sunken | QFrame::Panel);
+ m_pRowColLabel->setMinimumWidth(80);
+ g->addWidget(m_pRowColLabel,1,3);
+
+ connect(m_pFindLineEdit,SIGNAL(returnPressed()),m_pEditor,SLOT(slotFind()));
+ connect(m_pFindLineEdit,SIGNAL(returnPressed()),this,SLOT(slotFind()));
+ connect(m_pEditor,SIGNAL(cursorPositionChanged()),this,SLOT(updateRowColLabel()));
+ connect(m_pEditor,SIGNAL(selectionChanged()),this,SLOT(updateRowColLabel()));
+ m_lastCursorPos = 0;
+}
+
+ScriptEditorImplementation::~ScriptEditorImplementation()
+{
+ if(m_pOptionsDialog)
+ {
+ m_pOptionsDialog->deleteLater();
+ m_pOptionsDialog=0;
+ }
+ g_pScriptEditorWindowList->removeRef(this);
+ if(g_pScriptEditorWindowList->isEmpty())
+ saveOptions();
+}
+
+void ScriptEditorImplementation::loadOptions()
+{
+ QString szTmp;
+ g_pEditorModulePointer->getDefaultConfigFileName(szTmp);
+
+ KviConfigurationFile cfg(szTmp,KviConfigurationFile::Read);
+ g_clrBackground = cfg.readColorEntry("Background",QColor(0,0,0));;
+ g_clrNormalText = cfg.readColorEntry("NormalText",QColor(100,255,0));
+ g_clrBracket = cfg.readColorEntry("Bracket",QColor(255,0,0));
+ g_clrComment = cfg.readColorEntry("Comment",QColor(0,120,0));
+ g_clrFunction = cfg.readColorEntry("Function",QColor(255,255,0));
+ g_clrKeyword = cfg.readColorEntry("Keyword",QColor(120,120,150));
+ g_clrVariable = cfg.readColorEntry("Variable",QColor(200,200,200));
+ g_clrPunctuation = cfg.readColorEntry("Punctuation",QColor(180,180,0));
+ g_clrFind = cfg.readColorEntry("Find",QColor(255,0,0));
+ g_fntNormal = cfg.readFontEntry("Font",QFont(KVI_SCRIPTEDITOR_DEFAULT_FONT,8));
+}
+
+bool ScriptEditorImplementation::isModified()
+{
+ return m_pEditor->document()->isModified();
+}
+void ScriptEditorImplementation::setModified(bool bModified)
+{
+ return m_pEditor->document()->setModified(bModified);
+}
+void ScriptEditorImplementation::slotFind()
+{
+ emit find(m_pFindLineEdit->text());
+}
+
+void ScriptEditorImplementation::slotNextFind(const QString &) //szText
+{
+// emit nextFind(const QString & szText);
+}
+
+void ScriptEditorImplementation::slotInitFind()
+{
+ emit initFind();
+}
+
+void ScriptEditorImplementation::slotReplaceAll(const QString & szToReplace, const QString & szReplaceWith)
+{
+ emit replaceAll(szToReplace,szReplaceWith);
+}
+
+void ScriptEditorImplementation::saveOptions()
+{
+ QString szTmp;
+ g_pEditorModulePointer->getDefaultConfigFileName(szTmp);
+
+ KviConfigurationFile cfg(szTmp,KviConfigurationFile::Write);
+ cfg.writeEntry("Background",g_clrBackground);;
+ cfg.writeEntry("NormalText",g_clrNormalText);
+ cfg.writeEntry("Bracket",g_clrBracket);
+ cfg.writeEntry("Comment",g_clrComment);
+ cfg.writeEntry("Function",g_clrFunction);
+ cfg.writeEntry("Keyword",g_clrKeyword);
+ cfg.writeEntry("Variable",g_clrVariable);
+ cfg.writeEntry("Punctuation",g_clrPunctuation);
+ cfg.writeEntry("Find",g_clrFind);
+ cfg.writeEntry("Font",g_fntNormal);
+}
+
+void ScriptEditorImplementation::setFocus()
+{
+ m_pEditor->setFocus();
+}
+
+void ScriptEditorImplementation::focusInEvent(QFocusEvent *)
+{
+ m_pEditor->setFocus();
+}
+
+void ScriptEditorImplementation::setEnabled(bool bEnabled)
+{
+ QWidget::setEnabled(bEnabled);
+ m_pEditor->setEnabled(bEnabled);
+ m_pRowColLabel->setEnabled(bEnabled);
+}
+
+void ScriptEditorImplementation::saveToFile()
+{
+ QString szFileName;
+ if(KviFileDialog::askForSaveFileName(szFileName,
+ __tr2qs_ctx("Choose a Filename - KVIrc","editor"),
+ QString::null,
+ QString::null,false,true,true))
+ {
+ QString szBuffer = m_pEditor->toPlainText();
+
+ //if(tmp.isEmpty())tmp = "";
+ //KviCString buffer = tmp.toUtf8().data();
+ if(!KviFileUtils::writeFile(szFileName,szBuffer))
+ {
+ QString szTmp;
+ QMessageBox::warning(this,
+ __tr2qs_ctx("Save Failed - KVIrc","editor"),
+ KviQString::sprintf(szTmp,__tr2qs_ctx("Can't open the file %s for writing.","editor"),&szFileName));
+ }
+ }
+}
+
+void ScriptEditorImplementation::setText(const char * txt)
+{
+ setText(QByteArray(txt));
+}
+void ScriptEditorImplementation::setUnHighlightedText(const QString & szText)
+{
+ m_pEditor->disableSyntaxHighlighter();
+ m_pEditor->setText(szText);
+}
+void ScriptEditorImplementation::setText(const QByteArray & szText)
+{
+ m_pEditor->setPlainText(szText.data());
+ m_pEditor->document()->setModified(false);
+ updateRowColLabel();
+}
+void ScriptEditorImplementation::setReadOnly(bool bReadOnly)
+{
+ m_pEditor->setReadOnly(bReadOnly);
+}
+void ScriptEditorImplementation::getText(QByteArray & szText)
+{
+ szText = m_pEditor->toPlainText().toUtf8();
+}
+
+void ScriptEditorImplementation::setText(const QString & szText)
+{
+ m_pEditor->enableSyntaxHighlighter();
+ m_pEditor->setPlainText(szText);
+ QTextCursor cur=m_pEditor->textCursor();
+ cur.movePosition(QTextCursor::End);
+ m_pEditor->setTextCursor(cur);
+ m_pEditor->document()->setModified(false);
+ updateRowColLabel();
+}
+
+void ScriptEditorImplementation::getText(QString & szText)
+{
+ szText = m_pEditor->toPlainText();
+}
+
+void ScriptEditorImplementation::setFindText(const QString & szText)
+{
+ m_pFindLineEdit->setText(szText);
+ m_pEditor->slotFind();
+}
+
+void ScriptEditorImplementation::updateRowColLabel()
+{
+ if(m_lastCursorPos==m_pEditor->textCursor().position())
+ return;
+ int iRow = m_pEditor->textCursor().blockNumber();
+ int iCol = m_pEditor->textCursor().columnNumber();
+ QString szTmp;
+ KviQString::sprintf(szTmp,__tr2qs_ctx("Row: %d Col: %d","editor"),iRow,iCol);
+ m_pRowColLabel->setText(szTmp);
+ m_lastCursorPos = m_pEditor->textCursor().position();
+}
+
+void ScriptEditorImplementation::setCursorPosition(int iPos)
+{
+ QTextCursor cur = m_pEditor->textCursor();
+ cur.setPosition(iPos);
+ m_pEditor->setTextCursor(cur);
+ updateRowColLabel();
+}
+
+void ScriptEditorImplementation::loadFromFile()
+{
+ QString szFileName;
+ if(KviFileDialog::askForOpenFileName(szFileName,
+ __tr2qs_ctx("Load Script File - KVIrc","editor"),
+ QString::null,KVI_FILTER_SCRIPT,false,true))
+ {
+ QString szBuffer;
+ if(KviFileUtils::loadFile(szFileName,szBuffer))
+ {
+ m_pEditor->setPlainText(szBuffer);
+ setCursorPosition(0);
+ //m_pEditor->moveCursor(QTextEdit::MoveEnd,false);
+ //updateRowColLabel();
+ } else {
+ QString szTmp;
+ QMessageBox::warning(this,
+ __tr2qs_ctx("Open Failed - KVIrc","editor"),
+ KviQString::sprintf(szTmp,__tr2qs_ctx("Can't open the file %s for reading.","editor"),&szFileName));
+ }
+ }
+}
+
+void ScriptEditorImplementation::configureColors()
+{
+ if(!m_pOptionsDialog)
+ {
+ m_pOptionsDialog = new ScriptEditorWidgetColorOptions(this);
+ connect(m_pOptionsDialog,SIGNAL(finished(int)),this,SLOT(optionsDialogFinished(int)));
+ }
+ m_pOptionsDialog->show();
+}
+
+void ScriptEditorImplementation::optionsDialogFinished(int iResult)
+{
+ if(iResult == QDialog::Accepted)
+ {
+ m_pEditor->updateOptions();
+ saveOptions();
+ }
+}
+
+ScriptEditorReplaceDialog::ScriptEditorReplaceDialog(QWidget * pParent, const QString & szName)
+: QDialog(pParent)
+{
+ setObjectName(szName);
+
+ m_pParent = pParent;
+ emit initFind();
+ QPalette p = palette();
+ p.setColor(foregroundRole(),QColor( 0, 0, 0 ));
+ p.setColor(backgroundRole(),QColor( 236, 233, 216 ));
+ setPalette(p);
+
+ QGridLayout * pLayout = new QGridLayout(this);
+ pLayout->setObjectName("replace layout");
+
+ QLabel * m_pFindLabel = new QLabel(this);
+ m_pFindLabel->setObjectName("findlabel");
+ m_pFindLabel->setText(__tr2qs_ctx("Word to Find","editor"));
+ pLayout->addWidget(m_pFindLabel,0,0);
+
+ m_pFindLineEdit = new QLineEdit(this);
+ m_pFindLineEdit->setObjectName("findlineedit");
+ pLayout->addWidget(m_pFindLineEdit,0,1);
+
+ QLabel * m_pReplaceLabel = new QLabel(this);
+ m_pReplaceLabel->setObjectName("replacelabel");
+ m_pReplaceLabel->setText(__tr2qs_ctx("Replace with","editor"));
+ pLayout->addWidget(m_pReplaceLabel,1,0);
+
+ m_pReplaceLineEdit = new QLineEdit(this);
+ m_pReplaceLineEdit->setObjectName("replacelineedit");
+ pLayout->addWidget(m_pReplaceLineEdit,1,1);
+
+
+ m_pFindLineEdit->setFocus();
+
+ m_pCheckReplaceAll = new QCheckBox(this);
+ m_pCheckReplaceAll->setObjectName("replaceAll");
+ m_pCheckReplaceAll->setText(__tr2qs_ctx("&Replace in all editor's items","editor"));
+ pLayout->addWidget(m_pCheckReplaceAll,2,0);
+
+ QPushButton * pCancelButton = new QPushButton(this);
+ pCancelButton->setObjectName("cancelButton");
+ pCancelButton->setText(__tr2qs_ctx("&Cancel","editor"));
+ pLayout->addWidget(pCancelButton,3,0);
+
+ m_pReplaceButton = new QPushButton(this);
+ m_pReplaceButton->setObjectName("replacebutton");
+ m_pReplaceButton->setText(__tr2qs_ctx("&Replace","editor"));
+ m_pReplaceButton->setEnabled(false);
+ pLayout->addWidget(m_pReplaceButton,3,1);
+
+ setLayout(pLayout);
+
+ // signals and slots connections
+ connect(m_pReplaceButton, SIGNAL(clicked()), this, SLOT(slotReplace()));
+ connect(pCancelButton, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(m_pFindLineEdit, SIGNAL(textChanged(const QString &)), this, SLOT(textChanged(const QString &)));
+}
+
+ScriptEditorReplaceDialog::~ScriptEditorReplaceDialog()
+{
+}
+
+void ScriptEditorReplaceDialog::textChanged(const QString & szText)
+{
+ if(!szText.isEmpty())
+ m_pReplaceButton->setEnabled(true);
+ else
+ m_pReplaceButton->setEnabled(false);
+}
+
+void ScriptEditorReplaceDialog::slotReplace()
+{
+ QString szText = ((ScriptEditorWidget *)m_pParent)->toPlainText();
+ if(m_pCheckReplaceAll->isChecked())
+ emit replaceAll(m_pFindLineEdit->text(),m_pReplaceLineEdit->text());
+
+ szText.replace(m_pFindLineEdit->text(),m_pReplaceLineEdit->text(),Qt::CaseInsensitive);
+ ((ScriptEditorWidget *)m_pParent)->setText(szText);
+ ((ScriptEditorWidget *)m_pParent)->document()->setModified(true);
+ m_pFindLineEdit->setText("");
+ m_pReplaceLineEdit->setText("");
+ setTabOrder(m_pFindLineEdit,m_pReplaceLineEdit);
+}
+
+void ScriptEditorReplaceDialog::slotNextFind()
+{
+ emit nextFind(m_pFindLineEdit->text());
+}