Diffstat (limited to 'noncore/apps/tinykate/libkate/document') (more/less context) (show whitespace changes)
17 files changed, 8162 insertions, 0 deletions
diff --git a/noncore/apps/tinykate/libkate/document/katebuffer.cpp b/noncore/apps/tinykate/libkate/document/katebuffer.cpp new file mode 100644 index 0000000..22a4917 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katebuffer.cpp @@ -0,0 +1,179 @@ +/* + This file is part of KWrite + Copyright (c) 2000 Waldo Bastian <bastian@kde.org> + Copyright (c) 2002 Joseph Wenninger <jowenn@kde.org> + + $Id$ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + + +#include "katebuffer.h" + +// Includes for reading file +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> + +#include <qfile.h> +#include <qtextstream.h> + +#include <qtimer.h> +#include <qtextcodec.h> + +// + +#include <assert.h> +#include <kdebug.h> + +/** + * Create an empty buffer. + */ +KWBuffer::KWBuffer() +{ + clear(); +} + +void +KWBuffer::clear() +{ + m_stringListIt=0; + m_stringListCurrent=0; + m_stringList.clear(); + m_lineCount=1; + m_stringListIt = m_stringList.append(new TextLine()); +} + +/** + * Insert a file at line @p line in the buffer. + */ +void +KWBuffer::insertFile(int line, const QString &file, QTextCodec *codec) +{ + if (line) { + qDebug("insert File only supports insertion at line 0 == file opening"); + return; + } + clear(); + QFile iofile(file); + iofile.open(IO_ReadOnly); + QTextStream stream(&iofile); + stream.setCodec(codec); + QString qsl; + int count=0; + for (count=0;((qsl=stream.readLine())!=QString::null); count++) + { + if (count==0) + { + (*m_stringListIt)->append(qsl.unicode(),qsl.length()); + } + else + { + TextLine::Ptr tl=new TextLine(); + tl ->append(qsl.unicode(),qsl.length()); + m_stringListIt=m_stringList.append(tl); + } + } + if (count!=0) + { + m_stringListCurrent=count-1; + m_lineCount=count; + } +} + +void +KWBuffer::loadFilePart() +{ +} + + +void +KWBuffer::insertData(int line, const QByteArray &data, QTextCodec *codec) +{ +} + +void +KWBuffer::slotLoadFile() +{ + loadFilePart(); +// emit linesChanged(m_totalLines); + emit linesChanged(20); +} + +/** + * Return the total number of lines in the buffer. + */ +int +KWBuffer::count() +{ + qDebug("m_stringList.count %d",m_stringList.count()); + return m_lineCount; +// return m_stringList.count(); +// return m_totalLines; +} + + +void KWBuffer::seek(int i) +{ + if (m_stringListCurrent == i) + return; + while(m_stringListCurrent < i) + { + ++m_stringListCurrent; + ++m_stringListIt; + } + while(m_stringListCurrent > i) + { + --m_stringListCurrent; + --m_stringListIt; + } +} + + +TextLine::Ptr +KWBuffer::line(int i) +{ + if (i>=m_stringList.count()) return 0; + seek(i); + return *m_stringListIt; +} + +void +KWBuffer::insertLine(int i, TextLine::Ptr line) +{ + seek(i); + m_stringListIt = m_stringList.insert(m_stringListIt, line); + m_stringListCurrent = i; + m_lineCount++; +} + + +void +KWBuffer::removeLine(int i) +{ + seek(i); + m_stringListIt = m_stringList.remove(m_stringListIt); + m_stringListCurrent = i; + m_lineCount--; +} + +void +KWBuffer::changeLine(int i) +{ +} + diff --git a/noncore/apps/tinykate/libkate/document/katebuffer.h b/noncore/apps/tinykate/libkate/document/katebuffer.h new file mode 100644 index 0000000..9088498 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katebuffer.h @@ -0,0 +1,143 @@ +/* + This file is part of KWrite + Copyright (c) 2000 Waldo Bastian <bastian@kde.org> + Copyright (c) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License version 2 as published by the Free Software Foundation. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _KWBUFFER_H_ +#define _KWBUFFER_H_ + +#include <qstring.h> +#include <qstringlist.h> +#include <qlist.h> +#include <qobject.h> +#include <qtimer.h> + +#include "katetextline.h" + +class QTextCodec; + +/** + * The KWBuffer class maintains a collections of lines. + * It allows to maintain state information in a lazy way. + * It handles swapping out of data using secondary storage. + * + * It is designed to handle large amounts of text-data efficiently + * with respect to CPU and memory usage. + * + * @author Waldo Bastian <bastian@kde.org> + */ +class KWBuffer : public QObject +{ + Q_OBJECT +public: + /** + * Create an empty buffer. + */ + KWBuffer(); + + /** + * Insert a file at line @p line in the buffer. + * Using @p codec to decode the file. + */ + void insertFile(int line, const QString &file, QTextCodec *codec); + + /** + * Insert a block of data at line @p line in the buffer. + * Using @p codec to decode the file. + */ + void insertData(int line, const QByteArray &data, QTextCodec *codec); + + /** + * Return the total number of lines in the buffer. + */ + int count(); + + /** + * Return line @p i + */ + TextLine::Ptr line(int i); + + /** + * Insert @p line in front of line @p i + */ + void insertLine(int i, TextLine::Ptr line); + + /** + * Remove line @p i + */ + void removeLine(int i); + + /** + * Change line @p i + */ + void changeLine(int i); + + /** + * Clear the buffer. + */ + void clear(); + +signals: + + void textChanged(); + /** + * Emitted during loading. + */ + void linesChanged(int lines); + void needHighlight(long,long); + +protected: + /** + * Make sure @p buf gets loaded. + */ + void loadBlock(KWBufBlock *buf); + + /** + * Make sure @p buf gets parsed. + */ + void parseBlock(KWBufBlock *buf); + + /** + * Mark @p buf dirty. + */ + void dirtyBlock(KWBufBlock *buf); + + /** + * Find the block containing line @p i + */ + KWBufBlock *findBlock(int i); + + /** + * Load a part of the file that is currently loading. + */ + void loadFilePart(); + +protected slots: + void slotLoadFile(); + +protected: + TextLine::List m_stringList; + TextLine::List::Iterator m_stringListIt; + int m_stringListCurrent; + int m_lineCount; + void seek(int i); + + +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/document/katecmd.cpp b/noncore/apps/tinykate/libkate/document/katecmd.cpp new file mode 100644 index 0000000..beebaa2 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katecmd.cpp @@ -0,0 +1,58 @@ +/*************************************************************************** + katecmd.cpp - description + ------------------- + begin : Mon Feb 5 2001 + copyright : (C) 2001 by Christoph Cullmann + (C) 2002 by Joseph Wenninger + email : crossfire@babylon2k.de + jowenn@kde.org + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "katecmd.h" +#include "katecmds.h" + + +#include "katedocument.h" + +KateCmd::KateCmd (KateDocument *doc) : QObject (doc) +{ + myDoc = doc; + + myParser.append (new KateCommands::InsertTime (myDoc)); + myParser.append (new KateCommands::SedReplace (myDoc)); + myParser.append (new KateCommands::Character (myDoc)); +} + +KateCmd::~KateCmd () +{ +} + +void KateCmd::execCmd (QString cmd, KateView *view) +{ + for (uint i=0; i<myParser.count(); i++) + { + if (myParser.at(i)->execCmd (cmd, view)) + break; + } +} + +KateCmdParser::KateCmdParser (KateDocument *doc) +{ + myDoc = doc; +} + +KateCmdParser::~KateCmdParser() +{ +} + + diff --git a/noncore/apps/tinykate/libkate/document/katecmd.h b/noncore/apps/tinykate/libkate/document/katecmd.h new file mode 100644 index 0000000..72158cc --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katecmd.h @@ -0,0 +1,57 @@ +/*************************************************************************** + katecmd.h - description + ------------------- + begin : Mon Feb 5 2001 + copyright : (C) 2001 by Christoph Cullmann + (C) 2002 by Joseph Wenninger + email : crossfire@babylon2k.de + jowenn@kde.org + +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef _KATE_CMD_H +#define _KATE_CMD_H + +#include <qobject.h> +#include <qstring.h> +#include <qlist.h> +#include <katedocument.h> + +class KateCmdParser +{ + public: + KateCmdParser (KateDocument *doc=0L); + virtual ~KateCmdParser (); + + virtual bool execCmd (QString cmd=0L, KateView *view=0L)=0; + + private: + KateDocument *myDoc; +}; + +class KateCmd : public QObject +{ + Q_OBJECT + + public: + KateCmd (KateDocument *doc=0L); + ~KateCmd (); + + void execCmd (QString cmd=0L, KateView *view=0L); + + private: + KateDocument *myDoc; + QList<KateCmdParser> myParser; +}; + +#endif + diff --git a/noncore/apps/tinykate/libkate/document/katecmds.cpp b/noncore/apps/tinykate/libkate/document/katecmds.cpp new file mode 100644 index 0000000..3647853 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katecmds.cpp @@ -0,0 +1,278 @@ +/*************************************************************************** + katecmds.cpp - description + ------------------- + copyright : (C) 2001 by The Kate Team + (C) 2002 by Joseph Wenninger + email : kwrite-devel@kde.org + jowenn@kde.org + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "katecmds.h" +#include <qregexp.h> +#include <qregexp3.h> +#include <qdatetime.h> +#include "katedocument.h" +#include <kdebug.h> + +namespace KateCommands +{ + + +bool InsertTime::execCmd(QString cmd, KateView *view) +{ + if (cmd.left(5) == "time") + { + view->insertText(QTime::currentTime().toString()); + return true; + } + + return false; +} + +static void replace(QString &s, const QString &needle, const QString &with) +{ + int pos=0; + while (1) + { + pos=s.find(needle, pos); + if (pos==-1) break; + s.replace(pos, needle.length(), with); + pos+=with.length(); + } + +} + +// stolen from QString::replace +static void replace(QString &s, QRegExp3 &rx, const QString &with) +{ + if (s.isEmpty()) return; + int index = 0; + int slen = with.length(); + int len; + while (index < (int)s.length()) + { + index = rx.search(s, index); + len = rx.matchedLength(); + if ( index >= 0 ) + { + s.replace(index, len, with); + index += slen; + if (!len) + break; // Avoid infinite loop on 0-length matches, e.g. [a-z]* + } + else + break; + } +} + + + +static int backslashString(const QString &haystack, const QString &needle, int index) +{ + int len=haystack.length(); + int searchlen=needle.length(); + bool evenCount=true; + while (index<len) + { + if (haystack[index]=='\\') + { + evenCount=!evenCount; + } + else + { // isn't a slash + if (!evenCount) + { + if (haystack.mid(index, searchlen)==needle) + return index-1; + } + evenCount=true; + } + index++; + + } + + return -1; +} + + +// exchange "\t" for the actual tab character, for example +static void exchangeAbbrevs(QString &str) +{ + // the format is (findreplace)*[nullzero] + char *magic="a\x07t\t"; + + while (*magic) + { + int index=0; + char replace=magic[1]; + while ((index=backslashString(str, QChar(*magic), index))!=-1) + { + str.replace(index, 2, QChar(replace)); + index++; + } + magic++; + magic++; + } +} + +QString SedReplace::sedMagic(QString textLine, QString find, QString rep, bool noCase, bool repeat) +{ + QRegExp3 matcher(find, noCase); + + int start=0; + while (start!=-1) + { + start=matcher.search(textLine, start); + + if (start==-1) break; + + int length=matcher.matchedLength(); + + + // now set the backreferences in the replacement + QStringList backrefs=matcher.capturedTexts(); + int refnum=1; + + QStringList::Iterator i = backrefs.begin(); + ++i; + + for (; i!=backrefs.end(); ++i) + { + // I need to match "\\" or "", but not "\" + QString number=QString::number(refnum); + + int index=0; + while (index!=-1) + { + index=backslashString(rep, number, index); + if (index>=0) + { + rep.replace(index, 2, *i); + index+=(*i).length(); + } + } + + refnum++; + } + + textLine.replace(start, length, rep); + if (!repeat) break; + start+=rep.length(); + } + + replace(textLine, "\\\\", "\\"); + replace(textLine, "\\/", "/"); + + return textLine; +} + + +static void setLineText(KateView *view, int line, const QString &text) +{ +// view->doc()->removeLine(line); +// view->doc()->insertLine(text, line); + view->doc()->replaceLine(text,line); +} + +bool SedReplace::execCmd(QString cmd, KateView *view) +{ + kdDebug(13010)<<"SedReplace::execCmd()"<<endl; + if (QRegExp("[$%]?s/.+/.*/[ig]*").find(cmd, 0)==-1) + return false; + + bool fullFile=cmd[0]=='%'; + bool noCase=cmd[cmd.length()-1]=='i' || cmd[cmd.length()-2]=='i'; + bool repeat=cmd[cmd.length()-1]=='g' || cmd[cmd.length()-2]=='g'; + bool onlySelect=cmd[0]=='$'; + + QRegExp3 splitter("^[$%]?s/((?:[^\\\\/]|\\\\[\\\\/\\$0-9tadDsSwW])*)/((?:[^\\\\/]|\\\\[\\\\/\\$0-9tadDsSwW])*)/[ig]*$"); + if (splitter.search(cmd)<0) return false; + + QString find=splitter.cap(1); + kdDebug(13010)<< "SedReplace: find=" << find.latin1() <<endl; + + QString replace=splitter.cap(2); + exchangeAbbrevs(replace); + kdDebug(13010)<< "SedReplace: replace=" << replace.latin1() <<endl; + + + if (fullFile) + { + int numLines=view->doc()->numLines(); + for (int line=0; line < numLines; line++) + { + QString text=view->textLine(line); + text=sedMagic(text, find, replace, noCase, repeat); + setLineText(view, line, text); + } + } + else if (onlySelect) + { + // Not implemented + } + else + { // just this line + QString textLine=view->currentTextLine(); + int line=view->currentLine(); + textLine=sedMagic(textLine, find, replace, noCase, repeat); + setLineText(view, line, textLine); + } + return true; +} + +bool Character::execCmd(QString cmd, KateView *view) +{ + // hex, octal, base 9+1 + QRegExp3 num("^char: *(0?x[0-9A-Fa-f]{1,4}|0[0-7]{1,6}|[0-9]{1,3})$"); + if (num.search(cmd)==-1) return false; + + cmd=num.cap(1); + + // identify the base + + unsigned short int number=0; + int base=10; + if (cmd[0]=='x' || cmd.left(2)=="0x") + { + cmd.replace(QRegExp("^0?x"), ""); + base=16; + } + else if (cmd[0]=='0') + base=8; + bool ok; + number=cmd.toUShort(&ok, base); + if (!ok || number==0) return false; + if (number<=255) + { + char buf[2]; + buf[0]=(char)number; + buf[1]=0; + view->insertText(QString(buf)); + } + else + { // do the unicode thing + QChar c(number); + view->insertText(QString(&c, 1)); + } + + return true; +} + +bool Fifo::execCmd(QString cmd, KateView *view) +{ + +} + +} + +// vim: noet + diff --git a/noncore/apps/tinykate/libkate/document/katecmds.h b/noncore/apps/tinykate/libkate/document/katecmds.h new file mode 100644 index 0000000..bbd5937 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katecmds.h @@ -0,0 +1,94 @@ +/*************************************************************************** + katecmds.h - description + ------------------- + copyright : (C) 2001 by The Kate Team + (C) 2002 by Joseph Wenninger + email : kwrite-devel@kde.org + jowenn@kde.org + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef _KATECMDS_H +#define _KATECMDS_H + +#include "katecmd.h" + + +/** + * this namespace will be maintained by Charles Samuels <charles@kde.org> + * so we're going to be using this indentation style here. + * + * Respect my style, and I'll respect your's! + **/ +namespace KateCommands +{ + +/** + * This is by Christoph Cullmann + **/ +class InsertTime : public KateCmdParser +{ +public: + InsertTime(KateDocument *doc=0) : KateCmdParser(doc) { } + + bool execCmd(QString cmd=0, KateView *view=0); +}; + +/** + * -- Charles Samuels <charles@kde.org> + * Support vim/sed find and replace + * s/search/replace/ find search, replace with replace on this line + * %s/search/replace/ do the same to the whole file + * s/search/replace/i do the S. and R., but case insensitively + * $s/search/replace/ do the search are replacement to the selection only + * + * $s/// is currently unsupported + **/ +class SedReplace : public KateCmdParser +{ +public: + SedReplace(KateDocument *doc=0) : KateCmdParser(doc) { } + + bool execCmd(QString cmd=0, KateView *view=0); +private: + static QString sedMagic(QString textLine, QString find, QString replace, bool noCase, bool repeat); +}; + +/** + * insert a unicode or ascii character + * base 9+1: 1234 + * hex: 0x1234 or x1234 + * octal: 01231 + * + * prefixed with "char:" + **/ +class Character : public KateCmdParser +{ +public: + Character(KateDocument *doc=0) : KateCmdParser(doc) { } + + bool execCmd(QString cmd=0, KateView *view=0); +}; + +class Fifo : public KateCmdParser +{ +public: + Fifo(KateDocument *doc=0) : KateCmdParser(doc) { } + + bool execCmd(QString cmd=0, KateView *view=0); +}; + +} + +// vim: noet + +#endif + diff --git a/noncore/apps/tinykate/libkate/document/katedialogs.cpp b/noncore/apps/tinykate/libkate/document/katedialogs.cpp new file mode 100644 index 0000000..2f0ed7b --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katedialogs.cpp @@ -0,0 +1,588 @@ +/*************************************************************************** + katedialogs.cpp - description + ------------------- + copyright : (C) 2001 by The Kate Team + (C) 2002 by Joseph Wenninger + email : kwrite-devel@kde.org + jowenn@kde.org + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#include "katedialogs.h" +#include <klocale.h> +#include <kdebug.h> +#include <qgroupbox.h> +#include <qvgroupbox.h> +#include <qhgroupbox.h> +#include <qhbox.h> +#include <qvbox.h> +#include <qlayout.h> +#include <qpushbutton.h> +#include <qwidgetstack.h> +#include <qlabel.h> +#include <qlistview.h> +#include <qlineedit.h> +#include <qcombobox.h> +#include <qcheckbox.h> +//FIXME #include <kcharsets.h> +#include <kglobal.h> +#include <qmap.h> +#include <kmessagebox.h> +#include <kstddirs.h> + + +/******************************************************************************************************************* +* Context Editor * +*******************************************************************************************************************/ + +StyleChanger::StyleChanger( QWidget *parent ) + : QWidget(parent) +{ + QLabel *label; + + QGridLayout *glay = new QGridLayout( this, 4, 3, 0, KDialog::spacingHint() ); + CHECK_PTR(glay); + glay->addColSpacing( 1, KDialog::spacingHint() ); // Looks better + glay->setColStretch( 2, 10 ); + + col = new KColorButton(this); + CHECK_PTR(col); + connect(col,SIGNAL(changed(const QColor &)),this,SLOT(changed())); + label = new QLabel(col,i18n("Normal:"),this); + CHECK_PTR(label); + glay->addWidget(label,0,0); + glay->addWidget(col,1,0); + + selCol = new KColorButton(this); + CHECK_PTR(selCol); + connect(selCol,SIGNAL(changed(const QColor &)),this,SLOT(changed())); + label = new QLabel(selCol,i18n("Selected:"),this); + CHECK_PTR(label); + glay->addWidget(label,2,0); + glay->addWidget(selCol,3,0); + + bold = new QCheckBox(i18n("Bold"),this); + CHECK_PTR(bold); + connect(bold,SIGNAL(clicked()),SLOT(changed())); + glay->addWidget(bold,1,2); + + italic = new QCheckBox(i18n("Italic"),this); + CHECK_PTR(italic); + connect(italic,SIGNAL(clicked()),SLOT(changed())); + glay->addWidget(italic,2,2); +} + +void StyleChanger::setRef(ItemStyle *s) { + + style = s; + col->setColor(style->col); + selCol->setColor(style->selCol); + bold->setChecked(style->bold); + italic->setChecked(style->italic); + +} + +void StyleChanger::setEnabled(bool enable) { + + col->setEnabled(enable); + selCol->setEnabled(enable); + bold->setEnabled(enable); + italic->setEnabled(enable); +} + +void StyleChanger::changed() { + + if (style) { + style->col = col->color(); + style->selCol = selCol->color(); + style->bold = bold->isChecked(); + style->italic = italic->isChecked(); + } +} + +HighlightDialog::HighlightDialog( HlManager *hlManager, ItemStyleList *styleList, + HlDataList *highlightDataList, + int hlNumber, QWidget *parent, + const char *name, bool modal ) + :KDialogBase(parent,name,modal,i18n("Highlight Settings"), Ok|Cancel, Ok) +{ +// QVBox *page = makeVBoxMainWidget(); + QFrame *page=addPage("FIXME"); + (new QVBoxLayout(page))->setAutoAdd(true); + content=new HighlightDialogPage(hlManager,styleList,highlightDataList,hlNumber,page); +} + +void HighlightDialog::done(int r) +{ + kdDebug(13010)<<"HighlightDialod done"<<endl; + content->saveData(); + KDialogBase::done(r); +} + +HighlightDialogPage::HighlightDialogPage(HlManager *hlManager, ItemStyleList *styleList, + HlDataList* highlightDataList, + int hlNumber,QWidget *parent, const char *name) + :QTabWidget(parent,name),defaultItemStyleList(styleList),hlData(0L) + +{ + + // defaults ========================================================= + + QFrame *page1 = new QFrame(this); + addTab(page1,i18n("&Defaults")); + QGridLayout *grid = new QGridLayout(page1, 1, 1); + + QVGroupBox *dvbox1 = new QVGroupBox( i18n("Default Item Styles"), page1 ); + /*QLabel *label = */new QLabel( i18n("Item:"), dvbox1 ); + QComboBox *styleCombo = new QComboBox( false, dvbox1 ); + defaultStyleChanger = new StyleChanger( dvbox1 ); + for( int i = 0; i < hlManager->defaultStyles(); i++ ) { + styleCombo->insertItem(hlManager->defaultStyleName(i)); + } + connect(styleCombo, SIGNAL(activated(int)), this, SLOT(defaultChanged(int))); + grid->addWidget(dvbox1, 0,0); + + defaultChanged(0); + + // highlight modes ===================================================== + + QFrame *page2 = new QFrame(this); + addTab(page2,i18n("&Highlight Modes")); + //grid = new QGridLayout(page2,2,2); + QVBoxLayout *bl=new QVBoxLayout(page2); + bl->setAutoAdd(true); + QHGroupBox *hbox1 = new QHGroupBox( i18n("Config Select"), page2 ); + hbox1->layout()->setMargin(5); + QVBox *vbox1=new QVBox(hbox1); +// grid->addMultiCellWidget(vbox1,0,0,0,1); + QVGroupBox *vbox2 = new QVGroupBox( i18n("Item Style"), page2 ); +// grid->addWidget(vbox2,1,0); + QVGroupBox *vbox3 = new QVGroupBox( i18n("Highlight Auto Select"), hbox1 ); + //grid->addWidget(vbox3,1,1); + + QLabel *label = new QLabel( i18n("Highlight:"), vbox1 ); + hlCombo = new QComboBox( false, vbox1 ); + QHBox *modHl = new QHBox(vbox1); +// connect(new QPushButton(i18n("New"),modHl),SIGNAL(clicked()),this,SLOT(hlNew())); +// connect(new QPushButton(i18n("Edit"),modHl),SIGNAL(clicked()),this,SLOT(hlEdit())); + connect( hlCombo, SIGNAL(activated(int)), + this, SLOT(hlChanged(int)) ); + for( int i = 0; i < hlManager->highlights(); i++) { + hlCombo->insertItem(hlManager->hlName(i)); + } + hlCombo->setCurrentItem(hlNumber); + + + label = new QLabel( i18n("Item:"), vbox2 ); + itemCombo = new QComboBox( false, vbox2 ); + connect( itemCombo, SIGNAL(activated(int)), this, SLOT(itemChanged(int)) ); + + label = new QLabel( i18n("File Extensions:"), vbox3 ); + wildcards = new QLineEdit( vbox3 ); + label = new QLabel( i18n("Mime Types:"), vbox3 ); + mimetypes = new QLineEdit( vbox3 ); + + + styleDefault = new QCheckBox(i18n("Default"), vbox2 ); + connect(styleDefault,SIGNAL(clicked()),SLOT(changed())); + styleChanger = new StyleChanger( vbox2 ); + + hlDataList = highlightDataList; + hlChanged(hlNumber); +} + + +void HighlightDialogPage::defaultChanged(int z) +{ + defaultStyleChanger->setRef(defaultItemStyleList->at(z)); +} + + +void HighlightDialogPage::hlChanged(int z) +{ + writeback(); + + hlData = hlDataList->at(z); + + wildcards->setText(hlData->wildcards); + mimetypes->setText(hlData->mimetypes); + + itemCombo->clear(); + for (ItemData *itemData = hlData->itemDataList.first(); itemData != 0L; + itemData = hlData->itemDataList.next()) { + kdDebug(13010) << itemData->name << endl; + itemCombo->insertItem(i18n(itemData->name.latin1())); + } + + itemChanged(0); +} + +void HighlightDialogPage::itemChanged(int z) +{ + itemData = hlData->itemDataList.at(z); + + styleDefault->setChecked(itemData->defStyle); + styleChanger->setRef(itemData); +} + +void HighlightDialogPage::changed() +{ + itemData->defStyle = styleDefault->isChecked(); +} + +void HighlightDialogPage::writeback() { + if (hlData) { + hlData->wildcards = wildcards->text(); + hlData->mimetypes = mimetypes->text(); + } +} + +void HighlightDialogPage::saveData() { + kdDebug(13010)<<"HighlightDialogPage::saveData()"<<endl; + writeback(); +} + + +void HighlightDialogPage::hlEdit() { + HlEditDialog diag(0,0,"hlEdit", true,hlData); + diag.show(); +} + +void HighlightDialogPage::hlNew() { + HlEditDialog diag(0,0,"hlEdit",true,0); + diag.show(); +} + + +HlEditDialog::HlEditDialog(HlManager *,QWidget *parent, const char *name, bool modal,HlData *data) + :KDialogBase(KDialogBase::Swallow, i18n("Highlight Conditions"), Ok|Cancel, Ok, parent, name, modal) +{ + currentItem=0; + transTableCnt=0; + QHBox *wid=new QHBox(this); + QVBox *lbox=new QVBox(wid); + contextList=new KListView(lbox); + contextList->setRootIsDecorated(true); + contextList->addColumn(i18n("Syntax structure")); + contextList->setSorting(-1); + QHBox *bbox=new QHBox(lbox); + QPushButton *addContext=new QPushButton(i18n("New Context"),bbox); + QPushButton *addItem=new QPushButton(i18n("New Item"),bbox); + QVGroupBox *opt = new QVGroupBox( i18n("Options"), wid); + stack=new QWidgetStack(opt); + initContextOptions(contextOptions=new QVBox(stack)); + stack->addWidget(contextOptions,HlEContext); + initItemOptions(itemOptions=new QVBox(stack)); + stack->addWidget(itemOptions,HlEItem); + stack->raiseWidget(HlEContext); + setMainWidget(wid); + if (data!=0) loadFromDocument(data); + else newDocument(); + connect(contextList,SIGNAL(currentChanged( QListViewItem*)),this,SLOT(currentSelectionChanged ( QListViewItem * ))); + connect(addContext,SIGNAL(clicked()),this,SLOT(contextAddNew())); + connect(addItem,SIGNAL(clicked()),this,SLOT(ItemAddNew())); + } + +void HlEditDialog::newDocument() +{ + KStandardDirs *dirs = KGlobal::dirs(); + QStringList list=dirs->findAllResources("data","kate/syntax/syntax.template",false,true); + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + { + HlData data("","",*it); + loadFromDocument(&data); + return; + } + KMessageBox::error(this,i18n("Can't find template file")); +} + + +void HlEditDialog::initContextOptions(QVBox *co) +{ + if( co!=0) + { + QHBox *tmp = new QHBox(co); + (void) new QLabel(i18n("Description:"),tmp); + ContextDescr=new QLineEdit(tmp); + tmp= new QHBox(co); + (void) new QLabel(i18n("Attribute:"),tmp); + ContextAttribute=new QComboBox(tmp); + tmp= new QHBox(co); + (void) new QLabel(i18n("LineEnd:"),tmp); + ContextLineEnd = new QComboBox(tmp); + connect(ContextDescr,SIGNAL(textChanged(const QString&)),this,SLOT(contextDescrChanged(const QString&))); + connect(ContextLineEnd,SIGNAL(activated(int)),this,SLOT(contextLineEndChanged(int))); + connect(ContextAttribute,SIGNAL(activated(int)),this,SLOT(contextAttributeChanged(int))); + } + else + kdDebug(13010)<<"initContextOptions: Widget is 0"<<endl; +} + + +void HlEditDialog::insertTranslationList(QString tag, QString trans,int length) + { + ItemInfo data(trans,length); + id2tag.insert(transTableCnt,tag); + id2info.insert(transTableCnt,data); + tag2id.insert(tag,transTableCnt); + transTableCnt++; + } + + +void HlEditDialog::initItemOptions(QVBox *co) +{ + if (co!=0) + { + QHBox *tmp = new QHBox(co); + (void) new QLabel(i18n("Type:"),tmp); + ItemType = new QComboBox(tmp); + tmp= new QHBox(co); + (void) new QLabel(i18n("Parameter:"),tmp); + ItemParameter= new QLineEdit(tmp); + tmp= new QHBox(co); + (void) new QLabel(i18n("Attribute:"),tmp); + ItemAttribute= new QComboBox(tmp); + (void) new QLabel(i18n("Context switch:"),tmp); + ItemContext = new QComboBox(tmp); + co->setSpacing(15); + QPushButton *delItem=new QPushButton(i18n("Delete this item"),co); + + /* init translation lists */ + insertTranslationList("CharDetect","CharDetect",1); + insertTranslationList("2CharDetect","2CharDetect",2); + insertTranslationList("RangeDetect","RangeDetect",2); + insertTranslationList("StringDetect","StringDetect",-1); + insertTranslationList("AnyChar","AnyChar",-1); + insertTranslationList("RegExpr","RegExpr",-1); + insertTranslationList("Int","Int",0); + insertTranslationList("Float","Float",0); + insertTranslationList("keyword","keyword",0); + insertTranslationList("dataType","dataType",0); + ItemType->clear(); + for (int i=0; i<transTableCnt; i++) ItemType->insertItem(id2info[i].trans_i18n); + connect(ItemType,SIGNAL(activated(int)),this,SLOT(ItemTypeChanged(int))); + connect(ItemParameter,SIGNAL(textChanged(const QString&)),this,SLOT(ItemParameterChanged(const QString&))); + connect(ItemAttribute,SIGNAL(activated(int)),this,SLOT(ItemAttributeChanged(int))); + connect(ItemContext,SIGNAL(activated(int)),this,SLOT(ItemContextChanged(int))); + } + else + kdDebug(13010)<<"initItemOptions: Widget is 0"<<endl; +} + +void HlEditDialog::loadFromDocument(HlData *hl) +{ + struct syntaxContextData *data; + QListViewItem *last=0,*lastsub=0; + + HlManager::self()->syntax->setIdentifier(hl->identifier); + data=HlManager::self()->syntax->getGroupInfo("highlighting","context"); + int i=0; + if (data) + { + while (HlManager::self()->syntax->nextGroup(data)) //<context tags> + { + kdDebug(13010)<< "Adding context to list"<<endl; + last= new QListViewItem(contextList,last, + HlManager::self()->syntax->groupData(data,QString("name")), + QString("%1").arg(i), + HlManager::self()->syntax->groupData(data,QString("attribute")), + HlManager::self()->syntax->groupData(data,QString("lineEndContext"))); + i++; + lastsub=0; + while (HlManager::self()->syntax->nextItem(data)) + { + kdDebug(13010)<< "Adding item to list"<<endl; + lastsub=addContextItem(last,lastsub,data); + } + + + } + if (data) HlManager::self()->syntax->freeGroupInfo(data); + } + ContextAttribute->clear(); + ItemAttribute->clear(); + data=HlManager::self()->syntax->getGroupInfo("highlighting","itemData"); + while (HlManager::self()->syntax->nextGroup(data)) + { + ContextAttribute->insertItem(HlManager::self()->syntax->groupData(data,QString("name"))); + ItemAttribute->insertItem(HlManager::self()->syntax->groupData(data,QString("name"))); + } + if (data) HlManager::self()->syntax->freeGroupInfo(data); +} + +QListViewItem *HlEditDialog::addContextItem(QListViewItem *_parent,QListViewItem *prev,struct syntaxContextData *data) + { + + kdDebug(13010)<<HlManager::self()->syntax->groupItemData(data,QString("name")) << endl; + + QString dataname=HlManager::self()->syntax->groupItemData(data,QString("")); + QString attr=(HlManager::self()->syntax->groupItemData(data,QString("attribute"))); + QString context=(HlManager::self()->syntax->groupItemData(data,QString("context"))); + char chr; + if (! HlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty()) + chr= (HlManager::self()->syntax->groupItemData(data,QString("char")).latin1())[0]; + else + chr=0; + QString stringdata=HlManager::self()->syntax->groupItemData(data,QString("String")); + char chr1; + if (! HlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty()) + chr1= (HlManager::self()->syntax->groupItemData(data,QString("char1")).latin1())[0]; + else + chr1=0; + bool insensitive=(HlManager::self()->syntax->groupItemData(data,QString("insensitive"))==QString("TRUE")); + QString param(""); + if ((dataname=="keyword") || (dataname=="dataType")) param=dataname; + else if (dataname=="CharDetect") param=chr; + else if ((dataname=="2CharDetect") || (dataname=="RangeDetect")) param=QString("%1%2").arg(chr).arg(chr1); + else if ((dataname=="StringDetect") || (dataname=="AnyChar") || (dataname=="RegExpr")) param=stringdata; + else kdDebug(13010)<<"***********************************"<<endl<<"Unknown entry for Context:"<<dataname<<endl; + kdDebug(13010)<<dataname << endl; + return new QListViewItem(_parent,prev,i18n(dataname.latin1())+" "+param,dataname,param,attr,context); + } + + +void HlEditDialog::currentSelectionChanged ( QListViewItem *it) + { + kdDebug(13010)<<"Update data view"<<endl<<"Depth:"<<it->depth()<<endl; + currentItem=it; + if (it->depth()==0) showContext(); + else showItem(); + } + + +/****************************************************************************/ +/* CONTEXTS */ +/****************************************************************************/ + + +void HlEditDialog::showContext() + { + stack->raiseWidget(HlEContext); + ContextDescr->setText(currentItem->text(0)); + ContextAttribute->setCurrentItem(currentItem->text(2).toInt()); + ContextLineEnd->clear(); + for (QListViewItem *it=contextList->firstChild();it;it=it->nextSibling()) + ContextLineEnd->insertItem(it->text(0)); + ContextLineEnd->setCurrentItem(currentItem->text(3).toInt()); +// ContextAttribute->setText(currentItem->text(1)); +// ContextLineEnd->setText(currentItem->text(2)); + } + +void HlEditDialog::contextDescrChanged(const QString& name) + { + if (currentItem) + { + currentItem->setText(0,name); + ContextLineEnd->changeItem(name,currentItem->text(3).toInt()); + } + } + +void HlEditDialog::contextAttributeChanged(int id) +{ + if (currentItem) + { + currentItem->setText(2,QString("%1").arg(id)); + } +} + +void HlEditDialog::contextLineEndChanged(int id) +{ + kdDebug(13010)<<"contextLineEndChanged"<<endl; + if (currentItem) + { + currentItem->setText(3,QString("%1").arg(id)); + } +} + +void HlEditDialog::contextAddNew() +{ + QListViewItem *it=contextList->firstChild(); + for (;it->nextSibling()!=0;it=it->nextSibling()); + it=new QListViewItem(contextList,it,i18n("New Context"),QString("%1").arg(it->text(1).toInt()),"0","0"); + contextList->setSelected(it,true); +} + +/****************************************************************************/ +/* ITEMS */ +/****************************************************************************/ + +void HlEditDialog::showItem() + { + stack->raiseWidget(HlEItem); + ItemContext->clear(); + for (QListViewItem *it=contextList->firstChild();it;it=it->nextSibling()) + ItemContext->insertItem(it->text(0)); + ItemContext->setCurrentItem(currentItem->text(4).toInt()); + ItemAttribute->setCurrentItem(currentItem->text(3).toInt()); + QMap<QString,int>::Iterator iter=tag2id.find(currentItem->text(1)); + if (iter==tag2id.end()) + kdDebug(13010)<<"Oops, unknown itemtype in showItem: "<<currentItem->text(1)<<endl; + else + { + ItemType->setCurrentItem(*iter); + if (id2info[*iter].length==0) ItemParameter->hide(); + else + { + ItemParameter->setMaxLength(id2info[*iter].length); + ItemParameter->show(); + ItemParameter->setText(currentItem->text(2)); + } + } + + } + +void HlEditDialog::ItemTypeChanged(int id) +{ + if (currentItem) + { + currentItem->setText(1,id2tag[id]); + ItemParameter->setMaxLength(id2info[id].length); + ItemParameterChanged(ItemParameter->text()); + } +} + +void HlEditDialog::ItemParameterChanged(const QString& name) +{ + if (currentItem) + { + currentItem->setText(2,name); + currentItem->setText(0,id2info[ItemType->currentItem()].trans_i18n+" "+currentItem->text(2)); + } +} + +void HlEditDialog::ItemAttributeChanged(int attr) +{ + if (currentItem) + { + currentItem->setText(3,QString("%1").arg(attr)); + } +} + +void HlEditDialog::ItemContextChanged(int cont) +{ + if (currentItem) + { + currentItem->setText(4,QString("%1").arg(cont)); + } +} + +void HlEditDialog::ItemAddNew() +{ + QListViewItem *it; + if (currentItem) + { + if (currentItem->depth()==0) it=currentItem->firstChild(); + else + it=currentItem; + if (it) for (;it->nextSibling();it=it->nextSibling()); + (void) new QListViewItem(it ? it->parent() : currentItem,it,"StringDetect "+i18n("New Item"),"StringDetect",i18n("New Item"),0,it ? it->parent()->text(1) : currentItem->text(1)); + } +} diff --git a/noncore/apps/tinykate/libkate/document/katedialogs.h b/noncore/apps/tinykate/libkate/document/katedialogs.h new file mode 100644 index 0000000..f37f45a --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katedialogs.h @@ -0,0 +1,160 @@ +/*************************************************************************** + katedialogs.h - description + ------------------- + copyright : (C) 2001 by The Kate Team + (C) 2002 by Joseph Wenninger + email : kwrite-devel@kde.org + jowenn@kde.org + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef KATEDIALOGS_H +#define KATEDIALOGS_H +#include <kdialog.h> +#include <kdialogbase.h> +#include "katesyntaxdocument.h" +#include "katehighlight.h" +#include <klistview.h> +#include <qtabwidget.h> +#include <kcolorbutton.h> + +class QWidgetStack; +class QVBox; +class KListView; +class QListViewItem; +struct syntaxContextData; +class QCheckBox; +//class ItemFont; +#define HlEUnknown 0 +#define HlEContext 1 +#define HlEItem 2 + //-------- + + +class StyleChanger : public QWidget { + Q_OBJECT + public: + StyleChanger(QWidget *parent ); + void setRef(ItemStyle *); + void setEnabled(bool); + protected slots: + void changed(); + protected: + ItemStyle *style; + KColorButton *col; + KColorButton *selCol; + QCheckBox *bold; + QCheckBox *italic; +}; + +class HighlightDialogPage : public QTabWidget +{ + Q_OBJECT + public: + HighlightDialogPage(HlManager *, ItemStyleList *, HlDataList *, int hlNumber, + QWidget *parent=0, const char *name=0); + void saveData(); + + protected slots: + void defaultChanged(int); + + void hlChanged(int); + void itemChanged(int); + void changed(); + void hlEdit(); + void hlNew(); + protected: + StyleChanger *defaultStyleChanger; + ItemStyleList *defaultItemStyleList; + + void writeback(); + QComboBox *itemCombo, *hlCombo; + QLineEdit *wildcards; + QLineEdit *mimetypes; + QCheckBox *styleDefault; + StyleChanger *styleChanger; + + HlDataList *hlDataList; + HlData *hlData; + ItemData *itemData; +}; + +class ItemInfo +{ + public: + ItemInfo():trans_i18n(),length(0){}; + ItemInfo(QString _trans,int _length):trans_i18n(_trans),length(_length){}; + QString trans_i18n; + int length; +}; + +class HighlightDialog : public KDialogBase +{ + Q_OBJECT + public: + HighlightDialog( HlManager *hlManager, ItemStyleList *styleList, + HlDataList *highlightDataList, + int hlNumber, QWidget *parent, + const char *name=0, bool modal=true ); + private: + HighlightDialogPage *content; + protected: + virtual void done(int r); +}; + +class HlEditDialog : public KDialogBase +{ + Q_OBJECT + public: + HlEditDialog(HlManager *,QWidget *parent=0, const char *name=0, bool modal=true, HlData *data=0); + private: + class QWidgetStack *stack; + class QVBox *contextOptions, *itemOptions; + class KListView *contextList; + class QListViewItem *currentItem; + void initContextOptions(class QVBox *co); + void initItemOptions(class QVBox *co); + void loadFromDocument(HlData *hl); + void showContext(); + void showItem(); + + QListViewItem *addContextItem(QListViewItem *_parent,QListViewItem *prev,struct syntaxContextData *data); + void insertTranslationList(QString tag, QString trans,int length); + void newDocument(); + + class QLineEdit *ContextDescr; + class QComboBox *ContextAttribute; + class QComboBox *ContextLineEnd; + + class QComboBox *ItemType; + class QComboBox *ItemContext; + class QLineEdit *ItemParameter; + class QComboBox *ItemAttribute; + + class QMap<int,QString> id2tag; + class QMap<int,ItemInfo> id2info; + class QMap<QString,int> tag2id; + int transTableCnt; + protected slots: + void currentSelectionChanged ( QListViewItem * ); + void contextDescrChanged(const QString&); + void contextLineEndChanged(int); + void contextAttributeChanged(int); + void contextAddNew(); + + void ItemTypeChanged(int id); + void ItemParameterChanged(const QString& name); + void ItemAttributeChanged(int attr); + void ItemContextChanged(int cont); + void ItemAddNew(); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/document/katedocument.cpp b/noncore/apps/tinykate/libkate/document/katedocument.cpp new file mode 100644 index 0000000..0d84bcf --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katedocument.cpp @@ -0,0 +1,3169 @@ +/*************************************************************************** + katedocument.cpp - description + ------------------- + begin : Mon Jan 15 2001 + copyright : (C) 2001 by Christoph "Crossfire" Cullmann + (C) 2002 by Joseph Wenninger + email : crossfire@babylon2k.de + jowenn@kde.org + +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/* + Copyright (C) 1998, 1999 Jochen Wilhelmy + digisnap@cs.tu-berlin.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "katedocument.h" + + +#include <qfileinfo.h> +#include <qdatetime.h> + +#include <kmessagebox.h> +#include <klocale.h> +#include <qpe/config.h> +#include <qstring.h> + +#include <sys/time.h> +#include <unistd.h> + +#include <stdio.h> + +#include <qtimer.h> +#include <qobject.h> +#include <qapplication.h> +#include <qclipboard.h> +#include <qfont.h> +#include <qpainter.h> +#include <qfile.h> +#include <qtextstream.h> +#include <qtextcodec.h> +#include <kglobal.h> + +#include <klocale.h> +//#include <kcharsets.h> +#include <kdebug.h> +//#include <kinstance.h> + +#include <kglobalsettings.h> +//#include <kaction.h> +//#include <kstdaction.h> + +#include "../view/kateview.h" +#include "katebuffer.h" +#include "katetextline.h" + +#include "katecmd.h" + +KateAction::KateAction(Action a, PointStruc &cursor, int len, const QString &text) + : action(a), cursor(cursor), len(len), text(text) { +} + +KateActionGroup::KateActionGroup(PointStruc &aStart, int type) + : start(aStart), action(0L), undoType(type) { +} + +KateActionGroup::~KateActionGroup() { + KateAction *current, *next; + + current = action; + while (current) { + next = current->next; + delete current; + current = next; + } +} + +void KateActionGroup::insertAction(KateAction *a) { + a->next = action; + action = a; +} + +const char * KateActionGroup::typeName(int type) +{ + // return a short text description of the given undo group type suitable for a menu + // not the lack of i18n's, the caller is expected to handle translation + switch (type) { + case ugPaste : return "Paste Text"; + case ugDelBlock : return "Selection Overwrite"; + case ugIndent : return "Indent"; + case ugUnindent : return "Unindent"; + case ugComment : return "Comment"; + case ugUncomment : return "Uncomment"; + case ugReplace : return "Text Replace"; + case ugSpell : return "Spell Check"; + case ugInsChar : return "Typing"; + case ugDelChar : return "Delete Text"; + case ugInsLine : return "New Line"; + case ugDelLine : return "Delete Line"; + } + return ""; +} + +const int KateDocument::maxAttribs = 32; + +QStringList KateDocument::searchForList = QStringList(); +QStringList KateDocument::replaceWithList = QStringList(); + +uint KateDocument::uniqueID = 0; + +QPtrDict<KateDocument::KateDocPrivate>* KateDocument::d_ptr = 0; + + +KateDocument::KateDocument(bool bSingleViewMode, bool bBrowserView, + QWidget *parentWidget, const char *widgetName, + QObject *, const char *) + : Kate::Document (), + myFont(KGlobalSettings::generalFont()), myFontBold(KGlobalSettings::generalFont()), myFontItalic(KGlobalSettings::generalFont()), myFontBI(KGlobalSettings::generalFont()), + myFontMetrics (myFont), myFontMetricsBold (myFontBold), myFontMetricsItalic (myFontItalic), myFontMetricsBI (myFontBI), + hlManager(HlManager::self ()) +{ + + d(this)->hlSetByUser = false; + PreHighlightedTill=0; + RequestPreHighlightTill=0; + + m_bSingleViewMode=bSingleViewMode; + m_bBrowserView = bBrowserView; + + m_url = QString::null; + + // NOTE: QFont::CharSet doesn't provide all the charsets KDE supports + // (esp. it doesn't distinguish between UTF-8 and iso10646-1) + + myEncoding = QString::fromLatin1(QTextCodec::codecForLocale()->name()); + + maxLength = -1; + + setFont (KGlobalSettings::generalFont()); + + myDocID = uniqueID; + uniqueID++; + + myDocName = QString (""); + fileInfo = new QFileInfo (); + + myCmd = new KateCmd (this); + + connect(this,SIGNAL(modifiedChanged ()),this,SLOT(slotModChanged ())); + + buffer = new KWBuffer; + connect(buffer, SIGNAL(linesChanged(int)), this, SLOT(slotBufferChanged())); +// connect(buffer, SIGNAL(textChanged()), this, SIGNAL(textChanged())); + connect(buffer, SIGNAL(needHighlight(long,long)),this,SLOT(slotBufferHighlight(long,long))); + + colors[0] = KGlobalSettings::baseColor(); + colors[1] = KGlobalSettings::highlightColor(); + + m_attribs = new Attribute[maxAttribs]; + + m_highlight = 0L; + tabChars = 8; + + m_singleSelection = false; + + newDocGeometry = false; + readOnly = false; + newDoc = false; + + modified = false; + + undoList.setAutoDelete(true); + undoState = 0; + undoSteps = 50; + + pseudoModal = 0L; + clear(); + + setHighlight(0); //calls updateFontData() + // if the user changes the highlight with the dialog, notify the doc + connect(hlManager,SIGNAL(changed()),SLOT(hlChanged())); + + newDocGeometry = false; + + readConfig(); + + setReadOnly(false); +} + +void KateDocument::setDontChangeHlOnSave() +{ + d(this)->hlSetByUser = true; +} + +void KateDocument::setFont (QFont font) +{ + kdDebug()<<"Kate:: setFont"<<endl; + int oldwidth=myFontMetrics.width('W'); //Quick & Dirty Hack (by JoWenn) //Remove in KDE 3.0 + myFont = font; + myFontBold = QFont (font); + myFontBold.setBold (true); + + myFontItalic = QFont (font); + myFontItalic.setItalic (true); + + myFontBI = QFont (font); + myFontBI.setBold (true); + myFontBI.setItalic (true); + + myFontMetrics = CachedFontMetrics (myFont); + myFontMetricsBold = CachedFontMetrics (myFontBold); + myFontMetricsItalic = CachedFontMetrics (myFontItalic); + myFontMetricsBI = CachedFontMetrics (myFontBI); + int newwidth=myFontMetrics.width('W'); //Quick & Dirty Hack (by JoWenn) //Remove in KDE 3.0 + maxLength=maxLength*(float)newwidth/(float)oldwidth; //Quick & Dirty Hack (by JoWenn) //Remove in KDE 3.0 + + updateFontData(); + updateViews(); //Quick & Dirty Hack (by JoWenn) //Remove in KDE 3.0 + +} + +long KateDocument::needPreHighlight(long till) +{ + int max=numLines()-1; + if (till>max) + { + till=max; + } + if (PreHighlightedTill>=till) return -1; + + long tmp=RequestPreHighlightTill; + if (RequestPreHighlightTill<till) + { + RequestPreHighlightTill=till; + if (tmp<=PreHighlightedTill) QTimer::singleShot(10,this,SLOT(doPreHighlight())); + } + return RequestPreHighlightTill; +} + +void KateDocument::doPreHighlight() +{ + int from = PreHighlightedTill; + int till = PreHighlightedTill+200; + int max = numLines()-1; + if (till > max) + { + till = max; + } + PreHighlightedTill = till; + updateLines(from,till); + emit preHighlightChanged(PreHighlightedTill); + if (PreHighlightedTill<RequestPreHighlightTill) + QTimer::singleShot(10,this,SLOT(doPreHighlight())); +} + +KateDocument::~KateDocument() +{ + m_highlight->release(); + + if ( !m_bSingleViewMode ) + { + m_views.setAutoDelete( true ); + m_views.clear(); + m_views.setAutoDelete( false ); + } + delete_d(this); +} + +void KateDocument::openURL(const QString &filename) +{ + + m_file=filename; + fileInfo->setFile (m_file); + setMTime(); + + if (!fileInfo->exists() || !fileInfo->isReadable()) + { + qDebug("File doesn't exit or couldn't be read"); + return false; + } + + buffer->clear(); +#warning fixme +// buffer->insertFile(0, m_file, KGlobal::charsets()->codecForName(myEncoding)); + qDebug("Telling buffer to open file"); + buffer->insertFile(0, m_file, QTextCodec::codecForLocale()); + + setMTime(); + + if (myWordWrap) + wrapText (myWordWrapAt); + + int hl = hlManager->wildcardFind( m_file ); + + setHighlight(hl); + + updateLines(); + updateViews(); + + emit fileNameChanged(); + + return true; +} + +bool KateDocument::saveFile() +{ + QFile f( m_file ); + if ( !f.open( IO_WriteOnly ) ) + return false; // Error + + QTextStream stream(&f); + + stream.setEncoding(QTextStream::RawUnicode); // disable Unicode headers +#warning fixme +// stream.setCodec(KGlobal::charsets()->codecForName(myEncoding)); + stream.setCodec(QTextCodec::codecForLocale()); // this line sets the mapper to the correct codec + + int maxLine = numLines(); + int line = 0; + while(true) + { + stream << getTextLine(line)->getString(); + line++; + if (line >= maxLine) break; + + if (eolMode == KateDocument::eolUnix) stream << "\n"; + else if (eolMode == KateDocument::eolDos) stream << "\r\n"; + else if (eolMode == KateDocument::eolMacintosh) stream << '\r'; + }; + f.close(); + + fileInfo->setFile (m_file); + setMTime(); + + if (!(d(this)->hlSetByUser)) + { + int hl = hlManager->wildcardFind( m_file ); + + setHighlight(hl); + } + emit fileNameChanged (); + + return (f.status() == IO_Ok); +} + +KTextEditor::View *KateDocument::createView( QWidget *parent, const char *name ) +{ + return new KateView( this, parent, name); +} + +QString KateDocument::textLine( int line ) const +{ + TextLine::Ptr l = getTextLine( line ); + if ( !l ) + return QString(); + + return l->getString(); +} + +void KateDocument::replaceLine(const QString& s,int line) +{ + remove_Line(line,false); + insert_Line(s,line,true); +} + +void KateDocument::insertLine( const QString &str, int l ) { + insert_Line(str,l,true); +} + +void KateDocument::insert_Line(const QString& s,int line, bool update) +{ + kdDebug(13020)<<"KateDocument::insertLine "<<s<<QString(" %1").arg(line)<<endl; + TextLine::Ptr TL=new TextLine(); + TL->append(s.unicode(),s.length()); + buffer->insertLine(line,TL); + if (update) + { + newDocGeometry=true; + updateLines(line); + updateViews(); + } +} + +void KateDocument::insertAt( const QString &s, int line, int col, bool ) +{ + VConfig c; + c.view = 0; // ### FIXME + c.cursor.x = col; + c.cursor.y = line; + c.cXPos = 0; // ### FIXME + c.flags = 0; // ### FIXME + insert( c, s ); +} + +void KateDocument::removeLine( int line ) { + remove_Line(line,true); +} + +void KateDocument::remove_Line(int line,bool update) +{ + kdDebug(13020)<<"KateDocument::removeLine "<<QString("%1").arg(line)<<endl; + buffer->removeLine(line); +// newDocGeometry=true; +// if line==0) + if (update) + { + updateLines(line); + updateViews(); + } +} + +int KateDocument::length() const +{ + return text().length(); +} + +void KateDocument::setSelection( int , int , int , int ) +{ +} + +bool KateDocument::hasSelection() const +{ + return (selectEnd >= selectStart); +} + +QString KateDocument::selection() const +{ + uint flags = 0; + TextLine::Ptr textLine; + int len, z, start, end, i; + + len = 1; + if (!(flags & KateView::cfVerticalSelect)) { + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + len += textLine->numSelected(); + if (textLine->isSelected()) len++; + } + QString s; + len = 0; + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + end = 0; + do { + start = textLine->findUnselected(end); + end = textLine->findSelected(start); + for (i = start; i < end; i++) { + s[len] = textLine->getChar(i); + len++; + } + } while (start < end); + if (textLine->isSelected()) { + s[len] = '\n'; + len++; + } + } +// s[len] = '\0'; + return s; + } else { + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + len += textLine->numSelected() + 1; + } + QString s; + len = 0; + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + end = 0; + do { + start = textLine->findUnselected(end); + end = textLine->findSelected(start); + for (i = start; i < end; i++) { + s[len] = textLine->getChar(i); + len++; + } + } while (start < end); + s[len] = '\n'; + len++; + } +// s[len] = '\0'; // the final \0 is not counted in length() + return s; + } +} + +int KateDocument::numLines() const +{ + return buffer->count(); +} + + +TextLine::Ptr KateDocument::getTextLine(int line) const +{ + // This is a hack to get this stuff working. + return buffer->line(line); +} + +int KateDocument::textLength(int line) { + TextLine::Ptr textLine = getTextLine(line); + if (!textLine) return 0; + return textLine->length(); +} + +void KateDocument::setTabWidth(int chars) { + if (tabChars == chars) return; + if (chars < 1) chars = 1; + if (chars > 16) chars = 16; + tabChars = chars; + updateFontData(); + + maxLength = -1; + for (int i=0; i < buffer->count(); i++) + { + TextLine::Ptr textLine = buffer->line(i); + int len = textWidth(textLine,textLine->length()); + if (len > maxLength) { + maxLength = len; + longestLine = textLine; + } + } +} + +void KateDocument::setReadOnly(bool m) { + KTextEditor::View *view; + + if (m != readOnly) { + readOnly = m; +// if (readOnly) recordReset(); + for (view = m_views.first(); view != 0L; view = m_views.next() ) { + emit static_cast<KateView *>( view )->newStatus(); + } + } +} + +bool KateDocument::isReadOnly() const { + return readOnly; +} + +void KateDocument::setNewDoc( bool m ) +{ +// KTextEditor::View *view; + + if ( m != newDoc ) + { + newDoc = m; +//// if (readOnly) recordReset(); +// for (view = m_views.first(); view != 0L; view = m_views.next() ) { +// emit static_cast<KateView *>( view )->newStatus(); +// } + } +} + +bool KateDocument::isNewDoc() const { + return newDoc; +} + +void KateDocument::setModified(bool m) { + KTextEditor::View *view; + + if (m != modified) { + modified = m; + for (view = m_views.first(); view != 0L; view = m_views.next() ) { + emit static_cast<KateView *>( view )->newStatus(); + } + emit modifiedChanged (); + } +} + +bool KateDocument::isModified() const { + return modified; +} + +void KateDocument::readConfig() +{ + KConfig *config = KGlobal::config(); + config->setGroup("Kate Document"); + + myWordWrap = config->readBoolEntry("Word Wrap On", false); + myWordWrapAt = config->readNumEntry("Word Wrap At", 80); + if (myWordWrap) + wrapText (myWordWrapAt); + + setTabWidth(config->readNumEntry("TabWidth", 8)); + setUndoSteps(config->readNumEntry("UndoSteps", 50)); + m_singleSelection = config->readBoolEntry("SingleSelection", false); + myEncoding = config->readEntry("Encoding", QString::fromLatin1(QTextCodec::codecForLocale()->name())); + setFont (config->readFontEntry("Font", &myFont)); + + colors[0] = config->readColorEntry("Color Background", &colors[0]); + colors[1] = config->readColorEntry("Color Selected", &colors[1]); + + config->sync(); +} + +void KateDocument::writeConfig() +{ + KConfig *config = KGlobal::config(); + config->setGroup("Kate Document"); +#if 0 + cofig->writeEntry("Word Wrap On", myWordWrap); + config->writeEntry("Word Wrap At", myWordWrapAt); + config->writeEntry("TabWidth", tabChars); + config->writeEntry("UndoSteps", undoSteps); + config->writeEntry("SingleSelection", m_singleSelection); + config->writeEntry("Encoding", myEncoding); + config->writeEntry("Font", myFont); + config->writeEntry("Color Background", colors[0]); + config->writeEntry("Color Selected", colors[1]); +#endif + config->sync(); +} + +void KateDocument::readSessionConfig(KConfig *config) +{ + m_url = config->readEntry("URL"); // ### doesn't this break the encoding? (Simon) + setHighlight(hlManager->nameFind(config->readEntry("Highlight"))); + // anders: restore bookmarks if possible + QValueList<int> l = config->readIntListEntry("Bookmarks"); + if ( l.count() ) { + for (uint i=0; i < l.count(); i++) { + if ( numLines() < l[i] ) break; + getTextLine( l[i] )->addMark( Bookmark ); + } + } +} + +void KateDocument::writeSessionConfig(KConfig *config) +{ +#if 0 + config->writeEntry("URL", m_url); // ### encoding?? (Simon) + config->writeEntry("Highlight", m_highlight->name()); + // anders: save bookmarks + QList<Kate::Mark> l = marks(); + QValueList<int> ml; + for (uint i=0; i < l.count(); i++) { + if ( l.at(i)->type == 1) // only save bookmarks + ml << l.at(i)->line; + } + if ( ml.count() ) + config->writeEntry("Bookmarks", ml); +#endif +} + + +void KateDocument::setHighlight(int n) { + Highlight *h; + +// hlNumber = n; + + h = hlManager->getHl(n); + if (h == m_highlight) { + updateLines(); + } else { + if (m_highlight != 0L) m_highlight->release(); + h->use(); + m_highlight = h; + makeAttribs(); + } + PreHighlightedTill=0; + RequestPreHighlightTill=0; + emit(highlightChanged()); +} + +void KateDocument::makeAttribs() { + qDebug("KateDocument::makeAttribs()"); + m_numAttribs = hlManager->makeAttribs(m_highlight, m_attribs, maxAttribs); + updateFontData(); + updateLines(); +} + +void KateDocument::updateFontData() { + int maxAscent, maxDescent; + int tabWidth; + KateView *view; + + maxAscent = myFontMetrics.ascent(); + maxDescent = myFontMetrics.descent(); + tabWidth = myFontMetrics.width(' '); + + fontHeight = maxAscent + maxDescent + 1; + fontAscent = maxAscent; + m_tabWidth = tabChars*tabWidth; + + for (view = views.first(); view != 0L; view = views.next() ) { + view->myViewInternal->drawBuffer->resize(view->width(),fontHeight); + view->tagAll(); + view->updateCursor(); + } +} + +void KateDocument::hlChanged() { //slot + makeAttribs(); + updateViews(); +} + + +void KateDocument::addView(KTextEditor::View *view) { + views.append( static_cast<KateView *>( view ) ); + KTextEditor::Document::addView( view ); + connect( static_cast<KateView *>( view ), SIGNAL( destroyed() ), this, SLOT( slotViewDestroyed() ) ); +} + +void KateDocument::removeView(KTextEditor::View *view) { +// if (undoView == view) recordReset(); + disconnect( static_cast<KateView *>( view ), SIGNAL( destroyed() ), this, SLOT( slotViewDestroyed() ) ); + views.removeRef( static_cast<KateView *>( view ) ); + KTextEditor::Document::removeView( view ); +} + +void KateDocument::slotViewDestroyed() +{ + views.removeRef( static_cast<const KateView *>( sender() ) ); +} + +bool KateDocument::ownedView(KateView *view) { + // do we own the given view? + return (views.containsRef(view) > 0); +} + +bool KateDocument::isLastView(int numViews) { + return ((int) views.count() == numViews); +} + +int KateDocument::textWidth(const TextLine::Ptr &textLine, int cursorX) { + int x; + int z; + QChar ch; + Attribute *a; + + x = 0; + for (z = 0; z < cursorX; z++) { + ch = textLine->getChar(z); + a = &m_attribs[textLine->getAttr(z)]; + + if (ch == '\t') + x += m_tabWidth - (x % m_tabWidth); + else if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + } + return x; +} + +int KateDocument::textWidth(PointStruc &cursor) { + if (cursor.x < 0) + cursor.x = 0; + if (cursor.y < 0) + cursor.y = 0; + if (cursor.y >= numLines()) + cursor.y = lastLine(); + return textWidth(getTextLine(cursor.y),cursor.x); +} + +int KateDocument::textWidth(bool wrapCursor, PointStruc &cursor, int xPos) { + int len; + int x, oldX; + int z; + QChar ch; + Attribute *a; + + if (cursor.y < 0) cursor.y = 0; + if (cursor.y > lastLine()) cursor.y = lastLine(); + TextLine::Ptr textLine = getTextLine(cursor.y); + len = textLine->length(); + + x = oldX = z = 0; + while (x < xPos && (!wrapCursor || z < len)) { + oldX = x; + ch = textLine->getChar(z); + a = &m_attribs[textLine->getAttr(z)]; + + if (ch == '\t') + x += m_tabWidth - (x % m_tabWidth); + else if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + + z++; + } + if (xPos - oldX < x - xPos && z > 0) { + z--; + x = oldX; + } + cursor.x = z; + return x; +} + + +int KateDocument::textPos(const TextLine::Ptr &textLine, int xPos) { + int x, oldX; + int z; + QChar ch; + Attribute *a; + + x = oldX = z = 0; + while (x < xPos) { // && z < len) { + oldX = x; + ch = textLine->getChar(z); + a = &m_attribs[textLine->getAttr(z)]; + + if (ch == '\t') + x += m_tabWidth - (x % m_tabWidth); + else if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + + z++; + } + if (xPos - oldX < x - xPos && z > 0) { + z--; + // newXPos = oldX; + }// else newXPos = x; + return z; +} + +int KateDocument::textWidth() { + return int(maxLength + 8); +} + +int KateDocument::textHeight() { + return numLines()*fontHeight; +} + +void KateDocument::insert(VConfig &c, const QString &s) { + int pos; + QChar ch; + QString buf; + + if (s.isEmpty()) return; + + recordStart(c, KateActionGroup::ugPaste); + + pos = 0; + if (!(c.flags & KateView::cfVerticalSelect)) { + do { + ch = s[pos]; + if (ch.isPrint() || ch == '\t') { + buf += ch; // append char to buffer + } else if (ch == '\n') { + recordAction(KateAction::newLine, c.cursor); // wrap contents behind cursor to new line + recordInsert(c, buf); // append to old line +// c.cursor.x += buf.length(); + buf.truncate(0); // clear buffer + c.cursor.y++; + c.cursor.x = 0; + } + pos++; + } while (pos < (int) s.length()); + } else { + int xPos; + + xPos = textWidth(c.cursor); + do { + ch = s[pos]; + if (ch.isPrint() || ch == '\t') { + buf += ch; + } else if (ch == '\n') { + recordInsert(c, buf); + c.cursor.x += buf.length(); + buf.truncate(0); + c.cursor.y++; + if (c.cursor.y >= numLines()) + recordAction(KateAction::insLine, c.cursor); + c.cursor.x = textPos(getTextLine(c.cursor.y), xPos); + } + pos++; + } while (pos < (int) s.length()); + } + recordInsert(c, buf); + c.cursor.x += buf.length(); + recordEnd(c); +} + +void KateDocument::insertFile(VConfig &c, QIODevice &dev) +{ + recordStart(c, KateActionGroup::ugPaste); + + QString buf; + QChar ch, last; + + QTextStream stream( &dev ); + + while ( !stream.atEnd() ) { + stream >> ch; + + if (ch.isPrint() || ch == '\t') { + buf += ch; + } else if (ch == '\n' || ch == '\r') { + if (last != '\r' || ch != '\n') { + recordAction(KateAction::newLine, c.cursor); + recordInsert(c, buf); + buf.truncate(0); + c.cursor.y++; + c.cursor.x = 0; + } + last = ch; + } + } + + recordInsert(c, buf); + recordEnd(c); +} + +int KateDocument::currentColumn(PointStruc &cursor) { + return getTextLine(cursor.y)->cursorX(cursor.x,tabChars); +} + +bool KateDocument::insertChars(VConfig &c, const QString &chars) { + int z, pos, l; + bool onlySpaces; + QChar ch; + QString buf; + + TextLine::Ptr textLine = getTextLine(c.cursor.y); + + pos = 0; + onlySpaces = true; + for (z = 0; z < (int) chars.length(); z++) { + ch = chars[z]; + if (ch == '\t' && c.flags & KateView::cfReplaceTabs) { + l = tabChars - (textLine->cursorX(c.cursor.x, tabChars) % tabChars); + while (l > 0) { + buf.insert(pos, ' '); + pos++; + l--; + } + } else if (ch.isPrint() || ch == '\t') { + buf.insert(pos, ch); + pos++; + if (ch != ' ') onlySpaces = false; + if (c.flags & KateView::cfAutoBrackets) { + if (ch == '(') buf.insert(pos, ')'); + if (ch == '[') buf.insert(pos, ']'); + if (ch == '{') buf.insert(pos, '}'); + } + } + } + //pos = cursor increment + + //return false if nothing has to be inserted + if (buf.isEmpty()) return false; + + //auto deletion of the marked text occurs not very often and can therefore + // be recorded separately + if (c.flags &KateView:: cfDelOnInput) delMarkedText(c); + + recordStart(c, KateActionGroup::ugInsChar); + recordReplace(c/*.cursor*/, (c.flags & KateView::cfOvr) ? buf.length() : 0, buf); + c.cursor.x += pos; + + if (myWordWrap && myWordWrapAt > 0) { + int line; + const QChar *s; +// int pos; + PointStruc actionCursor; + + line = c.cursor.y; + do { + textLine = getTextLine(line); + s = textLine->getText(); + l = textLine->length(); + for (z = myWordWrapAt; z < l; z++) if (!s[z].isSpace()) break; //search for text to wrap + if (z >= l) break; // nothing more to wrap + pos = myWordWrapAt; + for (; z >= 0; z--) { //find wrap position + if (s[z].isSpace()) { + pos = z + 1; + break; + } + } + //pos = wrap position + + if (line == c.cursor.y && pos <= c.cursor.x) { + //wrap cursor + c.cursor.y++; + c.cursor.x -= pos; + } + + if (line == lastLine() || (getTextLine(line+1)->length() == 0) ) { + //at end of doc: create new line + actionCursor.x = pos; + actionCursor.y = line; + recordAction(KateAction::newLine,actionCursor); + } else { + //wrap + actionCursor.y = line + 1; + if (!s[l - 1].isSpace()) { //add space in next line if necessary + actionCursor.x = 0; + recordInsert(actionCursor, " "); + } + actionCursor.x = textLine->length() - pos; + recordAction(KateAction::wordWrap, actionCursor); + } + line++; + } while (true); + } + recordEnd(c); + return true; +} + +QString tabString(int pos, int tabChars) { + QString s; + while (pos >= tabChars) { + s += '\t'; + pos -= tabChars; + } + while (pos > 0) { + s += ' '; + pos--; + } + return s; +} + +void KateDocument::newLine(VConfig &c) { + + //auto deletion of marked text is done by the view to have a more + // "low level" KateDocument::newLine method + recordStart(c, KateActionGroup::ugInsLine); + + if (!(c.flags & KateView::cfAutoIndent)) { + recordAction(KateAction::newLine,c.cursor); + c.cursor.y++; + c.cursor.x = 0; + } else { + TextLine::Ptr textLine = getTextLine(c.cursor.y); + int pos = textLine->firstChar(); + if (c.cursor.x < pos) c.cursor.x = pos; // place cursor on first char if before + + int y = c.cursor.y; + while ((y > 0) && (pos < 0)) { // search a not empty text line + textLine = getTextLine(--y); + pos = textLine->firstChar(); + } + recordAction(KateAction::newLine, c.cursor); + c.cursor.y++; + c.cursor.x = 0; + if (pos > 0) { + pos = textLine->cursorX(pos, tabChars); +// if (getTextLine(c.cursor.y)->length() > 0) { + QString s = tabString(pos, (c.flags & KateView::cfSpaceIndent) ? 0xffffff : tabChars); + recordInsert(c.cursor, s); + pos = s.length(); +// } +// recordInsert(c.cursor, QString(textLine->getText(), pos)); + c.cursor.x = pos; + } + } + + recordEnd(c); +} + +void KateDocument::killLine(VConfig &c) { + + recordStart(c, KateActionGroup::ugDelLine); + c.cursor.x = 0; + recordDelete(c.cursor, 0xffffff); + if (c.cursor.y < lastLine()) { + recordAction(KateAction::killLine, c.cursor); + } + recordEnd(c); +} + +void KateDocument::backspace(VConfig &c) { + + if (c.cursor.x <= 0 && c.cursor.y <= 0) return; + + if (c.cursor.x > 0) { + recordStart(c, KateActionGroup::ugDelChar); + if (!(c.flags & KateView::cfBackspaceIndents)) { + // ordinary backspace + c.cursor.x--; + recordDelete(c.cursor, 1); + } else { + // backspace indents: erase to next indent position + int l = 1; // del one char + + TextLine::Ptr textLine = getTextLine(c.cursor.y); + int pos = textLine->firstChar(); + if (pos < 0 || pos >= c.cursor.x) { + // only spaces on left side of cursor + // search a line with less spaces + int y = c.cursor.y; + while (y > 0) { + textLine = getTextLine(--y); + pos = textLine->firstChar(); + if (pos >= 0 && pos < c.cursor.x) { + l = c.cursor.x - pos; // del more chars + break; + } + } + } + // break effectively jumps here + c.cursor.x -= l; + recordDelete(c.cursor, l); + } + } else { + // c.cursor.x == 0: wrap to previous line + recordStart(c, KateActionGroup::ugDelLine); + c.cursor.y--; + c.cursor.x = getTextLine(c.cursor.y)->length(); + recordAction(KateAction::delLine,c.cursor); + } + recordEnd(c); +} + + +void KateDocument::del(VConfig &c) { + TextLine::Ptr textLine = getTextLine(c.cursor.y); + int len = (c.flags & KateView::cfRemoveSpaces) ? textLine->lastChar() : textLine->length(); + if (c.cursor.x < len/*getTextLine(c.cursor.y)->length()*/) { + // delete one character + recordStart(c, KateActionGroup::ugDelChar); + recordDelete(c.cursor, 1); + recordEnd(c); + } else { + if (c.cursor.y < lastLine()) { + // wrap next line to this line + textLine->truncate(c.cursor.x); // truncate spaces + recordStart(c, KateActionGroup::ugDelLine); + recordAction(KateAction::delLine,c.cursor); + recordEnd(c); + } + } +} + +void KateDocument::clear() { + PointStruc cursor; + KateView *view; + + setPseudoModal(0L); + cursor.x = cursor.y = 0; + for (view = views.first(); view != 0L; view = views.next() ) { + view->updateCursor(cursor); + view->tagAll(); + } + + eolMode = KateDocument::eolUnix; + + buffer->clear(); + longestLine = buffer->line(0); + + maxLength = 0; + + select.x = -1; + + selectStart = 0xffffff; + selectEnd = 0; + oldMarkState = false; + + setModified(false); + + undoList.clear(); + currentUndo = 0; + newUndo(); +} + +void KateDocument::cut(VConfig &c) { + + if (selectEnd < selectStart) return; + + copy(c.flags); + delMarkedText(c); +} + +void KateDocument::copy(int flags) { + + if (selectEnd < selectStart) return; + + QString s = markedText(flags); + if (!s.isEmpty()) { +//#if defined(_WS_X11_) + if (m_singleSelection) + disconnect(QApplication::clipboard(), SIGNAL(dataChanged()), this, 0); +//#endif + QApplication::clipboard()->setText(s); +//#if defined(_WS_X11_) + if (m_singleSelection) { + connect(QApplication::clipboard(), SIGNAL(dataChanged()), + this, SLOT(clipboardChanged())); + } +//#endif + } +} + +void KateDocument::paste(VConfig &c) { + QString s = QApplication::clipboard()->text(); + if (!s.isEmpty()) { + insert(c, s); + } +} + +void KateDocument::toggleRect(int start, int end, int x1, int x2) { + int z, line; + bool t; + + if (x1 > x2) { + z = x1; + x1 = x2; + x2 = z; + } + if (start > end) { + z = start; + start = end; + end = z; + } + + t = false; + for (line = start; line < end; line++) { + int x, oldX, s, e, newX1, newX2; + QChar ch; + Attribute *a; + + TextLine::Ptr textLine = getTextLine(line); + + //--- speed optimization + //s = textPos(textLine, x1, newX1); + x = oldX = z = 0; + while (x < x1) { // && z < len) { + oldX = x; + ch = textLine->getChar(z); + a = &m_attribs[textLine->getAttr(z)]; + + if (ch == '\t') + x += m_tabWidth - (x % m_tabWidth); + else if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + + z++; + } + s = z; + if (x1 - oldX < x - x1 && z > 0) { + s--; + newX1 = oldX; + } else newX1 = x; + //e = textPos(textLine, x2, newX2); + while (x < x2) { // && z < len) { + oldX = x; + ch = textLine->getChar(z); + a = &m_attribs[textLine->getAttr(z)]; + + if (ch == '\t') + x += m_tabWidth - (x % m_tabWidth); + else if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + + z++; + } + e = z; + if (x2 - oldX < x - x2 && z > 0) { + e--; + newX2 = oldX; + } else newX2 = x; + //--- + + if (e > s) { + textLine->toggleSelect(s, e); + tagLineRange(line, newX1, newX2); + t = true; + } + } + if (t) { + end--; +// tagLines(start, end); + + if (start < selectStart) selectStart = start; + if (end > selectEnd) selectEnd = end; + emit selectionChanged(); + } +} + +void KateDocument::selectTo(VConfig &c, PointStruc &cursor, int cXPos) { + //c.cursor = old cursor position + //cursor = new cursor position + + if (c.cursor.x != select.x || c.cursor.y != select.y) { + //new selection + + if (!(c.flags & KateView::cfKeepSelection)) deselectAll(); +// else recordReset(); + + anchor = c.cursor; + aXPos = c.cXPos; + } + + if (!(c.flags & KateView::cfVerticalSelect)) { + //horizontal selections + int x, y, sXPos; + int ex, ey, eXPos; + bool sel; + + if (cursor.y > c.cursor.y || (cursor.y == c.cursor.y && cursor.x > c.cursor.x)) { + x = c.cursor.x; + y = c.cursor.y; + sXPos = c.cXPos; + ex = cursor.x; + ey = cursor.y; + eXPos = cXPos; + sel = true; + } else { + x = cursor.x; + y = cursor.y; + sXPos = cXPos; + ex = c.cursor.x; + ey = c.cursor.y; + eXPos = c.cXPos; + sel = false; + } + +// tagLines(y, ye); + if (y < ey) { + //tagLineRange(y, sXPos, 0xffffff); + tagLines(y, ey -1); + tagLineRange(ey, 0, eXPos); + } else tagLineRange(y, sXPos, eXPos); + + if (y < selectStart) selectStart = y; + if (ey > selectEnd) selectEnd = ey; + + TextLine::Ptr textLine = getTextLine(y); + + if (c.flags & KateView::cfXorSelect) { + //xor selection with old selection + while (y < ey) { + textLine->toggleSelectEol(x); + x = 0; + y++; + textLine = getTextLine(y); + } + textLine->toggleSelect(x, ex); + } else { + //set selection over old selection + + if (anchor.y > y || (anchor.y == y && anchor.x > x)) { + if (anchor.y < ey || (anchor.y == ey && anchor.x < ex)) { + sel = !sel; + while (y < anchor.y) { + textLine->selectEol(sel, x); + x = 0; + y++; + textLine = getTextLine(y); + } + textLine->select(sel, x, anchor.x); + x = anchor.x; + } + sel = !sel; + } + while (y < ey) { + textLine->selectEol(sel, x); + x = 0; + y++; + textLine = getTextLine(y); + } + textLine->select(sel, x, ex); + } + } else { + //vertical (block) selections +// int ax, sx, ex; + +// ax = textWidth(anchor); +// sx = textWidth(start); +// ex = textWidth(end); + + toggleRect(c.cursor.y + 1, cursor.y + 1, aXPos, c.cXPos); + toggleRect(anchor.y, cursor.y + 1, c.cXPos, cXPos); + } + select = cursor; + optimizeSelection(); + emit selectionChanged(); +} + + +void KateDocument::selectAll() { + int z; + TextLine::Ptr textLine; + + select.x = -1; + +// if (selectStart != 0 || selectEnd != lastLine()) recordReset(); + + selectStart = 0; + selectEnd = lastLine(); + + tagLines(selectStart,selectEnd); + + for (z = selectStart; z < selectEnd; z++) { + textLine = getTextLine(z); + textLine->selectEol(true,0); + } + textLine = getTextLine(z); + textLine->select(true,0,textLine->length()); + emit selectionChanged(); +} + +void KateDocument::deselectAll() { + select.x = -1; + if (selectEnd < selectStart) return; + +// recordReset(); + + tagLines(selectStart,selectEnd); + + for (int z = selectStart; z <= selectEnd; z++) { + TextLine::Ptr textLine = getTextLine(z); + textLine->selectEol(false,0); + } + selectStart = 0xffffff; + selectEnd = 0; + emit selectionChanged(); +} + +void KateDocument::invertSelection() { + TextLine::Ptr textLine; + + select.x = -1; + +// if (selectStart != 0 || selectEnd != lastLine()) recordReset(); + + selectStart = 0; + selectEnd = lastLine(); + + tagLines(selectStart,selectEnd); + + for (int z = selectStart; z < selectEnd; z++) { + textLine = getTextLine(z); + textLine->toggleSelectEol(0); + } + textLine = getTextLine(selectEnd); + textLine->toggleSelect(0,textLine->length()); + optimizeSelection(); + emit selectionChanged(); +} + +void KateDocument::selectWord(PointStruc &cursor, int flags) { + int start, end, len; + + TextLine::Ptr textLine = getTextLine(cursor.y); + len = textLine->length(); + start = end = cursor.x; + while (start > 0 && m_highlight->isInWord(textLine->getChar(start - 1))) start--; + while (end < len && m_highlight->isInWord(textLine->getChar(end))) end++; + if (end <= start) return; + if (!(flags & KateView::cfKeepSelection)) deselectAll(); +// else recordReset(); + + textLine->select(true, start, end); + + anchor.x = start; + select.x = end; + anchor.y = select.y = cursor.y; + tagLines(cursor.y, cursor.y); + if (cursor.y < selectStart) selectStart = cursor.y; + if (cursor.y > selectEnd) selectEnd = cursor.y; + emit selectionChanged(); +} + +void KateDocument::selectLength(PointStruc &cursor, int length, int flags) { + int start, end; + + TextLine::Ptr textLine = getTextLine(cursor.y); + start = cursor.x; + end = start + length; + if (end <= start) return; + if (!(flags & KateView::cfKeepSelection)) deselectAll(); + + textLine->select(true, start, end); + + anchor.x = start; + select.x = end; + anchor.y = select.y = cursor.y; + tagLines(cursor.y, cursor.y); + if (cursor.y < selectStart) selectStart = cursor.y; + if (cursor.y > selectEnd) selectEnd = cursor.y; + emit selectionChanged(); +} + +void KateDocument::doIndent(VConfig &c, int change) { + + c.cursor.x = 0; + + recordStart(c, (change < 0) ? KateActionGroup::ugUnindent + : KateActionGroup::ugIndent); + + if (selectEnd < selectStart) { + // single line + optimizeLeadingSpace(c.cursor.y, c.flags, change); + } else { + // entire selection + TextLine::Ptr textLine; + int line, z; + QChar ch; + + if (c.flags & KateView::cfKeepIndentProfile && change < 0) { + // unindent so that the existing indent profile doesn´t get screwed + // if any line we may unindent is already full left, don't do anything + for (line = selectStart; line <= selectEnd; line++) { + textLine = getTextLine(line); + if (textLine->isSelected() || textLine->numSelected()) { + for (z = 0; z < tabChars; z++) { + ch = textLine->getChar(z); + if (ch == '\t') break; + if (ch != ' ') { + change = 0; + goto jumpOut; + } + } + } + } + jumpOut:; + } + + for (line = selectStart; line <= selectEnd; line++) { + textLine = getTextLine(line); + if (textLine->isSelected() || textLine->numSelected()) { + optimizeLeadingSpace(line, c.flags, change); + } + } + } + // recordEnd now removes empty undo records + recordEnd(c.view, c.cursor, c.flags | KateView::cfPersistent); +} + +/* + Optimize the leading whitespace for a single line. + If change is > 0, it adds indentation units (tabChars) + if change is == 0, it only optimizes + If change is < 0, it removes indentation units + This will be used to indent, unindent, and optimal-fill a line. + If excess space is removed depends on the flag cfKeepExtraSpaces + which has to be set by the user +*/ +void KateDocument::optimizeLeadingSpace(int line, int flags, int change) { + int len; + int chars, space, okLen; + QChar ch; + int extra; + QString s; + PointStruc cursor; + + TextLine::Ptr textLine = getTextLine(line); + len = textLine->length(); + space = 0; // length of space at the beginning of the textline + okLen = 0; // length of space which does not have to be replaced + for (chars = 0; chars < len; chars++) { + ch = textLine->getChar(chars); + if (ch == ' ') { + space++; + if (flags & KateView::cfSpaceIndent && okLen == chars) okLen++; + } else if (ch == '\t') { + space += tabChars - space % tabChars; + if (!(flags & KateView::cfSpaceIndent) && okLen == chars) okLen++; + } else break; + } + + space += change*tabChars; // modify space width + // if line contains only spaces it will be cleared + if (space < 0 || chars == len) space = 0; + + extra = space % tabChars; // extra spaces which don´t fit the indentation pattern + if (flags & KateView::cfKeepExtraSpaces) chars -= extra; + + if (flags & KateView::cfSpaceIndent) { + space -= extra; + ch = ' '; + } else { + space /= tabChars; + ch = '\t'; + } + + // don´t replace chars which are already ok + cursor.x = QMIN(okLen, QMIN(chars, space)); + chars -= cursor.x; + space -= cursor.x; + if (chars == 0 && space == 0) return; //nothing to do + + s.fill(ch, space); + +//printf("chars %d insert %d cursor.x %d\n", chars, insert, cursor.x); + cursor.y = line; + recordReplace(cursor, chars, s); +} + +void KateDocument::doComment(VConfig &c, int change) +{ + c.flags |=KateView:: cfPersistent; + + recordStart(c, (change < 0) ? KateActionGroup::ugUncomment + : KateActionGroup::ugComment); + + QString startComment = m_highlight->getCommentStart(); + QString startLineComment = m_highlight->getCommentSingleLineStart(); + QString endComment = m_highlight->getCommentEnd(); + + int startCommentLen = startComment.length(); + int startLineCommentLen = startLineComment.length(); + int endCommentLen = endComment.length(); + + if (change > 0) + { + if ( !hasMarkedText() ) + { + if (startLineComment != "") + { + // Add a start comment mark + c.cursor.x = 0; + recordReplace(c.cursor, 0, startLineComment); + } + else if ((startComment != "") && (endComment != "")) + { + // Add a start comment mark + c.cursor.x = 0; + recordReplace(c.cursor, 0, startComment); + + // Add an end comment mark + TextLine* textline = getTextLine(c.cursor.y); + c.cursor.x = textline->length(); + recordReplace(c.cursor, 0, endComment); + c.cursor.x = 0; + } + } + else if ((startComment != "") && (endComment != "")) + { + QString marked (c.view->markedText ()); + int preDeleteLine = -1, preDeleteCol = -1; + c.view->getCursorPosition (&preDeleteLine, &preDeleteCol); + + if (marked.length() > 0) + c.view->keyDelete (); + + int line = -1, col = -1; + c.view->getCursorPosition (&line, &col); + + c.view->insertText (startComment + marked + endComment); + } + } + else + { + if ( !hasMarkedText() ) + { + TextLine* textline = getTextLine(c.cursor.y); + + if(textline->startingWith(startLineComment)) + { + // Remove start comment mark + c.cursor.x = 0; + recordReplace(c.cursor, startLineCommentLen, ""); + } + else if (textline->startingWith(startComment) && textline->endingWith(endComment)) + { + // Remove start comment mark + c.cursor.x = 0; + recordReplace(c.cursor, startCommentLen, ""); + + // Remove end comment mark + if(endComment != "") + { + c.cursor.x = textline->length() - endCommentLen; + recordReplace(c.cursor, endCommentLen, ""); + c.cursor.x = 0; + } + } + } + else + { + QString marked (c.view->markedText ()); + int preDeleteLine = -1, preDeleteCol = -1; + c.view->getCursorPosition (&preDeleteLine, &preDeleteCol); + + int start = marked.find (startComment); + int end = marked.findRev (endComment); + + if ((start > -1) && (end > -1)) + { + marked.remove (start, startCommentLen); + marked.remove (end-startCommentLen, endCommentLen); + + c.view->keyDelete (); + + int line = -1, col = -1; + c.view->getCursorPosition (&line, &col); + c.view->insertText (marked); + } + } + } + + recordEnd(c.view, c.cursor, c.flags | KateView::cfPersistent); +} + + +QString KateDocument::text() const +{ + QString s; + + for (int i=0; i < buffer->count(); i++) + { + TextLine::Ptr textLine = buffer->line(i); + s.insert(s.length(), textLine->getText(), textLine->length()); + if ( (i < (buffer->count()-1)) ) + s.append('\n'); + } + + return s; +} + +QString KateDocument::getWord(PointStruc &cursor) { + int start, end, len; + + TextLine::Ptr textLine = getTextLine(cursor.y); + len = textLine->length(); + start = end = cursor.x; + while (start > 0 && m_highlight->isInWord(textLine->getChar(start - 1))) start--; + while (end < len && m_highlight->isInWord(textLine->getChar(end))) end++; + len = end - start; + return QString(&textLine->getText()[start], len); +} + +void KateDocument::setText(const QString &s) { + int pos; + QChar ch; + + clear(); + + int line=1; + + TextLine::Ptr textLine = buffer->line(0); + for (pos = 0; pos <= (int) s.length(); pos++) { + ch = s[pos]; + if (ch.isPrint() || ch == '\t') { + textLine->append(&ch, 1); + } else if (ch == '\n') + { + textLine = new TextLine(); + buffer->insertLine (line, textLine); + line++; + } + } + updateLines(); +} + + +QString KateDocument::markedText(int flags) { + TextLine::Ptr textLine; + int len, z, start, end, i; + + len = 1; + if (!(flags & KateView::cfVerticalSelect)) { + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + len += textLine->numSelected(); + if (textLine->isSelected()) len++; + } + QString s; + len = 0; + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + end = 0; + do { + start = textLine->findUnselected(end); + end = textLine->findSelected(start); + for (i = start; i < end; i++) { + s[len] = textLine->getChar(i); + len++; + } + } while (start < end); + if (textLine->isSelected()) { + s[len] = '\n'; + len++; + } + } +// s[len] = '\0'; + return s; + } else { + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + len += textLine->numSelected() + 1; + } + QString s; + len = 0; + for (z = selectStart; z <= selectEnd; z++) { + textLine = getTextLine(z); + end = 0; + do { + start = textLine->findUnselected(end); + end = textLine->findSelected(start); + for (i = start; i < end; i++) { + s[len] = textLine->getChar(i); + len++; + } + } while (start < end); + s[len] = '\n'; + len++; + } +// s[len] = '\0'; // the final \0 is not counted in length() + return s; + } +} + +void KateDocument::delMarkedText(VConfig &c/*, bool undo*/) { + int end = 0; + + if (selectEnd < selectStart) return; + + // the caller may have already started an undo record for the current action +// if (undo) + + //auto deletion of the marked text occurs not very often and can therefore + // be recorded separately + recordStart(c, KateActionGroup::ugDelBlock); + + for (c.cursor.y = selectEnd; c.cursor.y >= selectStart; c.cursor.y--) { + TextLine::Ptr textLine = getTextLine(c.cursor.y); + + c.cursor.x = textLine->length(); + do { + end = textLine->findRevUnselected(c.cursor.x); + if (end == 0) break; + c.cursor.x = textLine->findRevSelected(end); + recordDelete(c.cursor, end - c.cursor.x); + } while (true); + end = c.cursor.x; + c.cursor.x = textLine->length(); + if (textLine->isSelected()) recordAction(KateAction::delLine,c.cursor); + } + c.cursor.y++; + /*if (end < c.cursor.x)*/ c.cursor.x = end; + + selectEnd = -1; + select.x = -1; + + /*if (undo)*/ recordEnd(c); +} + +void KateDocument::tagLineRange(int line, int x1, int x2) { + int z; + + for (z = 0; z < (int) views.count(); z++) { + views.at(z)->tagLines(line, line, x1, x2); + } +} + +void KateDocument::tagLines(int start, int end) { + int z; + + for (z = 0; z < (int) views.count(); z++) { + views.at(z)->tagLines(start, end, 0, 0xffffff); + } +} + +void KateDocument::tagAll() { + int z; + + for (z = 0; z < (int) views.count(); z++) { + views.at(z)->tagAll(); + } +} + +void KateDocument::updateLines(int startLine, int endLine, int flags, int cursorY) { + TextLine::Ptr textLine; + int line, last_line; + int ctxNum, endCtx; +// kdDebug(13020)<<"******************KateDocument::updateLines Checkpoint 1"<<endl; + if (buffer->line(startLine)==0) {kdDebug(13020)<<"********************No buffer for line " << startLine << " found**************"<<endl; return;}; +// kdDebug(13020)<<"KateDocument::updateLines Checkpoint 2"<<endl; + last_line = lastLine(); +// if (endLine >= last_line) endLine = last_line; + + line = startLine; + ctxNum = 0; + if (line > 0) ctxNum = getTextLine(line - 1)->getContext(); + do { +// kdDebug(13020)<<QString("**************Working on line: %1").arg(line)<<endl; + textLine = getTextLine(line); + if (textLine==0) kdDebug(13020)<<"****updateLines()>> error textLine==0"<<endl; + if (line <= endLine && line != cursorY) { + if (flags & KateView::cfRemoveSpaces) textLine->removeSpaces(); + updateMaxLength(textLine); + } + endCtx = textLine->getContext(); + qDebug("DOHIGHLIGHT"); + ctxNum = m_highlight->doHighlight(ctxNum,textLine); + textLine->setContext(ctxNum); + line++; + } while ((buffer->line(line)!=0) && (line <= endLine || endCtx != ctxNum)); +// kdDebug(13020)<<"updateLines :: while loop left"<<endl; + tagLines(startLine, line - 1); +} + + +void KateDocument::updateMaxLength(TextLine::Ptr &textLine) { + int len; + + len = textWidth(textLine,textLine->length()); + + if (len > maxLength) { + longestLine = textLine; + maxLength = len; + newDocGeometry = true; + } else { + if (!longestLine || (textLine == longestLine && len <= maxLength*3/4)) { + maxLength = -1; + for (int i = 0; i < numLines();i++) { + textLine = getTextLine(i); + len = textWidth(textLine,textLine->length()); + if (len > maxLength) { + maxLength = len; + longestLine = textLine; + } + } + newDocGeometry = true; + } + } +} + +void KateDocument::slotBufferChanged() { + newDocGeometry = true; + //updateLines();//JW + updateViews(); +} + +void KateDocument::slotBufferHighlight(long start,long stop) { + kdDebug(13020)<<"KateDocument::slotBufferHighlight"<<QString("%1-%2").arg(start).arg(stop)<<endl; + updateLines(start,stop); +// buffer->startLoadTimer(); +} + +void KateDocument::updateViews(KateView *exclude) { + KateView *view; + int flags; + bool markState = hasMarkedText(); + + flags = (newDocGeometry) ? KateView::ufDocGeometry : 0; + for (view = views.first(); view != 0L; view = views.next() ) { + if (view != exclude) view->updateView(flags); + + // notify every view about the changed mark state.... + if (oldMarkState != markState) emit view->newMarkStatus(); + } + oldMarkState = markState; + newDocGeometry = false; +} + +QColor &KateDocument::cursorCol(int x, int y) { + int attr; + Attribute *a; + + TextLine::Ptr textLine = getTextLine(y); + attr = textLine->getRawAttr(x); + a = &m_attribs[attr & taAttrMask]; + if (attr & taSelected) return a->selCol; else return a->col; +} + +void KateDocument::paintTextLine(QPainter &paint, int line, int xStart, int xEnd, bool showTabs) +{ + paintTextLine (paint, line, 0, xStart, xEnd, showTabs); +} + +void KateDocument::paintTextLine(QPainter &paint, int line, int y, int xStart, int xEnd, bool showTabs) +{ + TextLine::Ptr textLine; + int len; + const QChar *s; + int z, x; + QChar ch; + Attribute *a = 0L; + int attr, nextAttr; + int xs; + int xc, zc; + + if (line > lastLine()) { + paint.fillRect(0, y, xEnd - xStart,fontHeight, colors[0]); + return; + } + + textLine = getTextLine(line); + len = textLine->length(); + s = textLine->getText(); + + // skip to first visible character + x = 0; + z = 0; + do { + xc = x; + zc = z; + if (z == len) break; + ch = s[z];//textLine->getChar(z); + if (ch == '\t') { + x += m_tabWidth - (x % m_tabWidth); + } else { + a = &m_attribs[textLine->getAttr(z)]; + + if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + } + z++; + } while (x <= xStart); + + // draw background + xs = xStart; + attr = textLine->getRawAttr(zc); + while (x < xEnd) + { + nextAttr = textLine->getRawAttr(z); + if ((nextAttr ^ attr) & taSelected) + { + if (attr & taSelected) + paint.fillRect(xs - xStart, y, x - xs, fontHeight, colors[1]); + else + paint.fillRect(xs - xStart, y, x - xs, fontHeight, colors[0]); + + xs = x; + attr = nextAttr; + } + + if (z == len) break; + + ch = s[z];//textLine->getChar(z); + + if (ch == '\t') + x += m_tabWidth - (x % m_tabWidth); + else + { + a = &m_attribs[textLine->getAttr(z)]; + + if (a->bold && a->italic) + x += myFontMetricsBI.width(ch); + else if (a->bold) + x += myFontMetricsBold.width(ch); + else if (a->italic) + x += myFontMetricsItalic.width(ch); + else + x += myFontMetrics.width(ch); + } + z++; + } + + if (attr & taSelected) + paint.fillRect(xs - xStart, y, xEnd - xs, fontHeight, colors[1]); + else + paint.fillRect(xs - xStart, y, xEnd - xs, fontHeight, colors[0]); + + len = z; //reduce length to visible length + + // draw text + x = xc; + z = zc; + y += fontAscent;// -1; + attr = -1; + while (z < len) { + ch = s[z];//textLine->getChar(z); + if (ch == '\t') { + if (z > zc) { + //this should cause no copy at all + QConstString str((QChar *) &s[zc], z - zc /*+1*/); + QString s = str.string(); + paint.drawText(x - xStart, y, s); + + if (a->bold && a->italic) + x += myFontMetricsBI.width(s); + else if (a->bold) + x += myFontMetricsBold.width(s); + else if (a->italic) + x += myFontMetricsItalic.width(s); + else + x += myFontMetrics.width(s); + } + zc = z +1; + + if (showTabs) { + nextAttr = textLine->getRawAttr(z); + if (nextAttr != attr) { + attr = nextAttr; + a = &m_attribs[attr & taAttrMask]; + + if (attr & taSelected) paint.setPen(a->selCol); + else paint.setPen(a->col); + + if (a->bold && a->italic) + paint.setFont(myFontBI); + else if (a->bold) + paint.setFont(myFontBold); + else if (a->italic) + paint.setFont(myFontItalic); + else + paint.setFont(myFont); + } + +// paint.drawLine(x - xStart, y -2, x - xStart, y); +// paint.drawLine(x - xStart, y, x - xStart + 2, y); + paint.drawPoint(x - xStart, y); + paint.drawPoint(x - xStart +1, y); + paint.drawPoint(x - xStart, y -1); + } + x += m_tabWidth - (x % m_tabWidth); + } else { + nextAttr = textLine->getRawAttr(z); + if (nextAttr != attr) { + if (z > zc) { + QConstString str((QChar *) &s[zc], z - zc /*+1*/); + QString s = str.string(); + paint.drawText(x - xStart, y, s); + + if (a->bold && a->italic) + x += myFontMetricsBI.width(s); + else if (a->bold) + x += myFontMetricsBold.width(s); + else if (a->italic) + x += myFontMetricsItalic.width(s); + else + x += myFontMetrics.width(s); + zc = z; + } + attr = nextAttr; + a = &m_attribs[attr & taAttrMask]; + + if (attr & taSelected) paint.setPen(a->selCol); + else paint.setPen(a->col); + + if (a->bold && a->italic) + paint.setFont(myFontBI); + else if (a->bold) + paint.setFont(myFontBold); + else if (a->italic) + paint.setFont(myFontItalic); + else + paint.setFont(myFont); + } + } + z++; + } + if (z > zc) { + QConstString str((QChar *) &s[zc], z - zc /*+1*/); + paint.drawText(x - xStart, y, str.string()); + } +} + +// Applies the search context, and returns whether a match was found. If one is, +// the length of the string matched is also returned. +bool KateDocument::doSearch(SConfig &sc, const QString &searchFor) { + int line, col; + int searchEnd; + int bufLen, tlen; + QChar *t; + TextLine::Ptr textLine; + int pos, newPos; + + if (searchFor.isEmpty()) return false; + + bufLen = 0; + t = 0L; + + line = sc.cursor.y; + col = sc.cursor.x; + if (!(sc.flags & KateView::sfBackward)) { + //forward search + if (sc.flags & KateView::sfSelected) { + if (line < selectStart) { + line = selectStart; + col = 0; + } + searchEnd = selectEnd; + } else searchEnd = lastLine(); + + while (line <= searchEnd) { + textLine = getTextLine(line); + tlen = textLine->length(); + if (tlen > bufLen) { + delete t; + bufLen = (tlen + 255) & (~255); + t = new QChar[bufLen]; + } + memcpy(t, textLine->getText(), tlen*sizeof(QChar)); + if (sc.flags & KateView::sfSelected) { + pos = 0; + do { + pos = textLine->findSelected(pos); + newPos = textLine->findUnselected(pos); + memset(&t[pos], 0, (newPos - pos)*sizeof(QChar)); + pos = newPos; + } while (pos < tlen); + } + + QString text(t, tlen); + if (sc.flags & KateView::sfWholeWords) { + // Until the end of the line... + while (col < tlen) { + // ...find the next match. + col = sc.search(text, col); + if (col != -1) { + // Is the match delimited correctly? + if (((col == 0) || (!m_highlight->isInWord(t[col]))) && + ((col + sc.matchedLength == tlen) || (!m_highlight->isInWord(t[col + sc.matchedLength])))) { + goto found; + } + else { + // Start again from the next character. + col++; + } + } + else { + // No match. + break; + } + } + } + else { + // Non-whole-word search. + col = sc.search(text, col); + if (col != -1) + goto found; + } + col = 0; + line++; + } + } else { + // backward search + if (sc.flags & KateView::sfSelected) { + if (line > selectEnd) { + line = selectEnd; + col = -1; + } + searchEnd = selectStart; + } else searchEnd = 0; + + while (line >= searchEnd) { + textLine = getTextLine(line); + tlen = textLine->length(); + if (tlen > bufLen) { + delete t; + bufLen = (tlen + 255) & (~255); + t = new QChar[bufLen]; + } + memcpy(t, textLine->getText(), tlen*sizeof(QChar)); + if (sc.flags & KateView::sfSelected) { + pos = 0; + do { + pos = textLine->findSelected(pos); + newPos = textLine->findUnselected(pos); + memset(&t[pos], 0, (newPos - pos)*sizeof(QChar)); + pos = newPos; + } while (pos < tlen); + } + + if (col < 0 || col > tlen) col = tlen; + + QString text(t, tlen); + if (sc.flags & KateView::sfWholeWords) { + // Until the beginning of the line... + while (col >= 0) { + // ...find the next match. + col = sc.search(text, col); + if (col != -1) { + // Is the match delimited correctly? + if (((col == 0) || (!m_highlight->isInWord(t[col]))) && + ((col + sc.matchedLength == tlen) || (!m_highlight->isInWord(t[col + sc.matchedLength])))) { + goto found; + } + else { + // Start again from the previous character. + col--; + } + } + else { + // No match. + break; + } + } + } + else { + // Non-whole-word search. + col = sc.search(text, col); + if (col != -1) + goto found; + } + col = -1; + line--; + } + } + sc.flags |= KateView::sfWrapped; + return false; +found: + if (sc.flags & KateView::sfWrapped) { + if ((line > sc.startCursor.y || (line == sc.startCursor.y && col >= sc.startCursor.x)) + ^ ((sc.flags & KateView::sfBackward) != 0)) return false; + } + sc.cursor.x = col; + sc.cursor.y = line; + return true; +} + +void KateDocument::tagLine(int line) { + + if (tagStart > line) tagStart = line; + if (tagEnd < line) tagEnd = line; +} + +void KateDocument::insLine(int line) { + KateView *view; + + if (selectStart >= line) selectStart++; + if (selectEnd >= line) selectEnd++; + if (tagStart >= line) tagStart++; + if (tagEnd >= line) tagEnd++; + + newDocGeometry = true; + for (view = views.first(); view != 0L; view = views.next() ) { + view->insLine(line); + } +} + +void KateDocument::delLine(int line) { + KateView *view; + + if (selectStart >= line && selectStart > 0) selectStart--; + if (selectEnd >= line) selectEnd--; + if (tagStart >= line && tagStart > 0) tagStart--; + if (tagEnd >= line) tagEnd--; + + newDocGeometry = true; + for (view = views.first(); view != 0L; view = views.next() ) { + view->delLine(line); + } +} + +void KateDocument::optimizeSelection() { + TextLine::Ptr textLine; + + while (selectStart <= selectEnd) { + textLine = getTextLine(selectStart); + if (textLine->isSelected() || textLine->numSelected() > 0) break; + selectStart++; + } + while (selectEnd >= selectStart) { + textLine = getTextLine(selectEnd); + if (textLine->isSelected() || textLine->numSelected() > 0) break; + selectEnd--; + } + if (selectStart > selectEnd) { + selectStart = 0xffffff; + selectEnd = 0; + } +} + +void KateDocument::doAction(KateAction *a) { + + switch (a->action) { + case KateAction::replace: + doReplace(a); + break; + case KateAction::wordWrap: + doWordWrap(a); + break; + case KateAction::wordUnWrap: + doWordUnWrap(a); + break; + case KateAction::newLine: + doNewLine(a); + break; + case KateAction::delLine: + doDelLine(a); + break; + case KateAction::insLine: + doInsLine(a); + break; + case KateAction::killLine: + doKillLine(a); + break; +/* case KateAction::doubleLine: + break; + case KateAction::removeLine: + break;*/ + } +} + +void KateDocument::doReplace(KateAction *a) { + TextLine::Ptr textLine; + int l; + + //exchange current text with stored text in KateAction *a + + textLine = getTextLine(a->cursor.y); + l = textLine->length() - a->cursor.x; + if (l > a->len) l = a->len; + + QString oldText(&textLine->getText()[a->cursor.x], (l < 0) ? 0 : l); + textLine->replace(a->cursor.x, a->len, a->text.unicode(), a->text.length()); + + a->len = a->text.length(); + a->text = oldText; + + buffer->changeLine(a->cursor.y); + + tagLine(a->cursor.y); +} + +void KateDocument::doWordWrap(KateAction *a) { + TextLine::Ptr textLine; + + textLine = getTextLine(a->cursor.y - 1); + a->len = textLine->length() - a->cursor.x; + textLine->wrap(getTextLine(a->cursor.y),a->len); + + buffer->changeLine(a->cursor.y - 1); + buffer->changeLine(a->cursor.y); + + tagLine(a->cursor.y - 1); + tagLine(a->cursor.y); + if (selectEnd == a->cursor.y - 1) selectEnd++; + + a->action = KateAction::wordUnWrap; +} + +void KateDocument::doWordUnWrap(KateAction *a) { + TextLine::Ptr textLine; + + textLine = getTextLine(a->cursor.y - 1); +// textLine->setLength(a->len); + textLine->unWrap(a->len, getTextLine(a->cursor.y),a->cursor.x); + + buffer->changeLine(a->cursor.y - 1); + buffer->changeLine(a->cursor.y); + + tagLine(a->cursor.y - 1); + tagLine(a->cursor.y); + + a->action = KateAction::wordWrap; +} + +void KateDocument::doNewLine(KateAction *a) { + TextLine::Ptr textLine, newLine; + + textLine = getTextLine(a->cursor.y); + newLine = new TextLine(textLine->getRawAttr(), textLine->getContext()); + textLine->wrap(newLine,a->cursor.x); + + buffer->insertLine(a->cursor.y + 1, newLine); + buffer->changeLine(a->cursor.y); + + insLine(a->cursor.y + 1); + tagLine(a->cursor.y); + tagLine(a->cursor.y + 1); + if (selectEnd == a->cursor.y) selectEnd++;//addSelection(a->cursor.y + 1); + + a->action = KateAction::delLine; +} + +void KateDocument::doDelLine(KateAction *a) { + TextLine::Ptr textLine, nextLine; + + textLine = getTextLine(a->cursor.y); + nextLine = getTextLine(a->cursor.y+1); +// textLine->setLength(a->cursor.x); + textLine->unWrap(a->cursor.x, nextLine,nextLine->length()); + textLine->setContext(nextLine->getContext()); + if (longestLine == nextLine) longestLine = 0L; + + buffer->changeLine(a->cursor.y); + buffer->removeLine(a->cursor.y+1); + + tagLine(a->cursor.y); + delLine(a->cursor.y + 1); + + a->action = KateAction::newLine; +} + +void KateDocument::doInsLine(KateAction *a) { + + buffer->insertLine(a->cursor.y, new TextLine()); + + insLine(a->cursor.y); + + a->action = KateAction::killLine; +} + +void KateDocument::doKillLine(KateAction *a) { + TextLine::Ptr textLine = getTextLine(a->cursor.y); + if (longestLine == textLine) longestLine = 0L; + + buffer->removeLine(a->cursor.y); + + delLine(a->cursor.y); + tagLine(a->cursor.y); + + a->action = KateAction::insLine; +} + +void KateDocument::newUndo() { + KTextEditor::View *view; + int state; + + state = 0; + if (currentUndo > 0) state |= 1; + if (currentUndo < (int) undoList.count()) state |= 2; + undoState = state; + for (view = m_views.first(); view != 0L; view = m_views.next() ) { + emit static_cast<KateView *>( view )->newUndo(); + } +} + +void KateDocument::recordStart(VConfig &c, int newUndoType) { + recordStart(c.view, c.cursor, c.flags, newUndoType); +} + +void KateDocument::recordStart(KateView *, PointStruc &cursor, int flags, + int newUndoType, bool keepModal, bool mergeUndo) { + + KateActionGroup *g; + +// if (newUndoType == KateActionGroup::ugNone) { + // only a bug would cause this +//why should someone do this? we can't prevent all programming errors :) (jochen whilhelmy) +// debug("KateDocument::recordStart() called with no undo group type!"); +// return; +// } + + if (!keepModal) setPseudoModal(0L); + + //i optimized the group undo stuff a bit (jochen wilhelmy) + // recordReset() is not needed any more + g = undoList.getLast(); + if (g != 0L && ((undoCount < 1024 && flags & KateView::cfGroupUndo + && g->end.x == cursor.x && g->end.y == cursor.y) || mergeUndo)) { + + //undo grouping : same actions are put into one undo step + //precondition : new action starts where old stops or mergeUndo flag + if (g->undoType == newUndoType + || (g->undoType == KateActionGroup::ugInsChar + && newUndoType == KateActionGroup::ugInsLine) + || (g->undoType == KateActionGroup::ugDelChar + && newUndoType == KateActionGroup::ugDelLine)) { + + undoCount++; + if (g->undoType != newUndoType) undoCount = 0xffffff; + return; + } + } + undoCount = 0; +/* + if (undoView != view) { + // always kill the current undo group if the editing view changes + recordReset(); + undoType = newUndoType; + } else if (newUndoType == undoType) { +printf("bla!!!\n"); + // same as current type, keep using it + return; + } else if ( (undoType == KateActionGroup::ugInsChar && newUndoType == KateActionGroup::ugInsLine) || + (undoType == KateActionGroup::ugDelChar && newUndoType == KateActionGroup::ugDelLine) ) { + // some type combinations can run together... + undoType += 1000; + return; + } else { + recordReset(); + undoType = newUndoType; + } + + undoView = view; +*/ + while ((int) undoList.count() > currentUndo) undoList.removeLast(); + while ((int) undoList.count() > undoSteps) { + undoList.removeFirst(); + currentUndo--; + } + + g = new KateActionGroup(cursor, newUndoType); + undoList.append(g); +// currentUndo++; + + tagEnd = 0; + tagStart = 0xffffff; +} + +void KateDocument::recordAction(KateAction::Action action, PointStruc &cursor) { + KateAction *a; + + a = new KateAction(action, cursor); + doAction(a); + undoList.getLast()->insertAction(a); +} + +void KateDocument::recordInsert(VConfig &c, const QString &text) { + recordReplace(c, 0, text); +} + +void KateDocument::recordReplace(VConfig &c, int len, const QString &text) { + if (c.cursor.x > 0 && !(c.flags & KateView::cfSpaceIndent)) { + TextLine::Ptr textLine = getTextLine(c.cursor.y); + if (textLine->length() == 0) { + QString s = tabString(c.cursor.x, tabChars); + int len = s.length(); + s += text; + c.cursor.x = 0; + recordReplace(c.cursor, len, s); + c.cursor.x = len; + return; + } + } + recordReplace(c.cursor, len, text); +} + +void KateDocument::recordInsert(PointStruc &cursor, const QString &text) { + recordReplace(cursor, 0, text); +} + +void KateDocument::recordDelete(PointStruc &cursor, int len) { + recordReplace(cursor, len, QString::null); +} + +void KateDocument::recordReplace(PointStruc &cursor, int len, const QString &text) { + KateAction *a; + TextLine::Ptr textLine; + int l; + + if (len == 0 && text.isEmpty()) return; + + //try to append to last replace action + a = undoList.getLast()->action; + if (a == 0L || a->action != KateAction::replace + || a->cursor.x + a->len != cursor.x || a->cursor.y != cursor.y) { + +//if (a != 0L) printf("new %d %d\n", a->cursor.x + a->len, cursor.x); + a = new KateAction(KateAction::replace, cursor); + undoList.getLast()->insertAction(a); + } + + //replace + textLine = getTextLine(cursor.y); + l = textLine->length() - cursor.x; + if (l > len) l = len; + a->text.insert(a->text.length(), &textLine->getText()[cursor.x], (l < 0) ? 0 : l); + textLine->replace(cursor.x, len, text.unicode(), text.length()); + a->len += text.length(); + + buffer->changeLine(a->cursor.y); + updateMaxLength(textLine); + tagLine(a->cursor.y); +} + +void KateDocument::recordEnd(VConfig &c) { + recordEnd(c.view, c.cursor, c.flags); +} + +void KateDocument::recordEnd(KateView *view, PointStruc &cursor, int flags) { + KateActionGroup *g; + + // clear selection if option "persistent selections" is off +// if (!(flags & cfPersistent)) deselectAll(); + + g = undoList.getLast(); + if (g->action == 0L) { + // no action has been done: remove empty undo record + undoList.removeLast(); + return; + } + // store end cursor position for redo + g->end = cursor; + currentUndo = undoList.count(); + + if (tagStart <= tagEnd) { + optimizeSelection(); + updateLines(tagStart, tagEnd, flags, cursor.y); + setModified(true); + } + + view->updateCursor(cursor, flags); + +// newUndo(); +/* + undoCount++; + // we limit the number of individual undo operations for sanity - is 1K reasonable? + // this is also where we handle non-group undo preference + // if the undo type is singlular, we always finish it now + if ( undoType == KateActionGroup::ugPaste || + undoType == KateActionGroup::ugDelBlock || + undoType > 1000 || + undoCount > 1024 || !(flags & cfGroupUndo) ) { +printf("recordend %d %d\n", undoType, undoCount); + recordReset(); + } +*/ + + // this should keep the flood of signals down a little... + if (undoCount == 0) newUndo(); + emit textChanged(); +} +/* +void KateDocument::recordReset() +{ + if (pseudoModal) + return; + + // forces the next call of recordStart() to begin a new undo group + // not used in normal editing, but used by markFound(), etc. + undoType = KateActionGroup::ugNone; + undoCount = 0; + undoView = NULL; + undoReported = false; +printf("recordreset\n"); +} +*/ + +/* +void KateDocument::recordDel(PointStruc &cursor, TextLine::Ptr &textLine, int l) { + int len; + + len = textLine->length() - cursor.x; + if (len > l) len = l; + if (len > 0) { + insertUndo(new KateAction(KateAction::replace,cursor,&textLine->getText()[cursor.x],len)); + } +} +*/ + + +void KateDocument::doActionGroup(KateActionGroup *g, int flags, bool undo) { + KateAction *a, *next; + + setPseudoModal(0L); + if (!(flags & KateView::cfPersistent)) deselectAll(); + tagEnd = 0; + tagStart = 0xffffff; + + a = g->action; + g->action = 0L; + while (a) { + doAction(a); + next = a->next; + g->insertAction(a); + a = next; + } + optimizeSelection(); + if (tagStart <= tagEnd) updateLines(tagStart, tagEnd, flags); + + // the undo/redo functions set undo to true, all others should leave it + // alone (default) + if (!undo) { + setModified(true); + newUndo(); + } +} + +int KateDocument::nextUndoType() +{ + KateActionGroup *g; + + if (currentUndo <= 0) return KateActionGroup::ugNone; + g = undoList.at(currentUndo - 1); + return g->undoType; +} + +int KateDocument::nextRedoType() +{ + KateActionGroup *g; + + if (currentUndo >= (int) undoList.count()) return KateActionGroup::ugNone; + g = undoList.at(currentUndo); +// if (!g) return KateActionGroup::ugNone; + return g->undoType; +} + +void KateDocument::undoTypeList(QValueList<int> &lst) +{ + lst.clear(); + for (int i = currentUndo-1; i>=0 ;i--) + lst.append(undoList.at(i)->undoType); +} + +void KateDocument::redoTypeList(QValueList<int> &lst) +{ + lst.clear(); + for (int i = currentUndo+1; i<(int)undoList.count(); i++) + lst.append(undoList.at(i)->undoType); +} + +void KateDocument::undo(VConfig &c, int count) { + KateActionGroup *g = 0L; + int num; + bool needUpdate = false; // don't update the cursor until completely done + + if (count <= 0) return; + + for (num = 0 ; num < count ; num++) { + if (currentUndo <= 0) break; + currentUndo--; + g = undoList.at(currentUndo); + doActionGroup(g, c.flags, true); // do not setModified() or newUndo() + needUpdate = true; + +// if (num == 0) recordReset(); + } + + if (needUpdate) { + // since we told doActionGroup() not to do this stuff, we need to do it now + c.view->updateCursor(g->start); + setModified(true); + newUndo(); + } +} + +void KateDocument::redo(VConfig &c, int count) { + KateActionGroup *g = 0L; + int num; + bool needUpdate = false; // don't update the cursor until completely done + + if (count <= 0) return; + + for (num = 0 ; num < count ; num++) { + if (currentUndo+1 > (int)undoList.count()) break; + g = undoList.at(currentUndo); + currentUndo++; + doActionGroup(g, c.flags, true); // do not setModified() or newUndo() + needUpdate = true; + +// if (num == 0) recordReset(); + } + + if (needUpdate) { + // since we told doActionGroup() not to do this stuff, we need to do it now + c.view->updateCursor(g->end); + setModified(true); + newUndo(); + } +} + +void KateDocument::clearRedo() { + // disable redos + // this was added as an assist to the spell checker + bool deleted = false; + + while ((int) undoList.count() > currentUndo) { + deleted = true; + undoList.removeLast(); + } + + if (deleted) newUndo(); +} + +void KateDocument::setUndoSteps(int steps) { + if (steps < 5) steps = 5; + undoSteps = steps; +} + +void KateDocument::setPseudoModal(QWidget *w) { +// QWidget *old = pseudoModal; + + // (glenebob) + // this is a temporary hack to make the spell checker work a little + // better - as kspell progresses, this sort of thing should become + // obsolete or worked around more cleanly + // this is relied upon *only* by the spell-check code + if (pseudoModal && pseudoModal != (QWidget*)1L) + delete pseudoModal; + +// pseudoModal = 0L; +// if (old || w) recordReset(); + + pseudoModal = w; +} + + +void KateDocument::newBracketMark(PointStruc &cursor, BracketMark &bm) +{ + TextLine::Ptr textLine; + int x, line, count, attr; + QChar bracket, opposite, ch; + Attribute *a; + + bm.eXPos = -1; //mark bracked mark as invalid + x = cursor.x -1; // -1 to look at left side of cursor + if (x < 0) return; + line = cursor.y; //current line + count = 0; //bracket counter for nested brackets + + textLine = getTextLine(line); + if (!textLine) return; + + bracket = textLine->getChar(x); + attr = textLine->getAttr(x); + + if (bracket == '(' || bracket == '[' || bracket == '{') + { + //get opposite bracket + opposite = ')'; + if (bracket == '[') opposite = ']'; + if (bracket == '{') opposite = '}'; + //get attribute of bracket (opposite bracket must have the same attribute) + x++; + while (line - cursor.y < 40) { + //go to next line on end of line + while (x >= (int) textLine->length()) { + line++; + if (line > lastLine()) return; + textLine = getTextLine(line); + x = 0; + } + if (textLine->getAttr(x) == attr) { + //try to find opposite bracked + ch = textLine->getChar(x); + if (ch == bracket) count++; //same bracket : increase counter + if (ch == opposite) { + count--; + if (count < 0) goto found; + } + } + x++; + } + } + else if (bracket == ')' || bracket == ']' || bracket == '}') + { + opposite = '('; + if (bracket == ']') opposite = '['; + if (bracket == '}') opposite = '{'; + x--; + while (cursor.y - line < 20) { + + while (x < 0) { + line--; + if (line < 0) return; + textLine = getTextLine(line); + x = textLine->length() -1; + } + if (textLine->getAttr(x) == attr) { + ch = textLine->getChar(x); + if (ch == bracket) count++; + if (ch == opposite) { + count--; + if (count < 0) goto found; + } + } + x--; + } + } + return; + +found: + //cursor position of opposite bracket + bm.cursor.x = x; + bm.cursor.y = line; + //x position (start and end) of related bracket + bm.sXPos = textWidth(textLine, x); + a = &m_attribs[attr]; + + if (a->bold && a->italic) + bm.eXPos = bm.sXPos + myFontMetricsBI.width(bracket); + else if (a->bold) + bm.eXPos = bm.sXPos + myFontMetricsBold.width(bracket); + else if (a->italic) + bm.eXPos = bm.sXPos + myFontMetricsItalic.width(bracket); + else + bm.eXPos = bm.sXPos + myFontMetrics.width(bracket); +} + +void KateDocument::clipboardChanged() { //slot +//#if defined(_WS_X11_) + if (m_singleSelection) { + disconnect(QApplication::clipboard(), SIGNAL(dataChanged()), + this, SLOT(clipboardChanged())); + deselectAll(); + updateViews(); + } +//#endif +} + +#if 0 +void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev ) +{ + KParts::ReadWritePart::guiActivateEvent( ev ); + if ( ev->activated() ) + emit selectionChanged(); +} +#endif + +void KateDocument::setDocName (QString docName) +{ + myDocName = docName; + emit nameChanged (this); +} + +void KateDocument::setMTime() +{ + if (fileInfo && !fileInfo->fileName().isEmpty()) { + fileInfo->refresh(); + mTime = fileInfo->lastModified(); + } +} + +void KateDocument::isModOnHD(bool forceReload) +{ + if (fileInfo && !fileInfo->fileName().isEmpty()) { + fileInfo->refresh(); + if (fileInfo->lastModified() > mTime) { + if ( forceReload || + (KMessageBox::warningContinueCancel(0, + (i18n("The file %1 has changed on disk.\nDo you want to reload it?\n\nIf you cancel you will lose these changes next time you save this file")).arg(m_url), + i18n("File has changed on Disk"), + i18n("Yes") ) == KMessageBox::Continue) + ) + reloadFile(); + else + setMTime(); + } + } +} + +void KateDocument::reloadFile() +{ +#warning fixme +#if 0 + if (fileInfo && !fileInfo->fileName().isEmpty()) { + KateDocument::openFile(); + setMTime(); + } +#endif +} + +void KateDocument::slotModChanged() +{ + emit modStateChanged (this); +} + +QList<Kate::Mark> KateDocument::marks () +{ + QList<Kate::Mark> list; + TextLine::Ptr line; + + for (int i=0; i < numLines(); i++) + { + line = getTextLine(i); + if (line->mark() != 0) + { + Kate::Mark *mark=new Kate::Mark; + mark->line = i; + mark->type = line->mark(); + list.append (mark); + } + } + + return list; +} + +void KateDocument::flush () +{ + if (isReadOnly()) + return; + + m_url = QString::null; + fileInfo->setFile (QString()); + setMTime(); + + clear(); + updateViews(); + + emit fileNameChanged (); +} + +void KateDocument::open (const QString &name) +{ + openURL (name); +} + +void KateDocument::wrapText (uint col) +{ + int line = 0; + int z = 0; + + while(true) + { + TextLine::Ptr l = getTextLine(line); + + if (l->length() > col) + { + TextLine::Ptr tl = new TextLine(); + buffer->insertLine(line+1,tl); + const QChar *text = l->getText(); + + for (z=col; z>0; z--) + { + if (z < 1) break; + if (text[z].isSpace()) break; + } + + if (z < 1) z=col; + + l->wrap (tl, z); + } + + line++; + if (line >= numLines()) break; + }; + + newDocGeometry=true; + updateLines(); + updateViews(); +} + +void KateDocument::setWordWrap (bool on) +{ + if (on != myWordWrap && on) + wrapText (myWordWrapAt); + + myWordWrap = on; +} + +void KateDocument::setWordWrapAt (uint col) +{ + if (myWordWrapAt != col && myWordWrap) + wrapText (myWordWrapAt); + + myWordWrapAt = col; +} + +void KateDocument::applyWordWrap () +{ + wrapText (myWordWrapAt); +} diff --git a/noncore/apps/tinykate/libkate/document/katedocument.h b/noncore/apps/tinykate/libkate/document/katedocument.h new file mode 100644 index 0000000..220d188 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katedocument.h @@ -0,0 +1,569 @@ +/*************************************************************************** + katedocument.h - description + ------------------- + begin : Mon Jan 15 2001 + copyright : (C) 2001 by Christoph "Crossfire" Cullmann + (C) 2002 by Joseph Wenninger + email : crossfire@babylon2k.de + jowenn@kde.org + +***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +/* + Copyright (C) 1998, 1999 Jochen Wilhelmy + digisnap@cs.tu-berlin.de + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef kate_document_h +#define kate_document_h + + +#include <qobject.h> +#include <qlist.h> +#include <qcolor.h> +#include <qfont.h> +#include <qfontmetrics.h> +#include <qdatetime.h> +#include <qfileinfo.h> + +#include "../view/kateview.h" +#include "katehighlight.h" +#include "katebuffer.h" +#include "katetextline.h" + + +#include <qptrdict.h> + +class KateCmd; + +class CachedFontMetrics : public QFontMetrics { +private: + short *warray[256]; +public: + CachedFontMetrics(const QFont& f) : QFontMetrics(f) { + for (int i=0; i<256; i++) warray[i]=0; + } + ~CachedFontMetrics() { + for (int i=0; i<256; i++) + if (warray[i]) delete[] warray[i]; + } + int width(QChar c) { + uchar cell=c.cell(); + uchar row=c.row(); + short *wa=warray[row]; + if (!wa) { + // qDebug("create row: %d",row); + wa=warray[row]=new short[256]; + for (int i=0; i<256; i++) wa[i]=-1; + } + if (wa[cell]<0) wa[cell]=(short) QFontMetrics::width(c); + return (int)wa[cell]; + } + int width(QString s) { return QFontMetrics::width(s); } +}; + +class Attribute { + public: + Attribute() { ; }; + + QColor col; + QColor selCol; + bool bold; + bool italic; +}; + +class KateAction { + public: + enum Action {replace, wordWrap, wordUnWrap, newLine, delLine, + insLine, killLine};//, doubleLine, removeLine}; + + KateAction(Action, PointStruc &cursor, int len = 0, + const QString &text = QString::null); + + Action action; + PointStruc cursor; + int len; + QString text; + KateAction *next; +}; + +class KateActionGroup { + public: + // the undo group types + enum { ugNone, // + ugPaste, // paste + ugDelBlock, // delete/replace selected text + ugIndent, // indent + ugUnindent, // unindent + ugComment, // comment + ugUncomment, // uncomment + ugReplace, // text search/replace + ugSpell, // spell check + ugInsChar, // char type/deleting + ugDelChar, // '' '' + ugInsLine, // line insert/delete + ugDelLine // '' '' + }; + + KateActionGroup(PointStruc &aStart, int type = ugNone); + ~KateActionGroup(); + void insertAction(KateAction *); + + static const char * typeName(int type); + + PointStruc start; + PointStruc end; + KateAction *action; + int undoType; +}; + +/** + The text document. It contains the textlines, controls the + document changing operations and does undo/redo. WARNING: do not change + the text contents directly in methods where this is not explicitly + permitted. All changes have to be made with some basic operations, + which are recorded by the undo/redo system. + @see TextLine + @author Jochen Wilhelmy +*/ +class KateDocument: public Kate::Document +{ + Q_OBJECT + friend class KateViewInternal; + friend class KateView; + friend class KateIconBorder; + + public: + KateDocument(bool bSingleViewMode=false, bool bBrowserView=false, QWidget *parentWidget = 0, const char *widgetName = 0, QObject * = 0, const char * = 0); + ~KateDocument(); + + protected: + QFont myFont, myFontBold, myFontItalic, myFontBI; + CachedFontMetrics myFontMetrics, myFontMetricsBold, myFontMetricsItalic, myFontMetricsBI; + + public: + void setFont (QFont font); + QFont getFont () { return myFont; }; + CachedFontMetrics getFontMetrics () { return myFontMetrics; }; + + virtual bool saveFile(); + + virtual KTextEditor::View *createView( QWidget *parent, const char *name ); + virtual QString textLine( int line ) const; + + virtual void insertLine( const QString &s, int line = -1 ); + + void insert_Line(const QString& s,int line=-1, bool update=true); + void remove_Line(int line,bool update=true); + void replaceLine(const QString& s,int line=-1); + virtual void insertAt( const QString &s, int line, int col, bool mark = FALSE ); + virtual void removeLine( int line ); + virtual int length() const; + + virtual void setSelection( int row_from, int col_from, int row_to, int col_t ); + virtual bool hasSelection() const; + virtual QString selection() const; + + // only to make part work, don't change it ! + bool m_bSingleViewMode; + +// public interface + /** + * gets the number of lines + */ + virtual int numLines() const; + + /** + * gets the last line number (numLines() -1) + */ + int lastLine() const {return numLines()-1;} + + /** + gets the given line + @return the TextLine object at the given line + @see TextLine + */ + TextLine::Ptr getTextLine(int line) const; + + /** + get the length in pixels of the given line + */ + int textLength(int line); + + void setTabWidth(int); + int tabWidth() {return tabChars;} + void setReadOnly(bool); + bool isReadOnly() const; + void setNewDoc( bool ); + bool isNewDoc() const; + virtual void setReadWrite( bool ){}; + virtual bool isReadWrite() const {return true;} + virtual void setModified(bool); + virtual bool isModified() const; + void setSingleSelection(bool ss) {m_singleSelection = ss;} + bool singleSelection() {return m_singleSelection;} + + void readConfig(); + void writeConfig(); + void readSessionConfig(KConfig *); + void writeSessionConfig(KConfig *); + + bool hasBrowserExtension() const { return m_bBrowserView; } + + protected: + bool m_bBrowserView; + + signals: + void selectionChanged(); + void highlightChanged(); + void modifiedChanged (); + void preHighlightChanged(long); + + // search stuff + protected: + static QStringList searchForList; + static QStringList replaceWithList; + static uint uniqueID; + + // highlight stuff + public: + Highlight *highlight() {return m_highlight;} + int highlightNum() {return hlManager->findHl(m_highlight);} + int numAttribs() {return m_numAttribs;} + Attribute *attribs() {return m_attribs;} + void setDontChangeHlOnSave(); + + protected: + void setHighlight(int n); + void makeAttribs(); + void updateFontData(); + + protected slots: + void hlChanged(); + +// view interaction + public: + virtual void addView(KTextEditor::View *); + virtual void removeView(KTextEditor::View *); + bool ownedView(KateView *); + bool isLastView(int numViews); + + int getTextLineCount() {return numLines();} + + int textWidth(const TextLine::Ptr &, int cursorX); + int textWidth(PointStruc &cursor); + int textWidth(bool wrapCursor, PointStruc &cursor, int xPos); + int textPos(const TextLine::Ptr &, int xPos); +// int textPos(TextLine::Ptr &, int xPos, int &newXPos); + int textWidth(); + int textHeight(); + + void insert(VConfig &, const QString &); + void insertFile(VConfig &, QIODevice &); + + int currentColumn(PointStruc &cursor); + bool insertChars(VConfig &, const QString &chars); + void newLine(VConfig &); + void killLine(VConfig &); + void backspace(VConfig &); + void del(VConfig &); + void clear(); + void cut(VConfig &); + void copy(int flags); + void paste(VConfig &); + + void toggleRect(int, int, int, int); + void selectTo(VConfig &c, PointStruc &cursor, int cXPos); + void selectAll(); + void deselectAll(); + void invertSelection(); + void selectWord(PointStruc &cursor, int flags); + void selectLength(PointStruc &cursor, int length, int flags); + + void indent(VConfig &c) {doIndent(c, 1);} + void unIndent(VConfig &c) {doIndent(c, -1);} + void cleanIndent(VConfig &c) {doIndent(c, 0);} + // called by indent/unIndent/cleanIndent + // just does some setup and then calls optimizeLeadingSpace() + void doIndent(VConfig &, int change); + // optimize leading whitespace on a single line - see kwdoc.cpp for full description + void optimizeLeadingSpace(int line, int flags, int change); + + void comment(VConfig &c) {doComment(c, 1);} + void unComment(VConfig &c) {doComment(c, -1);} + void doComment(VConfig &, int change); + + virtual QString text() const; + QString getWord(PointStruc &cursor); + + public slots: + virtual void setText(const QString &); + + public: + long needPreHighlight(long till); + bool hasMarkedText() {return (selectEnd >= selectStart);} + QString markedText(int flags); + void delMarkedText(VConfig &/*, bool undo = true*/); + + void tagLineRange(int line, int x1, int x2); + void tagLines(int start, int end); + void tagAll(); + void updateLines(int startLine = 0, int endLine = 0xffffff, int flags = 0, int cursorY = -1); + void updateMaxLength(TextLine::Ptr &); + void updateViews(KateView *exclude = 0L); + + QColor &cursorCol(int x, int y); + void paintTextLine(QPainter &, int line, int xStart, int xEnd, bool showTabs); + void paintTextLine(QPainter &, int line, int y, int xStart, int xEnd, bool showTabs); + + bool doSearch(SConfig &s, const QString &searchFor); + +// internal + void tagLine(int line); + void insLine(int line); + void delLine(int line); + void optimizeSelection(); + + void doAction(KateAction *); + void doReplace(KateAction *); + void doWordWrap(KateAction *); + void doWordUnWrap(KateAction *); + void doNewLine(KateAction *); + void doDelLine(KateAction *); + void doInsLine(KateAction *); + void doKillLine(KateAction *); + void newUndo(); + + void recordStart(VConfig &, int newUndoType); + void recordStart(KateView *, PointStruc &, int flags, int newUndoType, bool keepModal = false, bool mergeUndo = false); + void recordAction(KateAction::Action, PointStruc &); + void recordInsert(VConfig &, const QString &text); + void recordReplace(VConfig &, int len, const QString &text); + void recordInsert(PointStruc &, const QString &text); + void recordDelete(PointStruc &, int len); + void recordReplace(PointStruc &, int len, const QString &text); + void recordEnd(VConfig &); + void recordEnd(KateView *, PointStruc &, int flags); + void doActionGroup(KateActionGroup *, int flags, bool undo = false); + + int nextUndoType(); + int nextRedoType(); + void undoTypeList(QValueList<int> &lst); + void redoTypeList(QValueList<int> &lst); + void undo(VConfig &, int count = 1); + void redo(VConfig &, int count = 1); + void clearRedo(); + void setUndoSteps(int steps); + + void setPseudoModal(QWidget *); + + void newBracketMark(PointStruc &, BracketMark &); + + + protected slots: + void clipboardChanged(); + void slotBufferChanged(); + void slotBufferHighlight(long,long); + void doPreHighlight(); + + private slots: + void slotViewDestroyed(); + +// member variables + protected: + long PreHighlightedTill; + long RequestPreHighlightTill; + KWBuffer *buffer; + QColor colors[2]; + HlManager *hlManager; + Highlight *m_highlight; + int m_numAttribs; + static const int maxAttribs; + Attribute *m_attribs; + + int eolMode; + + int tabChars; + int m_tabWidth; + int fontHeight; + int fontAscent; + + QList<KateView> views; + bool newDocGeometry; + + TextLine::Ptr longestLine; + float maxLength; + + PointStruc select; + PointStruc anchor; + int aXPos; + int selectStart; + int selectEnd; + bool oldMarkState; + bool m_singleSelection; // false: windows-like, true: X11-like + + bool readOnly; + bool newDoc; // True if the file is a new document (used to determine whether + // to check for overwriting files on save) + bool modified; + + bool myWordWrap; + uint myWordWrapAt; + + QList<KateActionGroup> undoList; + int currentUndo; + int undoState; + int undoSteps; + int tagStart; + int tagEnd; + int undoCount; //counts merged undo steps + + QWidget *pseudoModal; //the replace prompt is pseudo modal + + public: + /** Tjecks if the file on disk is newer than document contents. + If forceReload is true, the document is reloaded without asking the user, + otherwise [default] the user is asked what to do. */ + void isModOnHD(bool forceReload=false); + + uint docID () {return myDocID;}; + QString docName () {return myDocName;}; + + void setDocName (QString docName); + + public slots: + /** Reloads the current document from disk if possible */ + void reloadFile(); + + private slots: + void slotModChanged (); + + private: + /** updates mTime to reflect file on fs. + called from constructor and from saveFile. */ + void setMTime(); + uint myDocID; + QFileInfo* fileInfo; + QDateTime mTime; + QString myDocName; + + QString m_url; + QString m_file; + void openURL(const QString &filename); + private: + KateCmd *myCmd; + + public: + KateCmd *cmd () { return myCmd; }; + + private: + QString myEncoding; + + public: + void setEncoding (QString e) { myEncoding = e; }; + QString encoding() { return myEncoding; }; + + void setWordWrap (bool on); + bool wordWrap () { return myWordWrap; }; + + void setWordWrapAt (uint col); + uint wordWrapAt () { return myWordWrapAt; }; + + signals: + void modStateChanged (KateDocument *doc); + void nameChanged (KateDocument *doc); + + public: + QList<Kate::Mark> marks (); + + public slots: + // clear buffer/filename - update the views + void flush (); + + signals: + /** + The file has been saved (perhaps the name has changed). The main window + can use this to change its caption + */ + void fileNameChanged (); + + public: + //end of line settings + enum Eol_settings {eolUnix=0,eolDos=1,eolMacintosh=2}; + + // for the DCOP interface + public: + void open (const QString &name=0); + + public: + // wrap the text of the document at the column col + void wrapText (uint col); + + public slots: + void applyWordWrap (); + + private: + + class KateDocPrivate + { + public: + bool hlSetByUser; + }; + + +// BCI: Add a real d-pointer in the next BIC release +static QPtrDict<KateDocPrivate>* d_ptr; +static void cleanup_d_ptr() + { + delete d_ptr; + } + +KateDocPrivate* d( const KateDocument* foo ) + { + if ( !d_ptr ) { + d_ptr = new QPtrDict<KateDocPrivate>; + //qAddPostRoutine( cleanup_d_ptr ); + } + KateDocPrivate* ret = d_ptr->find( (void*) foo ); + if ( ! ret ) { + ret = new KateDocPrivate; + d_ptr->replace( (void*) foo, ret ); + } + return ret; + } + +void delete_d( const KateDocument* foo ) + { + if ( d_ptr ) + d_ptr->remove( (void*) foo ); + } + +}; + +#endif + + diff --git a/noncore/apps/tinykate/libkate/document/katedocumentIface.h b/noncore/apps/tinykate/libkate/document/katedocumentIface.h new file mode 100644 index 0000000..51c7506 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katedocumentIface.h @@ -0,0 +1,32 @@ +/*************************************************************************** + katedocumentIface.h - description + ------------------- + copyright : (C) 2001 by The Kate Team + (C) 2002 by Joseph Wenninger + email : kwrite-devel@kde.org + jowenn@kde.org + + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ +#ifndef _KATEDOCUMENT_IFACE_H_ +#define _KATEDOCUMENT_IFACE_H_ + +#include <dcopobject.h> + +class KateDocumentDCOPIface : virtual public DCOPObject +{ + K_DCOP + + k_dcop: + virtual void open (const QString &name=0)=0; +}; +#endif + diff --git a/noncore/apps/tinykate/libkate/document/katehighlight.cpp b/noncore/apps/tinykate/libkate/document/katehighlight.cpp new file mode 100644 index 0000000..797968b --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katehighlight.cpp @@ -0,0 +1,1459 @@ +/* + Copyright (C) 1998, 1999 Jochen Wilhelmy + digisnap@cs.tu-berlin.de + (C) 2002, 2001 The Kate Team <kwrite-devel@kde.org> + (C) 2002 Joseph Wenninger <jowenn@kde.org> + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include <string.h> + +#include <qtextstream.h> +#include <qpe/config.h> +#include <kglobal.h> +//#include <kinstance.h> +//#include <kmimemagic.h> +#include <klocale.h> +//#include <kregexp.h> +#include <kglobalsettings.h> +#include <kdebug.h> +#include <kstddirs.h> + +#include "katehighlight.h" + + +#include "katetextline.h" +#include "katedocument.h" +#include "katesyntaxdocument.h" + + +HlManager *HlManager::s_pSelf = 0; + +enum Item_styles { dsNormal,dsKeyword,dsDataType,dsDecVal,dsBaseN,dsFloat,dsChar,dsString,dsComment,dsOthers}; + +static bool trueBool = true; +static QString stdDeliminator = QString ("!%&()*+,-./:;<=>?[]^{|}~ \t\\"); + +int getDefStyleNum(QString name) +{ + if (name=="dsNormal") return dsNormal; + if (name=="dsKeyword") return dsKeyword; + if (name=="dsDataType") return dsDataType; + if (name=="dsDecVal") return dsDecVal; + if (name=="dsBaseN") return dsBaseN; + if (name=="dsFloat") return dsFloat; + if (name=="dsChar") return dsChar; + if (name=="dsString") return dsString; + if (name=="dsComment") return dsComment; + if (name=="dsOthers") return dsOthers; + + return dsNormal; +} + +bool ustrchr(const QChar *s, uint len, QChar c) +{ + for (int z=0; z < len; z++) + { + if (*s == c) return true; + s++; + } + + return false; +} + +HlItem::HlItem(int attribute, int context) + : attr(attribute), ctx(context) {subItems=0; +} + +HlItem::~HlItem() +{ + //kdDebug(13010)<<"In hlItem::~HlItem()"<<endl; + if (subItems!=0) {subItems->setAutoDelete(true); subItems->clear(); delete subItems;} +} + +bool HlItem::startEnable(QChar c) +{ + return true; +} + +HlCharDetect::HlCharDetect(int attribute, int context, QChar c) + : HlItem(attribute,context), sChar(c) { +} + +const QChar *HlCharDetect::checkHgl(const QChar *str, int len, bool) { + if (*str == sChar) return str + 1; + return 0L; +} + +Hl2CharDetect::Hl2CharDetect(int attribute, int context, QChar ch1, QChar ch2) + : HlItem(attribute,context) { + sChar1 = ch1; + sChar2 = ch2; +} + +const QChar *Hl2CharDetect::checkHgl(const QChar *str, int len, bool) { + if (str[0] == sChar1 && str[1] == sChar2) return str + 2; + return 0L; +} + +HlStringDetect::HlStringDetect(int attribute, int context, const QString &s, bool inSensitive) + : HlItem(attribute, context), str(inSensitive ? s.upper():s), _inSensitive(inSensitive) { +} + +HlStringDetect::~HlStringDetect() { +} + +const QChar *HlStringDetect::checkHgl(const QChar *s, int len, bool) { + if (!_inSensitive) {if (memcmp(s, str.unicode(), str.length()*sizeof(QChar)) == 0) return s + str.length();} + else + { + QString tmp=QString(s,str.length()).upper(); + if (tmp==str) return s+str.length(); + } + return 0L; +} + + +HlRangeDetect::HlRangeDetect(int attribute, int context, QChar ch1, QChar ch2) + : HlItem(attribute,context) { + sChar1 = ch1; + sChar2 = ch2; +} + +const QChar *HlRangeDetect::checkHgl(const QChar *s, int len, bool) { + if (*s == sChar1) + { + do + { + s++; + len--; + if (len == 0) return 0L; + } + while (*s != sChar2); + + return s + 1; + } + return 0L; +} + +HlKeyword::HlKeyword (int attribute, int context,bool casesensitive, const QChar *deliminator, uint deliLen) + : HlItem(attribute,context), dict (113, casesensitive) +{ + deliminatorChars = deliminator; + deliminatorLen = deliLen; + _caseSensitive=casesensitive; +} + +HlKeyword::~HlKeyword() { +} + +bool HlKeyword::startEnable(QChar c) +{ + return ustrchr(deliminatorChars, deliminatorLen, c); +} + +// If we use a dictionary for lookup we don't really need +// an item as such we are using the key to lookup +void HlKeyword::addWord(const QString &word) +{ + words.append(word); + dict.insert(word,&trueBool); +} + +void HlKeyword::addList(const QStringList& list) +{ + + words+=list; + for(uint i=0;i<list.count();i++) dict.insert(list[i], &trueBool); +} + +const QChar *HlKeyword::checkHgl(const QChar *s, int len, bool b) +{ + if (len == 0) return 0L; + + const QChar *s2 = s; + + while ( (len > 0) && (!ustrchr(deliminatorChars, deliminatorLen, *s2)) ) + { + s2++; + len--; + } + + if (s2 == s) return 0L; + + QString lookup = QString(s,s2-s); + + if ( dict.find(lookup) ) return s2; + return 0L; +} + +HlInt::HlInt(int attribute, int context) + : HlItem(attribute,context) { +} + +const QChar *HlInt::checkHgl(const QChar *str, int len, bool) { + const QChar *s,*s1; + + s = str; + while (s->isDigit()) s++; + if (s > str) + { + if (subItems) + { + for (HlItem *it=subItems->first();it;it=subItems->next()) + { + s1=it->checkHgl(s, len, false); + if (s1) return s1; + } + } + return s; + } + return 0L; +} + +HlFloat::HlFloat(int attribute, int context) + : HlItem(attribute,context) { +} + +const QChar *HlFloat::checkHgl(const QChar *s, int len, bool) { + bool b, p; + const QChar *s1; + + b = false; + while (s->isDigit()){ + s++; + b = true; + } + if (p = (*s == '.')) { + s++; + while (s->isDigit()) { + s++; + b = true; + } + } + if (!b) return 0L; + if ((*s&0xdf) == 'E') s++; + else + if (!p) return 0L; + else + { + if (subItems) + { + for (HlItem *it=subItems->first();it;it=subItems->next()) + { + s1=it->checkHgl(s, len, false); + if (s1) return s1; + } + } + return s; + } + if ((*s == '-')||(*s =='+')) s++; + b = false; + while (s->isDigit()) { + s++; + b = true; + } + if (b) + { + if (subItems) + { + for (HlItem *it=subItems->first();it;it=subItems->next()) + { + s1=it->checkHgl(s, len, false); + if (s1) return s1; + } + } + return s; + } + else return 0L; +} + + +HlCInt::HlCInt(int attribute, int context) + : HlInt(attribute,context) { +} + +const QChar *HlCInt::checkHgl(const QChar *s, int len, bool lineStart) { + +// if (*s == '0') s++; else s = HlInt::checkHgl(s); + s = HlInt::checkHgl(s, len, lineStart); + if (s != 0L) { + int l = 0; + int u = 0; + const QChar *str; + + do { + str = s; + if ((*s&0xdf) == 'L' ) { + l++; + if (l > 2) return 0L; + s++; + } + if ((*s&0xdf) == 'U' ){ + u++; + if (u > 1) return 0L; + s++; + } + } while (s != str); + } + return s; +} + +HlCOct::HlCOct(int attribute, int context) + : HlItem(attribute,context) { +} + +const QChar *HlCOct::checkHgl(const QChar *str, int len, bool) { + const QChar *s; + + if (*str == '0') { + str++; + s = str; + while (*s >= '0' && *s <= '7') s++; + if (s > str) { + if ((*s&0xdf) == 'L' || (*s&0xdf) == 'U' ) s++; + return s; + } + } + return 0L; +} + +HlCHex::HlCHex(int attribute, int context) + : HlItem(attribute,context) { +} + +const QChar *HlCHex::checkHgl(const QChar *str, int len, bool) { + const QChar *s=str; +#if 0 + int i; + for (i=0;(*s)!='\0';s++,i++); + QString line(str,i); + QRegExp3 rx("0[xX][a-fA-F\\d]+[UuLl]?"); // this matches but is also matching parenthesis + int pos=rx.search(line,0); + if(pos > -1) return str+rx.matchedLength(); + else + return 0L; + +#else + if (str[0] == '0' && ((str[1]&0xdf) == 'X' )) { + str += 2; + s = str; + while (s->isDigit() || ((*s&0xdf) >= 'A' && (*s&0xdf) <= 'F') /*|| (*s >= 'a' && *s <= 'f')*/) s++; + if (s > str) { + if ((*s&0xdf) == 'L' || (*s&0xdf) == 'U' ) s++; + return s; + } + } + return 0L; +#endif +} + +HlCFloat::HlCFloat(int attribute, int context) + : HlFloat(attribute,context) { +} + +const QChar *HlCFloat::checkHgl(const QChar *s, int len, bool lineStart) { + + s = HlFloat::checkHgl(s, len, lineStart); + if (s && ((*s&0xdf) == 'F' )) s++; + return s; +} + +HlAnyChar::HlAnyChar(int attribute, int context, const QChar* charList, uint len) + : HlItem(attribute, context) { + _charList=charList; + _charListLen=len; +} + +const QChar *HlAnyChar::checkHgl(const QChar *s, int len, bool) +{ + if (ustrchr(_charList, _charListLen, *s)) return s +1; + return 0L; +} + +HlRegExpr::HlRegExpr(int attribute, int context,QString regexp) + : HlItem(attribute, context) { + + handlesLinestart=regexp.startsWith("^"); + if(!handlesLinestart) regexp.prepend("^"); + Expr=new QRegExp3(regexp); +} + +const QChar *HlRegExpr::checkHgl(const QChar *s, int len, bool lineStart) +{ + if ((!lineStart) && handlesLinestart) return 0; + + QString line(s,len); + int pos = Expr->search( line, 0 ); + if (pos==-1) return 0L; + else + return (s+Expr->matchedLength()); +}; + + +HlLineContinue::HlLineContinue(int attribute, int context) + : HlItem(attribute,context) { +} + +const QChar *HlLineContinue::checkHgl(const QChar *s, int len, bool) { + + if ((s[0].latin1() == '\\') && (len == 1)) + { + return s + 1; + } + return 0L; +} + + +HlCStringChar::HlCStringChar(int attribute, int context) + : HlItem(attribute,context) { +} + +//checks for hex and oct (for example \x1b or \033) +const QChar *checkCharHexOct(const QChar *str) { + const QChar *s; + s=str; + int n; + if (*s == 'x') { + n = 0; + do { + s++; + n *= 16; + if (s->isDigit()) n += *s - '0'; + else if ((*s&0xdf) >= 'A' && (*s&0xdf) <= 'F') n += (*s&0xdf) - 'A' + 10; +// else if (*s >= 'a' && *s <= 'f') n += *s - 'a' + 10; + else break; + if (n >= 256) return 0L; + } while (true); + if (s - str == 1) return 0L; + } else { + if (!(*s >= '0' && *s <= '7')) return 0L; + n = *s - '0'; + do { + s++; + n *= 8; + if (*s >= '0' && *s <= '7') n += *s - '0'; else break; + if (n >= 256) return s; + } while (s - str < 3); + } + return s; +} +// checks for C escaped chars \n and escaped hex/octal chars +const QChar *checkEscapedChar(const QChar *s, int len) { + int i; + if (s[0] == '\\' && (len > 1) ) { + s++; + switch(*s){ + case 'a': // checks for control chars + case 'b': // we want to fall through + case 'e': + case 'f': + + case 'n': + case 'r': + case 't': + case 'v': + case '\'': + case '\"': + case '?' : // added ? ANSI C classifies this as an escaped char + case '\\': s++; + break; + case 'x': // if it's like \xff + s++; // eat the x + // these for loops can probably be + // replaced with something else but + // for right now they work + // check for hexdigits + for(i=0;i<2 &&(*s >= '0' && *s <= '9' || (*s&0xdf) >= 'A' && (*s&0xdf) <= 'F');i++,s++); + if(i==0) return 0L; // takes care of case '\x' + break; + + case '0': case '1': case '2': case '3' : + case '4': case '5': case '6': case '7' : + for(i=0;i < 3 &&(*s >='0'&& *s<='7');i++,s++); + break; + default: return 0L; + } + return s; + } + return 0L; +} + +const QChar *HlCStringChar::checkHgl(const QChar *str, int len, bool) { + return checkEscapedChar(str, len); +} + + +HlCChar::HlCChar(int attribute, int context) + : HlItem(attribute,context) { +} + +const QChar *HlCChar::checkHgl(const QChar *str, int len, bool) { + const QChar *s; + + if ((len > 1) && (str[0] == '\'') && (str[1] != '\'')) + { + s = checkEscapedChar(&str[1], len); //try to match escaped char + if (!s) s = &str[2]; //match single non-escaped char + if (*s == '\'') return s + 1; + } + return 0L; +} + + +//-------- +ItemStyle::ItemStyle() : selCol(Qt::white), bold(false), italic(false) { +} + +ItemStyle::ItemStyle(const QColor &col, const QColor &selCol, + bool bold, bool italic) + : col(col), selCol(selCol), bold(bold), italic(italic) { +} + +ItemData::ItemData(const QString name, int defStyleNum) + : name(name), defStyleNum(defStyleNum), defStyle(true) { +} + +ItemData::ItemData(const QString name, int defStyleNum, + const QColor &col, const QColor &selCol, bool bold, bool italic) + : ItemStyle(col,selCol,bold,italic), name(name), defStyleNum(defStyleNum), + defStyle(false) { +} + +HlData::HlData(const QString &wildcards, const QString &mimetypes, const QString &identifier) + : wildcards(wildcards), mimetypes(mimetypes), identifier(identifier) { + +//JW itemDataList.setAutoDelete(true); +} + +HlContext::HlContext(int attribute, int lineEndContext, int _lineBeginContext) + : attr(attribute), ctx(lineEndContext),lineBeginContext(_lineBeginContext) { + items.setAutoDelete(true); +} + +Hl2CharDetect::Hl2CharDetect(int attribute, int context, const QChar *s) + : HlItem(attribute,context) { + sChar1 = s[0]; + sChar2 = s[1]; +} + +Highlight::Highlight(syntaxModeListItem *def) : refCount(0) +{ + noHl = false; + + if (def == 0) + { + noHl = true; + iName = I18N_NOOP("Normal"); + iSection = ""; + } + else + { + iName = def->name; + iSection = def->section; + iWildcards = def->extension; + iMimetypes = def->mimetype; + identifier = def->identifier; + } + deliminator = stdDeliminator; + deliminatorChars = deliminator.unicode(); + deliminatorLen = deliminator.length(); +} + +Highlight::~Highlight() +{ +} + +int Highlight::doHighlight(int ctxNum, TextLine *textLine) +{ + if (noHl) + { + textLine->setAttribs(0,0,textLine->length()); + textLine->setAttr(0); + return 0; + } + + HlContext *context; + const QChar *s2; + HlItem *item; + + context = contextList[ctxNum]; + if (context->lineBeginContext!=-1) + { + ctxNum=context->lineBeginContext; + context=contextList[ctxNum]; + } + + QChar lastChar = ' '; + + // first char + const QChar *str = textLine->getText(); + + // non space char - index of that char + const QChar *s1 = textLine->firstNonSpace(); + uint z = textLine->firstChar(); + + // length of textline + uint len = textLine->length(); + + bool found = false; + while (z < len) + { + found = false; + + for (item = context->items.first(); item != 0L; item = context->items.next()) + { + if (item->startEnable(lastChar)) + { + s2 = item->checkHgl(s1, len-z, z==0); + if (s2 > s1) + { + qDebug("An item has been detected"); + textLine->setAttribs(item->attr,s1 - str,s2 - str); + ctxNum = item->ctx; + context = contextList[ctxNum]; + z = z + s2 - s1 - 1; + s1 = s2 - 1; + found = true; + break; + } + } + } + + // nothing found: set attribute of one char + if (!found) + textLine->setAttribs(context->attr,s1 - str,s1 - str + 1); + + lastChar = *s1; + s1++; + z++; + } + + //set "end of line"-properties + textLine->setAttr(context->attr); + + //return new context + return context->ctx; +} + +KConfig *Highlight::getKConfig() { + KConfig *config; + config=KGlobal::config(); + config->setGroup(iName + QString(" Highlight")); + return config; +} + +QString Highlight::getWildcards() { + KConfig *config; + + config = getKConfig(); + + //if wildcards not yet in config, then use iWildCards as default + return config->readEntry("Wildcards", iWildcards); +} + + +QString Highlight::getMimetypes() { + KConfig *config; + + config = getKConfig(); + + return config->readEntry("Mimetypes", iMimetypes); +} + + +HlData *Highlight::getData() { + KConfig *config; + HlData *hlData; + + config = getKConfig(); + +// iWildcards = config->readEntry("Wildcards"); +// iMimetypes = config->readEntry("Mimetypes"); +// hlData = new HlData(iWildcards,iMimetypes); + hlData = new HlData( + config->readEntry("Wildcards", iWildcards), + config->readEntry("Mimetypes", iMimetypes), + config->readEntry("Identifier", identifier)); + getItemDataList(hlData->itemDataList, config); + return hlData; +} + +void Highlight::setData(HlData *hlData) { + KConfig *config; + + config = getKConfig(); + +// iWildcards = hlData->wildcards; +// iMimetypes = hlData->mimetypes; + + config->writeEntry("Wildcards",hlData->wildcards); + config->writeEntry("Mimetypes",hlData->mimetypes); + + setItemDataList(hlData->itemDataList,config); +} + +void Highlight::getItemDataList(ItemDataList &list) { + KConfig *config; + + config = getKConfig(); + getItemDataList(list, config); +} + +void Highlight::getItemDataList(ItemDataList &list, KConfig *config) { + ItemData *p; + QString s; + QRgb col, selCol; + + list.clear(); +//JW list.setAutoDelete(true); + createItemData(list); + + for (p = list.first(); p != 0L; p = list.next()) { + s = config->readEntry(p->name); + if (!s.isEmpty()) { + sscanf(s.latin1(),"%d,%X,%X,%d,%d", &p->defStyle,&col,&selCol,&p->bold,&p->italic); + p->col.setRgb(col); + p->selCol.setRgb(selCol); + } + } +} + +/******************************************************************************************* + Highlight - setItemDataList + saves the ItemData / attribute / style definitions to the apps configfile. + Especially needed for user overridden values. + + * input: ItemDataList &list :reference to the list, whose + * items should be saved + * KConfig *config :Pointer KDE configuration + * class, which should be used + * as storage + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::setItemDataList(ItemDataList &list, KConfig *config) { + ItemData *p; + QString s; + + for (p = list.first(); p != 0L; p = list.next()) { + s.sprintf("%d,%X,%X,%d,%d", + p->defStyle,p->col.rgb(),p->selCol.rgb(),p->bold,p->italic); + config->writeEntry(p->name,s); + } +} + + +/******************************************************************************************* + Highlight - use + Increase the usage count and trigger initialization if needed + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::use() +{ + if (refCount == 0) init(); + refCount++; +} + + +/******************************************************************************************* + Highlight - release + Decrease the usage count and trigger a cleanup if needed + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::release() +{ + refCount--; + if (refCount == 0) done(); +} + +/******************************************************************************************* + Highlight - init + If it's the first time a particular highlighting is used create the needed contextlist + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::init() +{ + if (noHl) + return; + + for (int z = 0; z < nContexts; z++) contextList[z] = 0L; + makeContextList(); +} + + +/******************************************************************************************* + Highlight - done + If the there is no document using the highlighting style free the complete context + structure. + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::done() +{ + if (noHl) + return; + + for (int z = 0; z < nContexts; z++) delete contextList[z]; +} + + +/******************************************************************************************* + Highlight - createItemData + This function reads the itemData entries from the config file, which specifies the + default attribute styles for matched items/contexts. + + * input: none + ************* + * output: ItemDataList &list :A reference to the internal + list containing the parsed + default config + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::createItemData(ItemDataList &list) +{ + qDebug("Highlight::createItemData"); + + // If no highlighting is selected we need only one default. + if (noHl) + { + list.append(new ItemData(I18N_NOOP("Normal Text"), dsNormal)); + return; + } + + QString color; + QString selColor; + QString bold; + QString italic; + + // If the internal list isn't already available read the config file + if (internalIDList.count()==0) + { + //if all references to the list are destried the contents will also be deleted + internalIDList.setAutoDelete(true); + syntaxContextData *data; + + qDebug("Trying to read itemData section"); + + //Tell the syntax document class which file we want to parse and which data group + HlManager::self()->syntax->setIdentifier(identifier); + data=HlManager::self()->syntax->getGroupInfo("highlighting","itemData"); + //begin with the real parsing + while (HlManager::self()->syntax->nextGroup(data)) + { + qDebug("Setting up one itemData element"); + // read all attributes + color=HlManager::self()->syntax->groupData(data,QString("color")); + selColor=HlManager::self()->syntax->groupData(data,QString("selColor")); + bold=HlManager::self()->syntax->groupData(data,QString("bold")); + italic=HlManager::self()->syntax->groupData(data,QString("italic")); + //check if the user overrides something + if ( (!color.isEmpty()) && (!selColor.isEmpty()) && (!bold.isEmpty()) && (!italic.isEmpty())) + { + //create a user defined style + internalIDList.append(new ItemData( + HlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), + getDefStyleNum(HlManager::self()->syntax->groupData(data,QString("defStyleNum"))), + QColor(color),QColor(selColor),(bold=="true") || (bold=="1"), (italic=="true") || (italic=="1") + )); + } + else + { + //assign a default style + internalIDList.append(new ItemData( + HlManager::self()->syntax->groupData(data,QString("name")).simplifyWhiteSpace(), + getDefStyleNum(HlManager::self()->syntax->groupData(data,QString("defStyleNum"))))); + + } + } + //clean up + if (data) HlManager::self()->syntax->freeGroupInfo(data); + } + + //set the ouput reference + list=internalIDList; +} + + +/******************************************************************************************* + Highlight - lookupAttrName + This function is a helper for makeContextList and createHlItem. It looks the given + attribute name in the itemData list up and returns it's index + + * input: QString &name :the attribute name to lookup + * ItemDataList &iDl :the list containing all + * available attributes + ************* + * output: none + ************* + * return value: int :The index of the attribute + * or 0 +*******************************************************************************************/ + +int Highlight::lookupAttrName(const QString& name, ItemDataList &iDl) +{ + for (int i=0;i<iDl.count();i++) + { + if (iDl.at(i)->name==name) return i; + } + kdDebug(13010)<<"Couldn't resolve itemDataName"<<endl; + return 0; +} + + +/******************************************************************************************* + Highlight - createHlItem + This function is a helper for makeContextList. It parses the xml file for + information, how single or multi line comments are marked + + * input: syntaxContextData *data : Data about the item read from + * the xml file + * ItemDataList &iDl : List of all available itemData + * entries. Needed for attribute + * name->index translation + ************* + * output: none + ************* + * return value: HlItem * : Pointer to the newly created item + * object +*******************************************************************************************/ + +HlItem *Highlight::createHlItem(syntaxContextData *data, ItemDataList &iDl) +{ + // No highlighting -> exit + if (noHl) + return 0; + + // get the (tagname) itemd type + QString dataname=HlManager::self()->syntax->groupItemData(data,QString("")); + + // BEGIN - Translation of the attribute parameter + QString tmpAttr=HlManager::self()->syntax->groupItemData(data,QString("attribute")).simplifyWhiteSpace(); + int attr; + if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) + attr=tmpAttr.toInt(); + else + attr=lookupAttrName(tmpAttr,iDl); + // END - Translation of the attribute parameter + + // Info about context switch + int context=((HlManager::self()->syntax->groupItemData(data,QString("context"))).toInt()); + + // Get the char parameter (eg DetectChar) + char chr; + if (! HlManager::self()->syntax->groupItemData(data,QString("char")).isEmpty()) + chr= (HlManager::self()->syntax->groupItemData(data,QString("char")).latin1())[0]; + else + chr=0; + + // Get the String parameter (eg. StringDetect) + QString stringdata=HlManager::self()->syntax->groupItemData(data,QString("String")); + + // Get a second char parameter (char1) (eg Detect2Chars) + char chr1; + if (! HlManager::self()->syntax->groupItemData(data,QString("char1")).isEmpty()) + chr1= (HlManager::self()->syntax->groupItemData(data,QString("char1")).latin1())[0]; + else + chr1=0; + + // Will be removed eventuall. Atm used for StringDetect + bool insensitive=(HlManager::self()->syntax->groupItemData(data,QString("insensitive"))==QString("TRUE")); + + + //Create the item corresponding to it's type and set it's parameters + if (dataname=="keyword") + { + HlKeyword *keyword=new HlKeyword(attr,context,casesensitive, + deliminatorChars, deliminatorLen); + + //Get the entries for the keyword lookup list + keyword->addList(HlManager::self()->syntax->finddata("highlighting",stringdata)); + return keyword; + } else + if (dataname=="Float") return (new HlFloat(attr,context)); else + if (dataname=="Int") return(new HlInt(attr,context)); else + if (dataname=="DetectChar") return(new HlCharDetect(attr,context,chr)); else + if (dataname=="Detect2Chars") return(new Hl2CharDetect(attr,context,chr,chr1)); else + if (dataname=="RangeDetect") return(new HlRangeDetect(attr,context, chr, chr1)); else + if (dataname=="LineContinue") return(new HlLineContinue(attr,context)); else + if (dataname=="StringDetect") return(new HlStringDetect(attr,context,stringdata,insensitive)); else + if (dataname=="AnyChar") return(new HlAnyChar(attr,context,stringdata.unicode(), stringdata.length())); else + if (dataname=="RegExpr") return(new HlRegExpr(attr,context,stringdata)); else + if(dataname=="HlCChar") return ( new HlCChar(attr,context));else + if(dataname=="HlCHex") return (new HlCHex(attr,context));else + if(dataname=="HlCOct") return (new HlCOct(attr,context)); else + if(dataname=="HlCStringChar") return (new HlCStringChar(attr,context)); else + + { + // oops, unknown type. Perhaps a spelling error in the xml file + return 0; + } + + +} + + +/******************************************************************************************* + Highlight - isInWord + + * input: Qchar c Character to investigate + ************* + * output: none + ************* + * return value: returns true, if c is no deliminator +*******************************************************************************************/ + +bool Highlight::isInWord(QChar c) +{ + return !ustrchr(deliminatorChars, deliminatorLen, c); +} + + + +/******************************************************************************************* + Highlight - readCommentConfig + This function is a helper for makeContextList. It parses the xml file for + information, how single or multi line comments are marked + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + +void Highlight::readCommentConfig() +{ + + cslStart = ""; + HlManager::self()->syntax->setIdentifier(identifier); + + syntaxContextData *data=HlManager::self()->syntax->getGroupInfo("general","comment"); + if (data) + { +// kdDebug(13010)<<"COMMENT DATA FOUND"<<endl; + while (HlManager::self()->syntax->nextGroup(data)) + { + + if (HlManager::self()->syntax->groupData(data,"name")=="singleLine") + cslStart=HlManager::self()->syntax->groupData(data,"start"); + if (HlManager::self()->syntax->groupData(data,"name")=="multiLine") + { + cmlStart=HlManager::self()->syntax->groupData(data,"start"); + cmlEnd=HlManager::self()->syntax->groupData(data,"end"); + } + } + HlManager::self()->syntax->freeGroupInfo(data); + } + +} + +/******************************************************************************************* + Highlight - readGlobalKeyWordConfig + This function is a helper for makeContextList. It parses the xml file for + information, if keywords should be treated case(in)sensitive and creates the keyword + delimiter list. Which is the default list, without any given weak deliminiators + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + + +void Highlight::readGlobalKeywordConfig() +{ + // Tell the syntax document class which file we want to parse + HlManager::self()->syntax->setIdentifier(identifier); + + // Get the keywords config entry + syntaxContextData * data=HlManager::self()->syntax->getConfig("general","keywords"); + if (data) + { + kdDebug(13010)<<"Found global keyword config"<<endl; + + if (HlManager::self()->syntax->groupItemData(data,QString("casesensitive"))!="0") + casesensitive=true; else {casesensitive=false; kdDebug(13010)<<"Turning on case insensitiveness"<<endl;} + //get the weak deliminators + weakDeliminator=(!HlManager::self()->syntax->groupItemData(data,QString("weakDeliminator"))); + + // remove any weakDelimitars (if any) from the default list and store this list. + int f; + for (int s=0; s < weakDeliminator.length(); s++) + { + f = 0; + f = deliminator.find (weakDeliminator[s]); + + if (f > -1) + deliminator.remove (f, 1); + } + + deliminatorChars = deliminator.unicode(); + deliminatorLen = deliminator.length(); + + HlManager::self()->syntax->freeGroupInfo(data); + } + else + { + //Default values + casesensitive=true; + weakDeliminator=QString(""); + } + +} + +/******************************************************************************************* + Highlight - makeContextList + That's the most important initialization function for each highlighting. It's called + each time a document gets a highlighting style assigned. parses the xml file and + creates a corresponding internal structure + + * input: none + ************* + * output: none + ************* + * return value: none +*******************************************************************************************/ + + +void Highlight::makeContextList() +{ + if (noHl) + return; + + HlKeyword *keyword=0, *dataType=0; + syntaxContextData *data, *datasub; + HlItem *c; + + readCommentConfig(); + readGlobalKeywordConfig(); + + // Let the syntax document class know, which file we'd like to parse + HlManager::self()->syntax->setIdentifier(identifier); + + // This list is needed for the translation of the attribute parameter, if the itemData name is given instead of the index + ItemDataList iDl; + createItemData(iDl); + + //start the real work + data=HlManager::self()->syntax->getGroupInfo("highlighting","context"); + int i=0; + if (data) + { + while (HlManager::self()->syntax->nextGroup(data)) + { + + // BEGIN - Translation of the attribute parameter + QString tmpAttr=HlManager::self()->syntax->groupData(data,QString("attribute")).simplifyWhiteSpace(); + int attr; + if (QString("%1").arg(tmpAttr.toInt())==tmpAttr) + attr=tmpAttr.toInt(); + else + attr=lookupAttrName(tmpAttr,iDl); + // END - Translation of the attribute parameter + + contextList[i]=new HlContext( + attr, + (HlManager::self()->syntax->groupData(data,QString("lineEndContext"))).toInt(), + (HlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).isEmpty()?-1: + (HlManager::self()->syntax->groupData(data,QString("lineBeginContext"))).toInt()); + + + //Let's create all items for the context + while (HlManager::self()->syntax->nextItem(data)) + { +// kdDebug(13010)<< "In make Contextlist: Item:"<<endl; + c=createHlItem(data,iDl); + if (c) + { + contextList[i]->items.append(c); + + // Not supported completely atm and only one level. Subitems.(all have to be matched to at once) + datasub=HlManager::self()->syntax->getSubItems(data); + bool tmpbool; + if (tmpbool=HlManager::self()->syntax->nextItem(datasub)) + { + c->subItems=new QList<HlItem>; + for (;tmpbool;tmpbool=HlManager::self()->syntax->nextItem(datasub)) + c->subItems->append(createHlItem(datasub,iDl)); + } + HlManager::self()->syntax->freeGroupInfo(datasub); + // end of sublevel + } +// kdDebug(13010)<<"Last line in loop"<<endl; + } + i++; + } + } + + HlManager::self()->syntax->freeGroupInfo(data); + + +} + +HlManager::HlManager() : QObject(0L) +{ + syntax = new SyntaxDocument(); + SyntaxModeList modeList = syntax->modeList(); + + hlList.setAutoDelete(true); + hlList.append(new Highlight(0)); + + uint i=0; + while (i < modeList.count()) + { + hlList.append(new Highlight(modeList.at(i))); + i++; + } +} + +HlManager::~HlManager() { + if(syntax) delete syntax; +} + +HlManager *HlManager::self() +{ + if ( !s_pSelf ) + s_pSelf = new HlManager; + return s_pSelf; +} + +Highlight *HlManager::getHl(int n) { + if (n < 0 || n >= (int) hlList.count()) n = 0; + return hlList.at(n); +} + +int HlManager::defaultHl() { + KConfig *config; + config = KGlobal::config(); + config->setGroup("General Options"); + +#warning fixme return nameFind(config->readEntry("Highlight")); + +} + + +int HlManager::nameFind(const QString &name) { + int z; + + for (z = hlList.count() - 1; z > 0; z--) { + if (hlList.at(z)->iName == name) break; + } + return z; +} + +int HlManager::wildcardFind(const QString &fileName) { + Highlight *highlight; + int p1, p2; + QString w; + for (highlight = hlList.first(); highlight != 0L; highlight = hlList.next()) { + p1 = 0; + w = highlight->getWildcards(); + while (p1 < (int) w.length()) { + p2 = w.find(';',p1); + if (p2 == -1) p2 = w.length(); + if (p1 < p2) { + QRegExp regExp(w.mid(p1,p2 - p1),true,true); + if (regExp.match(fileName) == 0) return hlList.at(); + } + p1 = p2 + 1; + } + } + return -1; +} + + +int HlManager::makeAttribs(Highlight *highlight, Attribute *a, int maxAttribs) { + ItemStyleList defaultStyleList; + ItemStyle *defaultStyle; + ItemDataList itemDataList; + ItemData *itemData; + int nAttribs, z; + + qDebug("HlManager::makeAttribs"); + + defaultStyleList.setAutoDelete(true); + getDefaults(defaultStyleList); + +// itemDataList.setAutoDelete(true); + highlight->getItemDataList(itemDataList); + nAttribs = itemDataList.count(); + for (z = 0; z < nAttribs; z++) { + qDebug("HlManager::makeAttribs: createing one attribute definition"); + itemData = itemDataList.at(z); + if (itemData->defStyle) { + // default style + defaultStyle = defaultStyleList.at(itemData->defStyleNum); + a[z].col = defaultStyle->col; + a[z].selCol = defaultStyle->selCol; + a[z].bold = defaultStyle->bold; + a[z].italic = defaultStyle->italic; + } else { + // custom style + a[z].col = itemData->col; + a[z].selCol = itemData->selCol; + a[z].bold = itemData->bold; + a[z].italic = itemData->italic; + } + } + + for (; z < maxAttribs; z++) { + a[z].col = black; + a[z].selCol = black; + a[z].bold = defaultStyle->bold; + a[z].italic = defaultStyle->italic; + } + return nAttribs; +} + +int HlManager::defaultStyles() { + return 10; +} + +QString HlManager::defaultStyleName(int n) +{ + static QStringList names; + + if (names.isEmpty()) + { + names << i18n("Normal"); + names << i18n("Keyword"); + names << i18n("Data Type"); + names << i18n("Decimal/Value"); + names << i18n("Base-N Integer"); + names << i18n("Floating Point"); + names << i18n("Character"); + names << i18n("String"); + names << i18n("Comment"); + names << i18n("Others"); + } + + return names[n]; +} + +void HlManager::getDefaults(ItemStyleList &list) { + KConfig *config; + int z; + ItemStyle *i; + QString s; + QRgb col, selCol; + + list.setAutoDelete(true); + //ItemStyle(color, selected color, bold, italic) + list.append(new ItemStyle(black,white,false,false)); //normal + list.append(new ItemStyle(black,white,true,false)); //keyword + list.append(new ItemStyle(darkRed,white,false,false)); //datatype + list.append(new ItemStyle(blue,cyan,false,false)); //decimal/value + list.append(new ItemStyle(darkCyan,cyan,false,false)); //base n + list.append(new ItemStyle(darkMagenta,cyan,false,false));//float + list.append(new ItemStyle(magenta,magenta,false,false)); //char + list.append(new ItemStyle(red,red,false,false)); //string + list.append(new ItemStyle(darkGray,gray,false,true)); //comment + list.append(new ItemStyle(darkGreen,green,false,false)); //others + +#warning fixme +/* + config = KateFactory::instance()->config(); + config->setGroup("Default Item Styles"); + for (z = 0; z < defaultStyles(); z++) { + i = list.at(z); + s = config->readEntry(defaultStyleName(z)); + if (!s.isEmpty()) { + sscanf(s.latin1(),"%X,%X,%d,%d",&col,&selCol,&i->bold,&i->italic); + i->col.setRgb(col); + i->selCol.setRgb(selCol); + } + } +*/ +} + +void HlManager::setDefaults(ItemStyleList &list) { + KConfig *config; + int z; + ItemStyle *i; + char s[64]; +#warning fixme +/* + config = KateFactory::instance()->config(); + config->setGroup("Default Item Styles"); + for (z = 0; z < defaultStyles(); z++) { + i = list.at(z); + sprintf(s,"%X,%X,%d,%d",i->col.rgb(),i->selCol.rgb(),i->bold, i->italic); + config->writeEntry(defaultStyleName(z),s); + } +*/ + emit changed(); +} + + +int HlManager::highlights() { + return (int) hlList.count(); +} + +QString HlManager::hlName(int n) { + return hlList.at(n)->iName; +} + +QString HlManager::hlSection(int n) { + return hlList.at(n)->iSection; +} + +void HlManager::getHlDataList(HlDataList &list) { + int z; + + for (z = 0; z < (int) hlList.count(); z++) { + list.append(hlList.at(z)->getData()); + } +} + +void HlManager::setHlDataList(HlDataList &list) { + int z; + + for (z = 0; z < (int) hlList.count(); z++) { + hlList.at(z)->setData(list.at(z)); + } + //notify documents about changes in highlight configuration + emit changed(); +} diff --git a/noncore/apps/tinykate/libkate/document/katehighlight.h b/noncore/apps/tinykate/libkate/document/katehighlight.h new file mode 100644 index 0000000..1baddcc --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katehighlight.h @@ -0,0 +1,349 @@ +/* + Copyright (C) 1998, 1999 Jochen Wilhelmy + digisnap@cs.tu-berlin.de + (C) 2002, 2001 The Kate Team <kwrite-devel@kde.org> + (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _HIGHLIGHT_H_ +#define _HIGHLIGHT_H_ + +#include <qlist.h> +#include <qdialog.h> + +#include <kcolorbtn.h> +#include <qstrvec.h> +#include <qdict.h> +#include <qregexp.h> +#include "../qt3back/qregexp3.h" +#include <kdebug.h> + +class SyntaxDocument; +struct syntaxModeListItem; +struct syntaxContextData; + +class QCheckBox; +class QComboBox; +class QLineEdit; + +class TextLine; +class Attribute; + +class HlItem { + public: + HlItem(int attribute, int context); + virtual ~HlItem(); + virtual bool startEnable(QChar); + virtual const QChar *checkHgl(const QChar *, int len, bool) = 0; + QList<HlItem> *subItems; + int attr; + int ctx; +}; + +class HlCharDetect : public HlItem { + public: + HlCharDetect(int attribute, int context, QChar); + virtual const QChar *checkHgl(const QChar *, int len, bool); + protected: + QChar sChar; +}; + +class Hl2CharDetect : public HlItem { + public: + Hl2CharDetect(int attribute, int context, QChar ch1, QChar ch2); + Hl2CharDetect(int attribute, int context, const QChar *ch); + + virtual const QChar *checkHgl(const QChar *, int len, bool); + protected: + QChar sChar1; + QChar sChar2; +}; + +class HlStringDetect : public HlItem { + public: + HlStringDetect(int attribute, int context, const QString &, bool inSensitive=false); + virtual ~HlStringDetect(); + virtual const QChar *checkHgl(const QChar *, int len, bool); + protected: + const QString str; + bool _inSensitive; +}; + +class HlRangeDetect : public HlItem { + public: + HlRangeDetect(int attribute, int context, QChar ch1, QChar ch2); + virtual const QChar *checkHgl(const QChar *, int len, bool); + protected: + QChar sChar1; + QChar sChar2; +}; + +class HlKeyword : public HlItem +{ + public: + HlKeyword(int attribute, int context,bool casesensitive, const QChar *deliminator, uint deliLen); + virtual ~HlKeyword(); + + virtual void addWord(const QString &); + virtual void addList(const QStringList &); + virtual const QChar *checkHgl(const QChar *, int len, bool); + QStringList getList() { return words;}; + virtual bool startEnable(QChar c); + + protected: + QStringList words; + QDict<bool> dict; + bool _caseSensitive; + const QChar *deliminatorChars; + uint deliminatorLen; +}; + +class HlPHex : public HlItem { + public: + HlPHex(int attribute,int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; +class HlInt : public HlItem { + public: + HlInt(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlFloat : public HlItem { + public: + HlFloat(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlCInt : public HlInt { + public: + HlCInt(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlCOct : public HlItem { + public: + HlCOct(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlCHex : public HlItem { + public: + HlCHex(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlCFloat : public HlFloat { + public: + HlCFloat(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlLineContinue : public HlItem { + public: + HlLineContinue(int attribute, int context); + virtual bool endEnable(QChar c) {return c == '\0';} + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlCStringChar : public HlItem { + public: + HlCStringChar(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlCChar : public HlItem { + public: + HlCChar(int attribute, int context); + virtual const QChar *checkHgl(const QChar *, int len, bool); +}; + +class HlAnyChar : public HlItem { + public: + HlAnyChar(int attribute, int context, const QChar* charList, uint len); + virtual const QChar *checkHgl(const QChar *, int len, bool); + const QChar* _charList; + uint _charListLen; +}; + +class HlRegExpr : public HlItem { + public: + HlRegExpr(int attribute, int context,QString expr); + ~HlRegExpr(){delete Expr;}; + virtual const QChar *checkHgl(const QChar *, int len, bool); + QRegExp3 *Expr; + bool handlesLinestart; +}; + +//-------- + + +//Item Style: color, selected color, bold, italic +class ItemStyle { + public: + ItemStyle(); +// ItemStyle(const ItemStyle &); + ItemStyle(const QColor &, const QColor &, bool bold, bool italic); + ItemStyle(ItemStyle *its){col=its->col;selCol=its->selCol; bold=its->bold; italic=its->italic;} +// void setData(const ItemStyle &); + QColor col; + QColor selCol; + int bold; //boolean value + int italic; //boolean value +}; + +typedef QList<ItemStyle> ItemStyleList; + +//Item Properties: name, Item Style, Item Font +class ItemData : public ItemStyle { + public: + ItemData(const QString name, int defStyleNum); + ItemData(const QString name, int defStyleNum, + const QColor&, const QColor&, bool bold, bool italic); + ItemData(ItemData +*itd):ItemStyle((ItemStyle*)itd),name(itd->name),defStyleNum(itd->defStyleNum),defStyle(itd->defStyle){;} + const QString name; + int defStyleNum; + int defStyle; //boolean value +}; + +typedef QList<ItemData> ItemDataList; + +class HlData { + public: + HlData(const QString &wildcards, const QString &mimetypes,const QString &identifier); + ItemDataList itemDataList; + QString wildcards; + QString mimetypes; + QString identifier; +}; + +typedef QList<HlData> HlDataList; + +class HlManager; +class KConfig; + +//context +class HlContext { + public: + HlContext(int attribute, int lineEndContext,int _lineBeginContext); + QList<HlItem> items; + int attr; + int ctx; + int lineBeginContext; +}; + +class Highlight +{ + friend class HlManager; + + public: + Highlight(syntaxModeListItem *def); + ~Highlight(); + + int doHighlight(int ctxNum, TextLine *); + + KConfig *getKConfig(); + QString getWildcards(); + QString getMimetypes(); + HlData *getData(); + void setData(HlData *); + void getItemDataList(ItemDataList &); + void getItemDataList(ItemDataList &, KConfig *); + void setItemDataList(ItemDataList &, KConfig *); + QString name() {return iName;} + QString section() {return iSection;} + void use(); + void release(); + bool isInWord(QChar c); + + QString getCommentStart() {return cmlStart;}; + QString getCommentEnd() {return cmlEnd;}; + QString getCommentSingleLineStart() { return cslStart;}; + + protected: + void init(); + void done(); + void makeContextList (); + void createItemData (ItemDataList &list); + void readGlobalKeywordConfig(); + void readCommentConfig(); + HlItem *createHlItem(struct syntaxContextData *data, ItemDataList &iDl); + int lookupAttrName(const QString& name, ItemDataList &iDl); + ItemDataList internalIDList; + static const int nContexts = 32; + HlContext *contextList[nContexts]; + + bool noHl; + bool casesensitive; + QString weakDeliminator; + QString deliminator; + const QChar *deliminatorChars; + uint deliminatorLen; + QString cmlStart; + QString cmlEnd; + QString cslStart; + QString iName; + QString iSection; + QString iWildcards; + QString iMimetypes; + QString identifier; + int refCount; +}; + +class HlManager : public QObject { + Q_OBJECT + public: + HlManager(); + ~HlManager(); + + static HlManager *self(); + + Highlight *getHl(int n); + int defaultHl(); + int nameFind(const QString &name); + + int wildcardFind(const QString &fileName); + int findHl(Highlight *h) {return hlList.find(h);} + + int makeAttribs(Highlight *, Attribute *, int maxAttribs); + + int defaultStyles(); + QString defaultStyleName(int n); + void getDefaults(ItemStyleList &); + void setDefaults(ItemStyleList &); + + int highlights(); + QString hlName(int n); + QString hlSection(int n); + void getHlDataList(HlDataList &); + void setHlDataList(HlDataList &); + + SyntaxDocument *syntax; + + signals: + void changed(); + protected: + QList<Highlight> hlList; + static HlManager *s_pSelf; +}; + + + + +#endif //_HIGHLIGHT_H_ diff --git a/noncore/apps/tinykate/libkate/document/katesyntaxdocument.cpp b/noncore/apps/tinykate/libkate/document/katesyntaxdocument.cpp new file mode 100644 index 0000000..c51221b --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katesyntaxdocument.cpp @@ -0,0 +1,306 @@ +/*************************************************************************** + katesyntaxdocument.cpp - description + ------------------- + begin : Sat 31 March 2001 + copyright : (C) 2001,2002 by Joseph Wenninger + email : jowenn@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#include "katesyntaxdocument.h" +#include <qfile.h> +#include <kdebug.h> +#include <kstddirs.h> +#include <klocale.h> +#include <kmessagebox.h> +#include <qstringlist.h> +#include <kconfig.h> +#include <kglobal.h> + + + +SyntaxDocument::SyntaxDocument() +{ + m_root=0; + currentFile=""; + setupModeList(); +} + +void SyntaxDocument::setIdentifier(const QString& identifier) +{ +#warning FIXME delete m_root; + m_root=Opie::XMLElement::load(identifier); + if (!m_root) KMessageBox::error( 0L, i18n("Can't open %1").arg(identifier) ); + +} + +SyntaxDocument::~SyntaxDocument() +{ +} + +void SyntaxDocument::setupModeList(bool force) +{ + + if (myModeList.count() > 0) return; + + KConfig *config=KGlobal::config(); + KStandardDirs *dirs = KGlobal::dirs(); + + QStringList list=dirs->findAllResources("data","kate/syntax/*.xml",false,true); + + for ( QStringList::Iterator it = list.begin(); it != list.end(); ++it ) + { + QString Group="Highlighting_Cache"+*it; + + if ((config->hasGroup(Group)) && (!force)) + { + config->setGroup(Group); + syntaxModeListItem *mli=new syntaxModeListItem; + mli->name = config->readEntry("name",""); + mli->section = config->readEntry("section",""); + mli->mimetype = config->readEntry("mimetype",""); + mli->extension = config->readEntry("extension",""); + mli->identifier = *it; + myModeList.append(mli); + } + else + { + qDebug("Found a description file:"+(*it)); + setIdentifier(*it); + Opie::XMLElement *e=m_root; + if (e) + { + e=e->firstChild(); + qDebug(e->tagName()); + if (e->tagName()=="language") + { + syntaxModeListItem *mli=new syntaxModeListItem; + mli->name = e->attribute("name"); + mli->section = e->attribute("section"); + mli->mimetype = e->attribute("mimetype"); + mli->extension = e->attribute("extensions"); + qDebug(QString("valid description for: %1/%2").arg(mli->section).arg(mli->name)); + if (mli->section.isEmpty()) + mli->section=i18n("Other"); + + mli->identifier = *it; +#warning fixme +/* + config->setGroup(Group); + config->writeEntry("name",mli->name); + config->writeEntry("section",mli->section); + config->writeEntry("mimetype",mli->mimetype); + config->writeEntry("extension",mli->extension); +*/ + myModeList.append(mli); + } + } + } + } +// } + +// config->sync(); +} + +SyntaxModeList SyntaxDocument::modeList() +{ + return myModeList; +} + +bool SyntaxDocument::nextGroup( syntaxContextData* data) +{ + if(!data) return false; + + if (!data->currentGroup) + data->currentGroup=data->parent->firstChild(); + else + data->currentGroup=data->currentGroup->nextChild(); + + data->item=0; + + if (!data->currentGroup) + return false; + else + return true; +} + +bool SyntaxDocument::nextItem( syntaxContextData* data) +{ + if(!data) return false; + + if (!data->item) + data->item=data->currentGroup->firstChild(); + else + data->item=data->item->nextChild(); + + if (!data->item) + return false; + else + return true; +} + +QString SyntaxDocument::groupItemData( syntaxContextData* data,QString name) +{ + if(!data) + return QString::null; + + if ( (data->item) && (name.isEmpty())) + return data->item->tagName(); + + if (data->item) + return data->item->attribute(name); + else + return QString(); +} + +QString SyntaxDocument::groupData( syntaxContextData* data,QString name) +{ + if(!data) + return QString::null; + + if (data->currentGroup) + return data->currentGroup->attribute(name); + else + return QString(); +} + +void SyntaxDocument::freeGroupInfo( syntaxContextData* data) +{ + if (data) + delete data; +} + +syntaxContextData* SyntaxDocument::getSubItems(syntaxContextData* data) +{ + syntaxContextData *retval=new syntaxContextData; + retval->parent=0; + retval->currentGroup=0; + retval->item=0; + if (data != 0) + { + retval->parent=data->currentGroup; + retval->currentGroup=data->item; + retval->item=0; + } + + return retval; +} + +syntaxContextData* SyntaxDocument::getConfig(const QString& mainGroupName, const QString &Config) +{ + Opie::XMLElement *e = m_root->firstChild()->firstChild(); + + while (e) + { + kdDebug(13010)<<"in SyntaxDocument::getGroupInfo (outer loop) " <<endl; + + if (e->tagName().compare(mainGroupName)==0 ) + { + Opie::XMLElement *e1=e->firstChild(); + + while (e1) + { + kdDebug(13010)<<"in SyntaxDocument::getGroupInfo (inner loop) " <<endl; + + if (e1->tagName()==Config) + { + syntaxContextData *data=new ( syntaxContextData); + data->currentGroup=0; + data->parent=0; + data->item=e1; + return data; + } + + e1=e1->nextChild(); + } + + kdDebug(13010) << "WARNING :returning null 3"<< endl; + return 0; + } + + e=e->nextChild(); + } + + kdDebug(13010) << "WARNING :returning null 4" << endl; + return 0; +} + + + +syntaxContextData* SyntaxDocument::getGroupInfo(const QString& mainGroupName, const QString &group) +{ + + Opie::XMLElement *e=m_root->firstChild()->firstChild(); + + while (e) + { + kdDebug(13010)<<"in SyntaxDocument::getGroupInfo (outer loop) " <<endl; + + if (e->tagName().compare(mainGroupName)==0 ) + { + Opie::XMLElement *e1=e->firstChild(); + + while (e1) + { + kdDebug(13010)<<"in SyntaxDocument::getGroupInfo (inner loop) " <<endl; + if (e1->tagName()==group+"s") + { + syntaxContextData *data=new ( syntaxContextData); + data->parent=e1; + data->currentGroup=0; + data->item=0; + return data; + } + + e1=e1->nextChild(); + } + + kdDebug(13010) << "WARNING : getGroupInfo returning null :1 " << endl; + return 0; + } + + e=e->nextChild(); + } + + kdDebug(13010) << "WARNING : getGroupInfo returning null :2" << endl; + return 0; +} + + +QStringList& SyntaxDocument::finddata(const QString& mainGroup,const QString& type,bool clearList) +{ + Opie::XMLElement *e = m_root->firstChild(); + if (clearList) + m_data.clear(); + + for(e=e->firstChild(); e; e=e->nextChild()) + { + if (e->tagName()==mainGroup) + { + for (Opie::XMLElement *e1=e->firstChild();e1;e1=e1->nextChild()) + { + if (e1->tagName()!="list") continue; + + if (e1->attribute("name")==type) + { + for (Opie::XMLElement *e2=e1->firstChild();e2;e2=e2->nextChild()) + qDebug("FOUND A LIST ENTRY("+e2->tagName()+"):"+e2->value()); + m_data+="TEST";//e2->value().stripWhiteSpace(); + + break; + } + } + break; + } + } + + return m_data; +} diff --git a/noncore/apps/tinykate/libkate/document/katesyntaxdocument.h b/noncore/apps/tinykate/libkate/document/katesyntaxdocument.h new file mode 100644 index 0000000..5c5c5a4 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katesyntaxdocument.h @@ -0,0 +1,73 @@ +/*************************************************************************** + katesyntaxdocument.h - description + ------------------- + begin : Sat 31 March 2001 + copyright : (C) 2001,2002 by Joseph Wenninger + email : jowenn@kde.org + ***************************************************************************/ + +/*************************************************************************** + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + ***************************************************************************/ + +#ifndef SYNTAXDOCUMENT_H +#define SYNTAXDOCUMENT_H + +#include <opie/xmltree.h> +#include <qlist.h> +#include <qstringlist.h> + + +class syntaxModeListItem +{ + public: + QString name; + QString section; + QString mimetype; + QString extension; + QString identifier; +}; + +class syntaxContextData +{ + public: + Opie::XMLElement *parent; + Opie::XMLElement *currentGroup; + Opie::XMLElement *item; +}; + +typedef QList<syntaxModeListItem> SyntaxModeList; + +class SyntaxDocument +{ + public: + SyntaxDocument(); + ~SyntaxDocument(); + + QStringList& finddata(const QString& mainGroup,const QString& type,bool clearList=true); + SyntaxModeList modeList(); + + syntaxContextData* getGroupInfo(const QString& langName, const QString &group); + void freeGroupInfo(syntaxContextData* data); + syntaxContextData* getConfig(const QString& mainGroupName, const QString &Config); + bool nextItem(syntaxContextData* data); + bool nextGroup(syntaxContextData* data); + syntaxContextData* getSubItems(syntaxContextData* data); + QString groupItemData(syntaxContextData* data,QString name); + QString groupData(syntaxContextData* data,QString name); + void setIdentifier(const QString& identifier); + + private: + Opie::XMLElement *m_root; + void setupModeList(bool force=false); + QString currentFile; + SyntaxModeList myModeList; + QStringList m_data; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/document/katetextline.cpp b/noncore/apps/tinykate/libkate/document/katetextline.cpp new file mode 100644 index 0000000..f44cc1c --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katetextline.cpp @@ -0,0 +1,289 @@ +/* + Copyright (C) 1998, 1999 Jochen Wilhelmy + digisnap@cs.tu-berlin.de + (C) 2002, 2001 The Kate Team <kwrite-devel@kde.org> + (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#include "katetextline.h" +#include <kdebug.h> + +TextLine::TextLine(uchar attribute, int context) + : text(0L), attributes(0L), attr(attribute), ctx(context), myMark (0) +{ +} + +TextLine::~TextLine() +{ +} + + +void TextLine::replace(uint pos, uint delLen, const QChar *insText, uint insLen, uchar *insAttribs) +{ + uint oldLen = text.length(); + + text.remove (pos, delLen); + text.insert (pos, insText, insLen); + + if (oldLen<text.length()) attributes.resize (text.length()); + + if (text.length() == 0) + { + attributes.resize (0); + return; + } + + if (pos >= oldLen) + { + for (uint t=oldLen; t < attributes.size(); t++) + { + attributes[t]=0; + } + } + + int newAtStuff = insLen-delLen; + for (uint m=pos+delLen; m < attributes.size(); m++) + { + if (m+newAtStuff >= attributes.size()) break; + if (m >= attributes.size()) break; + + attributes[m+newAtStuff]=attributes[m]; + } + + if (insAttribs == 0L) + { + for (uint m3=pos; m3 < pos+insLen; m3++) + { + if (m3 < attributes.size()) attributes[m3]=0; + } + } + else + { + for (uint m2=pos; m2 < pos+insLen; m2++) + { + if (m2 < attributes.size()) attributes[m2]=insAttribs[m2-pos]; + } + } + + if (oldLen>text.length()) attributes.resize (text.length()); +} + +void TextLine::wrap(TextLine::Ptr nextLine, uint pos) +{ + int l = text.length() - pos; + + if (l > 0) + { + nextLine->replace(0, 0, &text.unicode()[pos], l, &attributes[pos]); + attr = attributes[pos]; + truncate(pos); + } +} + +void TextLine::unWrap(uint pos, TextLine::Ptr nextLine, uint len) { + + replace(pos, 0, nextLine->text.unicode(), len, nextLine->attributes.data()); + attr = nextLine->getRawAttr(len); + nextLine->replace(0, len, 0L, 0); +} + +int TextLine::firstChar() const { + uint z = 0; + + while (z < text.length() && text[z].isSpace()) z++; + + if (z < text.length()) + return z; + else + return -1; +} + +int TextLine::lastChar() const { + uint z = text.length(); + + while (z > 0 && text[z - 1].isSpace()) z--; + return z; +} + +void TextLine::removeSpaces() { + + while (text.length() > 0 && text[text.length() - 1].isSpace()) text.truncate (text.length()-1); +} + +QChar TextLine::getChar(uint pos) const { + if (pos < text.length()) return text.constref(pos); + return ' '; +} +const QChar *TextLine::firstNonSpace() +{ + const QChar *ptr=getText(); + int first=firstChar(); + return (first > -1) ? ptr+first : ptr; +} + +bool TextLine::startingWith(QString& match) +{ + return text.startsWith (match); +} + +bool TextLine::endingWith(QString& match) { + + int matchLen = match.length(); + + // Get the last chars of the textline + QString lastChars = text.right(matchLen); + + return (lastChars == match); +} + +int TextLine::cursorX(uint pos, uint tabChars) const { + int l, x, z; + + l = (pos < text.length()) ? pos : text.length(); + x = 0; + for (z = 0; z < l; z++) { + if (text[z] == '\t') x += tabChars - (x % tabChars); else x++; + } + x += pos - l; + return x; +} + +void TextLine::setAttribs(uchar attribute, uint start, uint end) { + uint z; + + if (end > text.length()) end = text.length(); + for (z = start; z < end; z++) attributes[z] = (attributes[z] & taSelected) | attribute; +} + +void TextLine::setAttr(uchar attribute) { + attr = (attr & taSelected) | attribute; +} + +uchar TextLine::getAttr(uint pos) const { + if (pos < text.length()) return attributes[pos] & taAttrMask; + return attr & taAttrMask; +} + +uchar TextLine::getAttr() const { + return attr & taAttrMask; +} + +uchar TextLine::getRawAttr(uint pos) const { + if (pos < text.length()) return attributes[pos]; + return (attr & taSelected) ? attr : attr | 256; +} + +uchar TextLine::getRawAttr() const { + return attr; +} + +void TextLine::setContext(int context) { + ctx = context; +} + +int TextLine::getContext() const { + return ctx; +} + + +void TextLine::select(bool sel, uint start, uint end) { + uint z; + + if (end > text.length()) end = text.length(); + if (sel) { + for (z = start; z < end; z++) attributes[z] |= taSelected; + } else { + for (z = start; z < end; z++) attributes[z] &= ~taSelected; + } +} + +void TextLine::selectEol(bool sel, uint pos) { + uint z; + + if (sel) { + for (z = pos; z < text.length(); z++) attributes[z] |= taSelected; + attr |= taSelected; + } else { + for (z = pos; z < text.length(); z++) attributes[z] &= ~taSelected; + attr &= ~taSelected; + } +} + + +void TextLine::toggleSelect(uint start, uint end) { + uint z; + + if (end > text.length()) end = text.length(); + for (z = start; z < end; z++) attributes[z] = attributes[z] ^ taSelected; +} + + +void TextLine::toggleSelectEol(uint pos) { + uint z; + + for (z = pos; z < text.length(); z++) attributes[z] = attributes[z] ^ taSelected; + attr = attr ^ taSelected; +} + + +int TextLine::numSelected() const { + uint z, n; + + n = 0; + for (z = 0; z < text.length(); z++) if (attributes[z] & taSelected) n++; + return n; +} + +bool TextLine::isSelected(uint pos) const { + if (pos < text.length()) return (attributes[pos] & taSelected); + return (attr & taSelected); +} + +bool TextLine::isSelected() const { + return (attr & taSelected); +} + +int TextLine::findSelected(uint pos) const { + while (pos < text.length() && attributes[pos] & taSelected) pos++; + return pos; +} + +int TextLine::findUnselected(uint pos) const { + while (pos < text.length() && !(attributes[pos] & taSelected)) pos++; + return pos; +} + +int TextLine::findRevSelected(uint pos) const { + while (pos > 0 && attributes[pos - 1] & taSelected) pos--; + return pos; +} + +int TextLine::findRevUnselected(uint pos) const { + while (pos > 0 && !(attributes[pos - 1] & taSelected)) pos--; + return pos; +} + +void TextLine::addMark (uint m) +{ + myMark = myMark | m; +} + +void TextLine::delMark (uint m) +{ + myMark = myMark & ~m; +} diff --git a/noncore/apps/tinykate/libkate/document/katetextline.h b/noncore/apps/tinykate/libkate/document/katetextline.h new file mode 100644 index 0000000..c2968cc --- a/dev/null +++ b/noncore/apps/tinykate/libkate/document/katetextline.h @@ -0,0 +1,359 @@ +/* + Copyright (C) 1998, 1999 Jochen Wilhelmy + digisnap@cs.tu-berlin.de + (C) 2002, 2001 The Kate Team <kwrite-devel@kde.org> + (C) 2002 Joseph Wenninger <jowenn@kde.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ + +#ifndef _KWTEXTLINE_H_ +#define _KWTEXTLINE_H_ + +#include <stdlib.h> + +#include <qstring.h> +#include <qarray.h> +#include <qvaluelist.h> + +#include <ksharedptr.h> + +/** + FastValueList: QValueList, but with a faster at() like QList + FVPrivate is needed so that "const" functions can change the + current position +*/ +template<class T> +class FVPrivate +{ +public: + int curpos; + typedef QValueListConstIterator<T> Iterator; + Iterator curit; + + FVPrivate() { curpos=-1; }; +}; + +template<class T> +class FastValueList : public QValueList<T> +{ +public: + typedef QValueListIterator<T> Iterator; + typedef QValueListConstIterator<T> ConstIterator; +protected: + FVPrivate<T> *fvp; + + Iterator fastat( uint i ) { + uint num=count(); + if (i>=num) {return end();} + if (fvp->curpos<0) { fvp->curpos=0; fvp->curit=begin(); } + uint curpos=(uint) fvp->curpos; + Iterator curit(fvp->curit.node); + if (curpos==i) return curit; + + int diff=i-curpos; + bool forward; + if (diff<0) diff=-diff; + if (((uint)diff < i) && ((uint)diff < num-i)) { // start from current node + forward=i > (uint)curpos; + } else if (i < num - i) { // start from first node + curit=begin(); diff=i; forward=TRUE; + } else { // start from last node + curit=fromLast(); diff=num - i - 1; + if (diff<0) diff=0; + forward=FALSE; + } + if (forward) { + while(diff--) curit++; + } else { + while(diff--) curit--; + } + fvp->curpos=i; fvp->curit=curit; + return curit; + } + ConstIterator fastat( uint i ) const { + uint num=count(); + if (i>=num) {return end();} + if (fvp->curpos<0) { fvp->curpos=0; fvp->curit=begin(); } + uint curpos=(uint) fvp->curpos; + ConstIterator curit=fvp->curit; + if (curpos==i) return curit; + + int diff=i-curpos; + bool forward; + if (diff<0) diff=-diff; + if (((uint)diff < i) && ((uint)diff < num-i)) { // start from current node + forward=i > (uint)curpos; + } else if (i < num - i) { // start from first node + curit=begin(); diff=i; forward=TRUE; + } else { // start from last node + curit=fromLast(); diff=num - i - 1; + if (diff<0) diff=0; + forward=FALSE; + } + if (forward) { + while(diff--) curit++; + } else { + while(diff--) curit--; + } + fvp->curpos=i; fvp->curit=curit; + return curit; + } + +public: + FastValueList() : QValueList<T>() + { fvp=new FVPrivate<T>(); } + FastValueList(const FastValueList<T>& l) : QValueList<T>(l) + { fvp=new FVPrivate<T>(); } + ~FastValueList() { delete fvp; } + + Iterator insert( Iterator it, const T& x ) { + fvp->curpos=-1; return QValueList<T>::insert(it, x); + } + + Iterator append( const T& x ) { + fvp->curpos=-1; return QValueList<T>::append( x ); + } + Iterator prepend( const T& x ) { + fvp->curpos=-1; return QValueList<T>::prepend( x ); + } + + Iterator remove( Iterator it ) { + fvp->curpos=-1; return QValueList<T>::remove( it ); + } + void remove( const T& x ) { + fvp->curpos=-1; QValueList<T>::remove( x ); + } + + T& operator[] ( uint i ) { detach(); return fastat(i); } + const T& operator[] ( uint i ) const { return *fastat(i); } + Iterator at( uint i ) { detach(); return fastat(i); } + ConstIterator at( uint i ) const { return ConstIterator( fastat(i) ); } +}; + + +/** + The TextLine represents a line of text. A text line that contains the + text, an attribute for each character, an attribute for the free space + behind the last character and a context number for the syntax highlight. + The attribute stores the index to a table that contains fonts and colors + and also if a character is selected. +*/ +class TextLine : public KShared +{ + friend class KWBuffer; + friend class KWBufBlock; + +public: + typedef KSharedPtr<TextLine> Ptr; + typedef FastValueList<Ptr> List; + +public: + /** + Creates an empty text line with given attribute and syntax highlight + context + */ + TextLine(uchar attribute = 0, int context = 0); + ~TextLine(); + + /** + Returns the length + */ + uint length() const {return text.length();} + /** + Universal text manipulation method. It can be used to insert, delete + or replace text. + */ + void replace(uint pos, uint delLen, const QChar *insText, uint insLen, uchar *insAttribs = 0L); + + /** + Appends a string of length l to the textline + */ + void append(const QChar *s, uint l) {replace(text.length(), 0, s, l);} + /** + Wraps the text from the given position to the end to the next line + */ + void wrap(TextLine::Ptr nextLine, uint pos); + /** + Wraps the text of given length from the beginning of the next line to + this line at the given position + */ + void unWrap(uint pos, TextLine::Ptr nextLine, uint len); + /** + Truncates the textline to the new length + */ + void truncate(uint newLen) { text.truncate(newLen); attributes.resize(text.length()); } + /** + Returns the position of the first character which is not a white space + */ + int firstChar() const; + /** + Returns the position of the last character which is not a white space + */ + int lastChar() const; + /** + Removes trailing spaces + */ + void removeSpaces(); + /** + Gets the char at the given position + */ + QChar getChar(uint pos) const; + /** + Gets the text. WARNING: it is not null terminated + */ + const QChar *getText() const {return text.unicode();}; + /** + Gets a C-like null terminated string + */ + const QString getString() { return text; }; + + /* + Gets a null terminated pointer to first non space char + */ + const QChar *firstNonSpace(); + /** + Returns the x position of the cursor at the given position, which + depends on the number of tab characters + */ + int cursorX(uint pos, uint tabChars) const; + /** + Is the line starting with the given string + */ + bool startingWith(QString& match); + /** + Is the line ending with the given string + */ + bool endingWith(QString& match); + + /** + Sets the attributes from start to end -1 + */ + void setAttribs(uchar attribute, uint start, uint end); + /** + Sets the attribute for the free space behind the last character + */ + void setAttr(uchar attribute); + /** + Gets the attribute at the given position + */ + uchar getAttr(uint pos) const; + /** + Gets the attribute for the free space behind the last character + */ + uchar getAttr() const; + /** + Gets the attribute, including the select state, at the given position + */ + uchar getRawAttr(uint pos) const; + /** + Gets the attribute, including the select state, for the free space + behind the last character + */ + uchar getRawAttr() const; + + /** + Sets the syntax highlight context number + */ + void setContext(int context); + /** + Gets the syntax highlight context number + */ + int getContext() const; + + /** + Sets the select state from start to end -1 + */ + void select(bool sel, uint start, uint end); + /** + Sets the select state from the given position to the end, including + the free space behind the last character + */ + void selectEol(bool sel, uint pos); + /** + Toggles the select state from start to end -1 + */ + void toggleSelect(uint start, uint end); + /** + Toggles the select state from the given position to the end, including + the free space behind the last character + */ + void toggleSelectEol(uint pos); + /** + Returns the number of selected characters + */ + int numSelected() const; + /** + Returns if the character at the given position is selected + */ + bool isSelected(uint pos) const; + /** + Returns true if the free space behind the last character is selected + */ + bool isSelected() const; + /** + Finds the next selected character, starting at the given position + */ + int findSelected(uint pos) const; + /** + Finds the next unselected character, starting at the given position + */ + int findUnselected(uint pos) const; + /** + Finds the previous selected character, starting at the given position + */ + int findRevSelected(uint pos) const; + /** + Finds the previous unselected character, starting at the given position + */ + int findRevUnselected(uint pos) const; + + void clearMark () { myMark = 0; }; + void addMark ( uint m ); + void delMark ( uint m ); + uint mark() { return myMark; }; + + uchar *getAttribs() { return attributes.data(); } + + protected: + /** + The text + */ + QString text; + /** + The attributes + */ + QArray<uchar> attributes; + /** + The attribute of the free space behind the end + */ + uchar attr; + /** + The syntax highlight context + */ + int ctx; + /** + The marks of the current line + */ + uint myMark; +}; + +//text attribute constants +const int taSelected = 0x40; +const int taAttrMask = ~taSelected & 0xFF; + +#endif //KWTEXTLINE_H + |