104 files changed, 22372 insertions, 0 deletions
diff --git a/apps/Applications/tinykate.desktop b/apps/Applications/tinykate.desktop new file mode 100644 index 0000000..3555ce2 --- a/dev/null +++ b/apps/Applications/tinykate.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Categories = +Comment = A texteditor with syntax highlighting +Exec = tinykate +File = +Icon = tinykate/tinykate +Name = TinyKATE +Type = Applications diff --git a/noncore/apps/tinykate/install b/noncore/apps/tinykate/install new file mode 100755 index 0000000..912c91b --- a/dev/null +++ b/noncore/apps/tinykate/install @@ -0,0 +1,13 @@ +#!/bin/sh +if [ a$OPIEDIR = a ] +then +echo OPIEDIR must be set +exit +fi +[ -f $OPIEDIR/pics/tinykate_icon.xpm ] || cp tinykate_icon.xpm $OPIEDIR/pics/ +[ -f $OPIEDIR/apps/tinykate.desktop ] || cp tinykate.desktop $OPIEDIR/apps/ +mv $OPIEDIR/Makefile $OPIEDIR/Makefile.orig +sed "s/APPS=/&tinykate \\\\ \\ + /" $OPIEDIR/Makefile.orig >> $OPIEDIR/Makefile +echo You may wish to move the desktop file in to +echo an appropriate subdirectory of the menus. 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 + diff --git a/noncore/apps/tinykate/libkate/interfaces/document.h b/noncore/apps/tinykate/libkate/interfaces/document.h new file mode 100644 index 0000000..cbfd1b3 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/interfaces/document.h @@ -0,0 +1,103 @@ +/*************************************************************************** + document.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 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_INCLUDE_ +#define _KATE_DOCUMENT_INCLUDE_ + +#include <ktexteditor.h> + +class KConfig; + +namespace Kate +{ + +/** internal class for document bookmarks. */ +class Mark +{ + public: + uint line; + uint type; +}; + +/** This interface provedes access to the Kate Document class. +*/ +class Document : public KTextEditor::Document +{ + Q_OBJECT + + public: + Document (); + virtual ~Document (); + + public: + /** Read document config. + */ + virtual void readConfig () { ; }; + /** Save document config. + */ + virtual void writeConfig () { ; }; + + /** Read document session config. + */ + virtual void readSessionConfig (KConfig *) { ; }; + /** Save document session config. + */ + virtual void writeSessionConfig (KConfig *) { ; }; + + /** Returns the document ID. + */ + virtual uint docID () { return 0L; }; + + /** Defines possible mark types. A line can have marks of different types. + */ + enum marks + { + Bookmark = 1, + Breakpoint = 2, + markType0 = 4, + markType1 = 8, + markType2 = 16, + markType3 = 32, + markType4 = 64, + markType5 = 128, + markType6 = 256, + markType7 = 512, + markType8 = 1024 + }; + + /** A list of all marks in a document. Use binary comparing to find marks of a specific type. + */ + virtual QList<Mark> marks () { QList<Mark> l; return l; }; + + public slots: + // clear buffer/filename - update the views + virtual void flush () { ; }; +}; + +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/interfaces/interfaces.cpp b/noncore/apps/tinykate/libkate/interfaces/interfaces.cpp new file mode 100644 index 0000000..4fdd252 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/interfaces/interfaces.cpp @@ -0,0 +1,51 @@ +/*************************************************************************** + interfaces.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 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 "document.h" + +#include "view.h" + +namespace Kate +{ + +Document::Document () : KTextEditor::Document (0L, 0L) +{ +} + +Document::~Document () +{ +} + +View::View ( KTextEditor::Document *doc, QWidget *parent, const char *name ) : KTextEditor::View (doc, parent, name) +{ +} + +View::~View () +{ +} + +}; diff --git a/noncore/apps/tinykate/libkate/interfaces/view.h b/noncore/apps/tinykate/libkate/interfaces/view.h new file mode 100644 index 0000000..5b24bb5 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/interfaces/view.h @@ -0,0 +1,160 @@ +/*************************************************************************** + view.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 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_VIEW_INCLUDE_ +#define _KATE_VIEW_INCLUDE_ + +#include <ktexteditor.h> + +class KConfig; + +namespace Kate +{ + +class Document; +class Mark; + +/** This interface provides access to the view. +*/ +class View : public KTextEditor::View +{ + Q_OBJECT + + public: + View ( KTextEditor::Document *doc, QWidget *parent, const char *name = 0 ); + virtual ~View (); + + /** Returns a pointer to the document of the view. + */ + virtual Document *getDoc () { return 0L; }; + + /** Returns the marked text in the view. + */ + virtual QString markedText () { return 0L; }; + + public slots: + /** popup a config dialog for the editor part. + */ + virtual void configDialog () { ; }; + + // Highlighting slots + virtual void setHl (int) { ; }; + virtual int getHl () { return 0; }; + virtual int getHlCount () { return 0; }; + virtual QString getHlName (int) { return 0L; }; + virtual QString getHlSection (int) { return 0L; }; + + // undo/redo stuff + virtual void undo () { ; }; + virtual void redo () { ; }; + virtual void undoHistory() { ; }; + + public: + // read/save config of the view + virtual void readConfig () { ; }; + virtual void writeConfig () { ; }; + + // read/save sessionconfig of the view + virtual void readSessionConfig (KConfig *) { ; }; + virtual void writeSessionConfig (KConfig *) { ; }; + + public slots: + // some simply key commands + virtual void keyReturn () { ; }; + virtual void keyDelete () { ; }; + virtual void backspace () { ; }; + virtual void killLine () { ; }; + + // move cursor in the view + virtual void cursorLeft () { ; }; + virtual void shiftCursorLeft () { ; }; + virtual void cursorRight () { ; }; + virtual void shiftCursorRight () { ; }; + virtual void wordLeft () { ; }; + virtual void shiftWordLeft () { ; }; + virtual void wordRight () { ; }; + virtual void shiftWordRight () { ; }; + virtual void home () { ; }; + virtual void shiftHome () { ; }; + virtual void end () { ; }; + virtual void shiftEnd () { ; }; + virtual void up () { ; }; + virtual void shiftUp () { ; }; + virtual void down () { ; }; + virtual void shiftDown () { ; }; + virtual void scrollUp () { ; }; + virtual void scrollDown () { ; }; + virtual void topOfView () { ; }; + virtual void bottomOfView () { ; }; + virtual void pageUp () { ; }; + virtual void shiftPageUp () { ; }; + virtual void pageDown () { ; }; + virtual void shiftPageDown () { ; }; + virtual void top () { ; }; + virtual void shiftTop () { ; }; + virtual void bottom () { ; }; + virtual void shiftBottom () { ; }; + + public slots: + // edit command popup window + virtual void slotEditCommand () { ; }; + + // icon border enable/disable + virtual void setIconBorder (bool) { ; }; + virtual void toggleIconBorder () { ; }; + + // goto mark + virtual void gotoMark (Mark *) { ; }; + + // toggle current line bookmark or clear all bookmarks + virtual void toggleBookmark () { ; }; + virtual void clearBookmarks () { ; }; + + public: + // is iconborder visible ? + virtual bool iconBorder() { return false; }; + + public slots: + /** + Flushes the document of the text widget. The user is given + a chance to save the current document if the current document has + been modified. + */ + virtual void flush () { ; }; + + public: + /** + Returns true if the current document can be + discarded. If the document is modified, the user is asked if he wants + to save it. On "cancel" the function returns false. + */ + virtual bool canDiscard() { return false; }; +}; + +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/ktexteditor/ktexteditor.cpp b/noncore/apps/tinykate/libkate/ktexteditor/ktexteditor.cpp new file mode 100644 index 0000000..6b4d86d --- a/dev/null +++ b/noncore/apps/tinykate/libkate/ktexteditor/ktexteditor.cpp @@ -0,0 +1,140 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Simon Hausmann <hausmann@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 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 "ktexteditor.h" + +using namespace KTextEditor; + +class View::ViewPrivate +{ +public: + ViewPrivate() + { + } + ~ViewPrivate() + { + } + + Document *m_doc; + bool m_bContextPopup; +}; + +View::View( Document *doc, QWidget *parent, const char *name ) +: QWidget( parent, name ) +{ + d = new ViewPrivate; + d->m_doc = doc; + d->m_bContextPopup = true; +} + +View::~View() +{ + delete d; +} + +Document *View::document() const +{ + return d->m_doc; +} + +void View::insertText( const QString &text, bool mark ) +{ + int line, col; + getCursorPosition( &line, &col ); + document()->insertAt( text, line, col, mark ); +} + +void View::setInternalContextMenuEnabled( bool b ) +{ + d->m_bContextPopup = b; +} + +bool View::internalContextMenuEnabled() const +{ + return d->m_bContextPopup; +} + +class Document::DocumentPrivate +{ +public: + DocumentPrivate() + { + } + ~DocumentPrivate() + { + } + +}; + +Document::Document( QObject *parent, const char *name ) + : QObject(parent,name) +{ + d = new DocumentPrivate; +} + +Document::~Document() +{ + //one never knows... + QListIterator<View> it( m_views ); + + for (; it.current(); ++it ) + disconnect( it.current(), SIGNAL( destroyed() ), + this, SLOT( slotViewDestroyed() ) ); + + delete d; +} + +QList<View> Document::views() const +{ + return m_views; +} + +void Document::addView( View *view ) +{ + if ( !view ) + return; + + if ( m_views.findRef( view ) != -1 ) + return; + + m_views.append( view ); + connect( view, SIGNAL( destroyed() ), + this, SLOT( slotViewDestroyed() ) ); +} + +void Document::removeView( View *view ) +{ + if ( !view ) + return; + + disconnect( view, SIGNAL( destroyed() ), + this, SLOT( slotViewDestroyed() ) ); + + m_views.removeRef( view ); +} + +void Document::slotViewDestroyed() +{ + const View *view = static_cast<const View *>( sender() ); + m_views.removeRef( view ); +} + + diff --git a/noncore/apps/tinykate/libkate/ktexteditor/ktexteditor.h b/noncore/apps/tinykate/libkate/ktexteditor/ktexteditor.h new file mode 100644 index 0000000..595b5d3 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/ktexteditor/ktexteditor.h @@ -0,0 +1,239 @@ +/* This file is part of the KDE project + Copyright (C) 2000 Simon Hausmann <hausmann@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 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 __ktexteditor_h__ +#define __ktexteditor_h__ + +#include <qwidget.h> +#include <qlist.h> + +/** + * This is the kparts interface classes for text editors. + * The text editors use the Document/View model that allows multiple views into + * one file (Document) + * + * Line numbers passed via this interface must begin at line number zero (0). + * + * TODO: See documentation at http://??????? for information on how to use kparts in + * general. A simple (but sufficient) implementation is shown below. + * + * <pre> + * QHBoxLayout *layout = new QHBoxLayout(this); + * QSplitter *fixme = new QSplitter(this); + * + * KTrader::OfferList offers = KTrader::self()->query( "KTextEditor/Document" ); + * assert( offers.count() >= 1 ); + * KService::Ptr service = *offers.begin(); + * KLibFactory *factory = KLibLoader::self()->factory( service->library() ); + * assert( factory ); + * m_part = static_cast<KTextEditor::Document *>( + * factory->create( this, 0, "KTextEditor::Document" ) ); + * assert( m_part ); + * m_part->createView( fixme, 0 ); + * layout->addWidget(fixme); + * m_part->setText( "" ); + * </pre> + * + * You may also be able to use a dynamic_cast for the document part above + * (depending on compliation of the library used) + * + */ + +namespace KTextEditor +{ + +class Document; + +/** + * The View class encapsulates a single view into the document. + */ + +class View : public QWidget +{ + Q_OBJECT + +public: + /** + * Create a new view to the given document. The document must be non-null. + */ + View( Document *doc, QWidget *parent, const char *name = 0 ); + virtual ~View(); + + /** + * Acessor to the parent Document. + */ + virtual Document *document() const; // XXX fix when renaming KXMLGUIClient::document + + virtual void setCursorPosition( int line, int col, bool mark = false ) = 0; + virtual void getCursorPosition( int *line, int *col ) = 0; + + /** + * Inserts text at the current cursor position into the document + */ + virtual void insertText( const QString &text, bool mark = false ); + + /** + * Overwrite mode is where the char under the cursor is replaced with the + * char typed by the user + */ + virtual bool isOverwriteMode() const = 0; + + /** + * You should reimplement this method. + * If the internal popupmenu property is enabled, then the implementation + * is free to handle/use/implement/show a context popupmenu ( see also + * KContextMenuManager class in kdeui ). If disabled, then the + * implementation should emit the @ref contextPopupMenu signal. + */ + virtual void setInternalContextMenuEnabled( bool b ); + virtual bool internalContextMenuEnabled() const; + +public slots: + virtual void setOverwriteMode( bool b ) = 0; + +signals: + /** + * Connect here when you want to implement a custom popup menu. + */ + void contextPopupMenu( const QPoint &p ); + + /** + * Connect here if you want to track the scrolling within the editor. This + * allows you to add specialised borders that displays extra data about + * particular lines such as breakpoints etc. + */ + void scrollValueChanged( int value ); + +private: + class ViewPrivate; + ViewPrivate *d; +}; + +class Document : public QObject +{ + Q_OBJECT +public: + Document( QObject *parent = 0, const char *name = 0 ); + virtual ~Document(); + + /** + * Create a view that will display the document data. You can create as many + * views as you like. When the user modifies data in one view then all other + * views will be updated as well. + */ + virtual View *createView( QWidget *parent, const char *name = 0 ) = 0; + + /* + * Accessor to the list of views. + */ + virtual QList<View> views() const; + + /** + * @return All the text from the requested line. + */ + virtual QString textLine( int line ) const = 0; + + virtual void setSelection( int row_from, int col_from, int row_to, int col_t ) = 0; + virtual bool hasSelection() const = 0; + virtual QString selection() const = 0; + + /** + * @return The current number of lines in the document + */ + virtual int numLines() const = 0; + + /** + * Insert line(s) at the given line number. If the line number is -1 + * (the default) then the line is added to end of the document + */ + virtual void insertLine( const QString &s, int line = -1 ) = 0; + + /** + * Add the line(s) into the document at the given line and column. + */ + virtual void insertAt( const QString &s, int line, int col, bool mark = FALSE ) = 0; + + virtual void removeLine( int line ) = 0; + + /** + * @return the complete document as a single QString + */ + virtual QString text() const = 0; + + /** + * @return the number of characters in the document + */ + virtual int length() const = 0; + +public slots: + /** + * Set the given text into the view. + * Warning: This will overwrite any data currently held in this view. + */ + virtual void setText( const QString &t ) = 0; + +signals: + + /** + * When the user changes the text then this signal is emitted + * TODO: - explain why and what type of change trigger this? + */ + void textChanged(); + + /** + */ + void deleted( int startLine, int endLine ); + + /** + */ + void inserted( int startLine, int endLine ); + +protected: + /** + * Call this method in your document implementation whenever you created a new + * view. + * (like in @ref createView ) + */ + virtual void addView( View *view ); + + /** + * Call this method in your document implementation whenever you delete a view. + */ + virtual void removeView( View *view ); + + QList<View> m_views; + +private slots: + + /** + * The view emits a destroyed() signal which is connected to this slot + * and removed from our internal list. Note: The view* is obtained from + * the QObject::sender() method. + */ + void slotViewDestroyed(); + +private: + class DocumentPrivate; + DocumentPrivate *d; +}; + +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/libkate.pro b/noncore/apps/tinykate/libkate/libkate.pro new file mode 100644 index 0000000..a504abf --- a/dev/null +++ b/noncore/apps/tinykate/libkate/libkate.pro @@ -0,0 +1,90 @@ +TEMPLATE = lib +CONFIG = qt warn_on release +DESTDIR = $(OPIEDIR)/bin +HEADERS = microkde/kapplication.h \ + microkde/kconfig.h \ + microkde/kdebug.h \ + microkde/kdialog.h \ + microkde/kdialogbase.h \ + microkde/kfiledialog.h \ + microkde/kglobal.h \ + microkde/kiconloader.h \ + microkde/klineedit.h \ + microkde/klocale.h \ + microkde/kmessagebox.h \ + microkde/kprinter.h \ + microkde/krestrictedline.h \ + microkde/kseparator.h \ + microkde/ksimpleconfig.h \ + microkde/kstandarddirs.h \ + microkde/ktempfile.h \ + microkde/kunload.h \ + microkde/kurlrequester.h \ + microkde/kfontdialog.h \ + microkde/krun.h \ + microkde/knumvalidator.h \ + microkde/kstaticdeleter.h \ + microkde/klistview.h \ + microkde/kglobalsettings.h \ + microkde/kcolorbtn.h \ + \ + \ + qt3back/qregexp3.h \ + kde/ksharedptr.h \ + document/katebuffer.h document/katedialogs.h \ + document/katetextline.h \ + document/katecmd.h \ + document/katehighlight.h \ + document/katecmds.h document/katedocument.h \ + document/katesyntaxdocument.h \ + view/kateundohistory.h \ + view/kateview.h \ + view/kateviewdialog.h \ + interfaces/view.h \ + interfaces/document.h \ + ktexteditor/ktexteditor.h + +SOURCES = microkde/kapplication.cpp \ + microkde/kdialogbase.cpp \ + microkde/kconfig.cpp \ + microkde/klocale.cpp \ + microkde/kmessagebox.cpp \ + microkde/kprocess.cpp \ + microkde/kstandarddirs.cpp \ + microkde/ktempfile.cpp \ + microkde/kurlrequester.cpp \ + microkde/kcolordialog.cpp \ + microkde/kfontdialog.cpp \ + microkde/krun.cpp \ + microkde/knumvalidator.cpp \ + microkde/kglobal.cpp \ + microkde/kglobalsettings.cpp \ + microkde/kcolorbtn.cpp \ + \ + \ + qt3back/qregexp3.cpp \ + ktexteditor/ktexteditor.cpp \ + document/katebuffer.cpp document/katedialogs.cpp \ + document/katehighlight.cpp \ + document/katecmd.cpp \ + document/katesyntaxdocument.cpp document/katecmds.cpp \ + document/katedocument.cpp document/katetextline.cpp \ + view/kateundohistory.cpp \ + view/kateview.cpp \ + view/kateviewdialog.cpp \ + interfaces/interfaces.cpp + +INTERFACES = +INCLUDEPATH += $(OPIEDIR)/include $(OPIEDIR)/noncore/apps/tinykate/libkate/microkde \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/document \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/view \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/interfaces \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/ktexteditor \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/qt3back +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lqpe -lopie +TARGET = tinykate + +INCLUDEPATH += $(OPIEDIR)/include +DESTDIR = $(QTDIR)/lib$(PROJMAK) + diff --git a/noncore/apps/tinykate/libkate/microkde/kaction.h b/noncore/apps/tinykate/libkate/microkde/kaction.h new file mode 100644 index 0000000..622330e --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kaction.h @@ -0,0 +1,8 @@ +#ifndef MINIKDE_KACTION_H +#define MINIKDE_KACTION_H + +#include <qaction.h> + +#define KAction QAction + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kapplication.cpp b/noncore/apps/tinykate/libkate/microkde/kapplication.cpp new file mode 100644 index 0000000..60ed579 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kapplication.cpp @@ -0,0 +1,8 @@ +#include <stdlib.h> + +#include "kapplication.h" + +int KApplication::random() +{ + return rand(); +} diff --git a/noncore/apps/tinykate/libkate/microkde/kapplication.h b/noncore/apps/tinykate/libkate/microkde/kapplication.h new file mode 100644 index 0000000..99fb4f0 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kapplication.h @@ -0,0 +1,11 @@ +#ifndef MINIKDE_KAPPLICATION_H +#define MINIKDE_KAPPLICATION_H + +class KApplication +{ + public: + static int random(); + static int cursorFlashTime() { return 1000; } +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kcolorbtn.cpp b/noncore/apps/tinykate/libkate/microkde/kcolorbtn.cpp new file mode 100644 index 0000000..5d21f15 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kcolorbtn.cpp @@ -0,0 +1,84 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Martin Jones (mjones@kde.org) + Copyright (C) 1999 Cristian Tibirna (ctibirna@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 <qdialog.h> +#include <qpainter.h> +#include <qdrawutil.h> +#include <qapplication.h> +#include <kglobalsettings.h> +#include "kcolordialog.h" +#include "kcolorbtn.h" + +KColorButton::KColorButton( QWidget *parent, const char *name ) + : QPushButton( parent, name ), dragFlag(false) +{ + // 2000-10-15 (putzer): fixes broken keyboard usage + connect (this, SIGNAL(clicked()), this, SLOT(chooseColor())); +} + +KColorButton::KColorButton( const QColor &c, QWidget *parent, + const char *name ) + : QPushButton( parent, name ), col(c), dragFlag(false) +{ + + // 2000-10-15 (putzer): fixes broken keyboard usage + connect (this, SIGNAL(clicked()), this, SLOT(chooseColor())); +} + +void KColorButton::setColor( const QColor &c ) +{ + col = c; + repaint( false ); +} + +void KColorButton::drawButtonLabel( QPainter *painter ) +{ + QRect r = QApplication::style().buttonRect( 0, 0, width(), height() ); + int l = r.x(); + int t = r.y(); + int w = r.width(); + int h = r.height(); + int b = 5; + + QColor lnCol = colorGroup().text(); + QColor fillCol = isEnabled() ? col : backgroundColor(); + + if ( isDown() ) { + qDrawPlainRect( painter, l+b+1, t+b+1, w-b*2, h-b*2, lnCol, 1, 0 ); + b++; + painter->fillRect( l+b+1, t+b+1, w-b*2, h-b*2, fillCol ); + } else { + qDrawPlainRect( painter, l+b, t+b, w-b*2, h-b*2, lnCol, 1, 0 ); + b++; + painter->fillRect( l+b, t+b, w-b*2, h-b*2, fillCol ); + } +} + +void KColorButton::chooseColor() +{ + if( KColorDialog::getColor( col) == QDialog::Rejected ) + { + return; + } + + repaint( false ); + emit changed( col ); +} + diff --git a/noncore/apps/tinykate/libkate/microkde/kcolorbtn.h b/noncore/apps/tinykate/libkate/microkde/kcolorbtn.h new file mode 100644 index 0000000..b79d5e8 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kcolorbtn.h @@ -0,0 +1,92 @@ +/* This file is part of the KDE libraries + Copyright (C) 1997 Martin Jones (mjones@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 __COLBTN_H__ +#define __COLBTN_H__ + +#include <qpushbutton.h> + +/** +* This widget can be used to display or allow user selection of a colour. +* +* @see KColorDialog +* +* @short A pushbutton to display or allow user selection of a colour. +* @version $Id$ +*/ +class KColorButton : public QPushButton +{ + Q_OBJECT + Q_PROPERTY( QColor color READ color WRITE setColor ) + +public: + /** + * Constructor. Create a KColorButton. + */ + KColorButton( QWidget *parent, const char *name = 0L ); + /** + * Constructor. Create a KColorButton. + * @param c The initial colour of the button. + */ + KColorButton( const QColor &c, QWidget *parent, const char *name = 0L ); + /** + * Destructor. + */ + virtual ~KColorButton() {} + + /** + * The current colour. + * @return The current colour. + */ + QColor color() const + { return col; } + /** + * Set the current colour. + * + * @param c The colour to set. + */ + void setColor( const QColor &c ); + +signals: + /** + * This signal will be emitted when the colour of the widget + * is changed, either with @ref #setColor() or via user selection. + */ + void changed( const QColor &newColor ); + +protected slots: + void chooseColor(); + +protected: + /** + * @reimplemented + */ + virtual void drawButtonLabel( QPainter *p ); + +private: + QColor col; + QPoint mPos; + bool dragFlag; + + class KColorButtonPrivate; + KColorButtonPrivate *d; +}; + +#endif + diff --git a/noncore/apps/tinykate/libkate/microkde/kcolorbutton.h b/noncore/apps/tinykate/libkate/microkde/kcolorbutton.h new file mode 100644 index 0000000..b446eca --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kcolorbutton.h @@ -0,0 +1,4 @@ +#ifndef K_COLOR_BUTTON_H +#define K_COLOR_BUTTON_H +#include <kcolorbtn.h> +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kcolordialog.cpp b/noncore/apps/tinykate/libkate/microkde/kcolordialog.cpp new file mode 100644 index 0000000..3aee42a --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kcolordialog.cpp @@ -0,0 +1,6 @@ +#include "kcolordialog.h" + +int KColorDialog::getColor( const QColor & ) +{ + return 0; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kcolordialog.h b/noncore/apps/tinykate/libkate/microkde/kcolordialog.h new file mode 100644 index 0000000..0f831cd --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kcolordialog.h @@ -0,0 +1,14 @@ +#ifndef MINIKDE_KCOLORDIALOG_H +#define MINIKDE_KCOLORDIALOG_H + +#include <qcolor.h> + +class KColorDialog +{ + public: + enum { Accepted }; + + static int getColor( const QColor & ); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kconfig.cpp b/noncore/apps/tinykate/libkate/microkde/kconfig.cpp new file mode 100644 index 0000000..d88bda0 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kconfig.cpp @@ -0,0 +1,181 @@ +#include <qfile.h> +#include <qtextstream.h> + +#include "kdebug.h" + +#include "kconfig.h" + +QString KConfig::mGroup = ""; +//QString KConfig::mGroup = "General"; + +KConfig::KConfig( const QString &fileName ) + : mFileName( fileName ), mDirty( false ) +{ + kdDebug() << "KConfig::KConfig(): '" << fileName << "'" << endl; + + load(); +} + + +KConfig::~KConfig() +{ + sync(); +} + +void KConfig::setGroup( const QString &group ) +{ + return; + +// kdDebug() << "KConfig::setGroup(): '" << group << "'" << endl; + + mGroup = group; + + if ( mGroup.right( 1 ) != "/" ) mGroup += "/"; +} + + +QValueList<int> KConfig::readIntListEntry( const QString & ) +{ + QValueList<int> l; + return l; +} + +int KConfig::readNumEntry( const QString &, int def ) +{ + return def; +} + +QString KConfig::readEntry( const QString &key, const QString &def ) +{ + QMap<QString,QString>::ConstIterator it = mStringMap.find( mGroup + key ); + + if ( it == mStringMap.end() ) { + return def; + } + + return *it; +} + +QStringList KConfig::readListEntry( const QString & ) +{ + return QStringList(); +} + +bool KConfig::readBoolEntry( const QString &key, bool def ) +{ + QMap<QString,bool>::ConstIterator it = mBoolMap.find( mGroup + key ); + + if ( it == mBoolMap.end() ) { + return def; + } + + return *it; +} + +QColor KConfig::readColorEntry( const QString &, QColor *def ) +{ + if ( def ) return *def; + return QColor(); +} + +QFont KConfig::readFontEntry( const QString &, QFont *def ) +{ + if ( def ) return *def; + return QFont(); +} + + +void KConfig::writeEntry( const QString &, QValueList<int> ) +{ +} + +void KConfig::writeEntry( const QString &, int ) +{ +} + +void KConfig::writeEntry( const QString &key, const QString &value ) +{ + mStringMap.insert( mGroup + key, value ); + + mDirty = true; +} + +void KConfig::writeEntry( const QString &, const QStringList & ) +{ +} + +void KConfig::writeEntry( const QString &key, bool value) +{ + mBoolMap.insert( mGroup + key, value ); + + mDirty = true; +} + +void KConfig::writeEntry( const QString &, const QColor & ) +{ +} + +void KConfig::writeEntry( const QString &, const QFont & ) +{ +} + +void KConfig::load() +{ + mBoolMap.clear(); + mStringMap.clear(); + + QFile f( mFileName ); + if ( !f.open( IO_ReadOnly ) ) { + kdDebug() << "KConfig::load(): Can't open file '" << mFileName << "'" + << endl; + return; + } + + + QTextStream t( &f ); + + QString line = t.readLine(); + + while ( !line.isNull() ) { + QStringList tokens = QStringList::split( ",", line ); + if ( tokens[0] == "bool" ) { + bool value = false; + if ( tokens[2] == "1" ) value = true; + + mBoolMap.insert( tokens[1], value ); + } else if ( tokens[0] == "QString" ) { + QString value = tokens[2]; + mStringMap.insert( tokens[1], value ); + } + + line = t.readLine(); + } +} + +void KConfig::sync() +{ + if ( !mDirty ) return; + + QFile f( mFileName ); + if ( !f.open( IO_WriteOnly ) ) { + kdDebug() << "KConfig::sync(): Can't open file '" << mFileName << "'" + << endl; + return; + } + + QTextStream t( &f ); + + QMap<QString,bool>::ConstIterator itBool; + for( itBool = mBoolMap.begin(); itBool != mBoolMap.end(); ++itBool ) { + t << "bool," << itBool.key() << "," << (*itBool ) << endl; + } + + QMap<QString,QString>::ConstIterator itString; + for( itString = mStringMap.begin(); itString != mStringMap.end(); ++itString ) { + t << "QString," << itString.key() << "," << (*itString ) << endl; + } + + f.close(); + + mDirty = false; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kconfig.h b/noncore/apps/tinykate/libkate/microkde/kconfig.h new file mode 100644 index 0000000..8bd768a --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kconfig.h @@ -0,0 +1,51 @@ +#ifndef MINIKDE_KCONFIG_H +#define MINIKDE_KCONFIG_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qvaluelist.h> +#include <qcolor.h> +#include <qfont.h> +#include <qmap.h> + +class KConfig +{ + public: + KConfig( const QString & ); + ~KConfig(); + + void setGroup( const QString & ); + + bool hasGroup( const QString &) {return false;} + + QValueList<int> readIntListEntry( const QString & ); + int readNumEntry( const QString &, int def=0 ); + QString readEntry( const QString &, const QString &def=QString::null ); + QStringList readListEntry( const QString & ); + bool readBoolEntry( const QString &, bool def=false ); + QColor readColorEntry( const QString &, QColor * ); + QFont readFontEntry( const QString &, QFont * ); + + void writeEntry( const QString &, QValueList<int> ); + void writeEntry( const QString &, int ); + void writeEntry( const QString &, const QString & ); + void writeEntry( const QString &, const QStringList & ); + void writeEntry( const QString &, bool ); + void writeEntry( const QString &, const QColor & ); + void writeEntry( const QString &, const QFont & ); + + void load(); + void sync(); + + private: + static QString mGroup; + + QString mFileName; + + QMap<QString,bool> mBoolMap; + QMap<QString,QString> mStringMap; + + bool mDirty; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kdatepicker.cpp b/noncore/apps/tinykate/libkate/microkde/kdatepicker.cpp new file mode 100644 index 0000000..2cdd609 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdatepicker.cpp @@ -0,0 +1,405 @@ +/* -*- C++ -*- + This file is part of the KDE libraries + Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) + (C) 1998-2001 Mirko Boehm (mirko@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 "kdatepicker.h" +#include <kglobal.h> +#include <kapplication.h> +#include <klocale.h> +#include <kiconloader.h> +#include <qframe.h> +#include <qpainter.h> +#include <qdialog.h> +#include <qtoolbutton.h> +#include <qfont.h> +#include <qlineedit.h> +#include <qvalidator.h> +#include <kdebug.h> +#include <knotifyclient.h> +#include "kdatetbl.h" +#include "kdatepicker.moc" + + +KDatePicker::KDatePicker(QWidget *parent, QDate dt, const char *name) + : QFrame(parent,name), + yearForward(new QToolButton(this)), + yearBackward(new QToolButton(this)), + monthForward(new QToolButton(this)), + monthBackward(new QToolButton(this)), + selectMonth(new QToolButton(this)), + selectYear(new QToolButton(this)), + line(new QLineEdit(this)), + val(new KDateValidator(this)), + table(new KDateTable(this)), + fontsize(10) +{ + // ----- + setFontSize(10); + line->setValidator(val); + yearForward->setPixmap(BarIcon(QString::fromLatin1("2rightarrow"))); + yearBackward->setPixmap(BarIcon(QString::fromLatin1("2leftarrow"))); + monthForward->setPixmap(BarIcon(QString::fromLatin1("1rightarrow"))); + monthBackward->setPixmap(BarIcon(QString::fromLatin1("1leftarrow"))); + setDate(dt); // set button texts + connect(table, SIGNAL(dateChanged(QDate)), SLOT(dateChangedSlot(QDate))); + connect(table, SIGNAL(tableClicked()), SLOT(tableClickedSlot())); + connect(monthForward, SIGNAL(clicked()), SLOT(monthForwardClicked())); + connect(monthBackward, SIGNAL(clicked()), SLOT(monthBackwardClicked())); + connect(yearForward, SIGNAL(clicked()), SLOT(yearForwardClicked())); + connect(yearBackward, SIGNAL(clicked()), SLOT(yearBackwardClicked())); + connect(selectMonth, SIGNAL(clicked()), SLOT(selectMonthClicked())); + connect(selectYear, SIGNAL(clicked()), SLOT(selectYearClicked())); + connect(line, SIGNAL(returnPressed()), SLOT(lineEnterPressed())); +} + +KDatePicker::~KDatePicker() +{ +} + +void +KDatePicker::resizeEvent(QResizeEvent*) +{ + QWidget *buttons[] = { + yearBackward, + monthBackward, + selectMonth, + selectYear, + monthForward, + yearForward }; + const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); + QSize sizes[NoOfButtons]; + int buttonHeight=0; + int count; + int w; + int x=0; + // ----- calculate button row height: + for(count=0; count<NoOfButtons; ++count) { + sizes[count]=buttons[count]->sizeHint(); + buttonHeight=QMAX(buttonHeight, sizes[count].height()); + } + // ----- calculate size of the month button: + w=0; + for(count=0; count<NoOfButtons; ++count) { + if(buttons[count]!=selectMonth) + { + w+=sizes[count].width(); + } else { + x=count; + } + } + sizes[x].setWidth(width()-w); // stretch the month button + // ----- place the buttons: + x=0; + for(count=0; count<NoOfButtons; ++count) + { + w=sizes[count].width(); + buttons[count]->setGeometry(x, 0, w, buttonHeight); + x+=w; + } + // ----- place the line edit for direct input: + sizes[0]=line->sizeHint(); + line->setGeometry(0, height()-sizes[0].height(), width(), sizes[0].height()); + // ----- adjust the table: + table->setGeometry(0, buttonHeight, width(), + height()-buttonHeight-sizes[0].height()); +} + +void +KDatePicker::dateChangedSlot(QDate date) +{ + kdDebug() << "KDatePicker::dateChangedSlot: date changed (" << date.year() << "/" << date.month() << "/" << date.day() << ")." << endl; + line->setText(KGlobal::locale()->formatDate(date, true)); + emit(dateChanged(date)); +} + +void +KDatePicker::tableClickedSlot() +{ + kdDebug() << "KDatePicker::tableClickedSlot: table clicked." << endl; + emit(dateSelected(table->getDate())); + emit(tableClicked()); +} + +const QDate& +KDatePicker::getDate() const +{ + return table->getDate(); +} + +const QDate & +KDatePicker::date() const +{ + return table->getDate(); +} + +bool +KDatePicker::setDate(const QDate& date) +{ + if(date.isValid()) { + QString temp; + // ----- + table->setDate(date); + selectMonth->setText(KGlobal::locale()->monthName(date.month(), false)); + temp.setNum(date.year()); + selectYear->setText(temp); + line->setText(KGlobal::locale()->formatDate(date, true)); + return true; + } else { + kdDebug() << "KDatePicker::setDate: refusing to set invalid date." << endl; + return false; + } +} + +void +KDatePicker::monthForwardClicked() +{ + QDate temp=table->getDate(); + int day=temp.day(); + // ----- + if(temp.month()==12) { + temp.setYMD(temp.year()+1, 1, 1); + } else { + temp.setYMD(temp.year(), temp.month()+1, 1); + } + if(temp.daysInMonth()<day) { + temp.setYMD(temp.year(), temp.month(), temp.daysInMonth()); + } else { + temp.setYMD(temp.year(), temp.month(), day); + } + // assert(temp.isValid()); + setDate(temp); +} + +void +KDatePicker::monthBackwardClicked() +{ + QDate temp=table->getDate(); + int day=temp.day(); + // ----- + if(temp.month()==1) + { + temp.setYMD(temp.year()-1, 12, 1); + } else { + temp.setYMD(temp.year(), temp.month()-1, 1); + } + if(temp.daysInMonth()<day) + { + temp.setYMD(temp.year(), temp.month(), temp.daysInMonth()); + } else { + temp.setYMD(temp.year(), temp.month(), day); + } + // assert(temp.isValid()); + setDate(temp); +} + +void +KDatePicker::yearForwardClicked() +{ + QDate temp=table->getDate(); + int day=temp.day(); + // ----- + temp.setYMD(temp.year()+1, temp.month(), 1); + if(temp.daysInMonth()<day) + { + temp.setYMD(temp.year(), temp.month(), temp.daysInMonth()); + } else { + temp.setYMD(temp.year(), temp.month(), day); + } + // assert(temp.isValid()); + setDate(temp); +} + +void +KDatePicker::yearBackwardClicked() +{ + QDate temp=table->getDate(); + int day=temp.day(); + // ----- + temp.setYMD(temp.year()-1, temp.month(), 1); + if(temp.daysInMonth()<day) + { + temp.setYMD(temp.year(), temp.month(), temp.daysInMonth()); + } else { + temp.setYMD(temp.year(), temp.month(), day); + } + // assert(temp.isValid()); + setDate(temp); +} + +void +KDatePicker::selectMonthClicked() +{ + int month; + KPopupFrame* popup = new KPopupFrame(this); + KDateInternalMonthPicker* picker = new KDateInternalMonthPicker(fontsize, popup); + // ----- + picker->resize(picker->sizeHint()); + popup->setMainWidget(picker); + picker->setFocus(); + connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int))); + if(popup->exec(selectMonth->mapToGlobal(QPoint(0, selectMonth->height())))) + { + QDate date; + int day; + // ----- + month=picker->getResult(); + date=table->getDate(); + day=date.day(); + // ----- construct a valid date in this month: + date.setYMD(date.year(), month, 1); + date.setYMD(date.year(), month, QMIN(day, date.daysInMonth())); + // ----- set this month + setDate(date); + } else { + KNotifyClient::beep(); + } + delete popup; +} + +void +KDatePicker::selectYearClicked() +{ + int year; + KPopupFrame* popup = new KPopupFrame(this); + KDateInternalYearSelector* picker = new KDateInternalYearSelector(fontsize, popup); + // ----- + picker->resize(picker->sizeHint()); + popup->setMainWidget(picker); + connect(picker, SIGNAL(closeMe(int)), popup, SLOT(close(int))); + picker->setFocus(); + if(popup->exec(selectYear->mapToGlobal(QPoint(0, selectMonth->height())))) + { + QDate date; + int day; + // ----- + year=picker->getYear(); + date=table->getDate(); + day=date.day(); + // ----- construct a valid date in this month: + date.setYMD(year, date.month(), 1); + date.setYMD(year, date.month(), QMIN(day, date.daysInMonth())); + // ----- set this month + setDate(date); + } else { + KNotifyClient::beep(); + } + delete popup; +} + +void +KDatePicker::setEnabled(bool enable) +{ + QWidget *widgets[]= { + yearForward, yearBackward, monthForward, monthBackward, + selectMonth, selectYear, + line, table }; + const int Size=sizeof(widgets)/sizeof(widgets[0]); + int count; + // ----- + for(count=0; count<Size; ++count) + { + widgets[count]->setEnabled(enable); + } +} + +void +KDatePicker::lineEnterPressed() +{ + QDate temp; + // ----- + if(val->date(line->text(), temp)==QValidator::Acceptable) + { + kdDebug() << "KDatePicker::lineEnterPressed: valid date entered." << endl; + emit(dateEntered(temp)); + setDate(temp); + } else { + KNotifyClient::beep(); + kdDebug() << "KDatePicker::lineEnterPressed: invalid date entered." << endl; + } +} + +QSize +KDatePicker::sizeHint() const +{ + QSize tableSize=table->sizeHint(); + QWidget *buttons[]={ + yearBackward, + monthBackward, + selectMonth, + selectYear, + monthForward, + yearForward }; + const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); + QSize sizes[NoOfButtons]; + int cx=0, cy=0, count; + // ----- store the size hints: + for(count=0; count<NoOfButtons; ++count) + { + sizes[count]=buttons[count]->sizeHint(); + if(buttons[count]==selectMonth) + { + cx+=maxMonthRect.width(); + } else { + cx+=sizes[count].width(); + } + cy=QMAX(sizes[count].height(), cy); + } + // ----- calculate width hint: + cx=QMAX(cx, tableSize.width()); // line edit ignored + // ----- calculate height hint: + cy+=tableSize.height()+line->sizeHint().height(); + return QSize(cx, cy); +} + +void +KDatePicker::setFontSize(int s) +{ + QWidget *buttons[]= { + // yearBackward, + // monthBackward, + selectMonth, + selectYear, + // monthForward, + // yearForward + }; + const int NoOfButtons=sizeof(buttons)/sizeof(buttons[0]); + int count; + QFont font; + QRect r; + // ----- + fontsize=s; + for(count=0; count<NoOfButtons; ++count) + { + font=buttons[count]->font(); + font.setPointSize(s); + buttons[count]->setFont(font); + } + QFontMetrics metrics(selectMonth->fontMetrics()); + for(int i=1; i <= 12; ++i) + { // maxMonthRect is used by sizeHint() + r=metrics.boundingRect(KGlobal::locale()->monthName(i, false)); + maxMonthRect.setWidth(QMAX(r.width(), maxMonthRect.width())); + maxMonthRect.setHeight(QMAX(r.height(), maxMonthRect.height())); + } + table->setFontSize(s); +} + +void KDatePicker::virtual_hook( int id, void* data ) +{ /*BASE::virtual_hook( id, data );*/ } + diff --git a/noncore/apps/tinykate/libkate/microkde/kdatepicker.h b/noncore/apps/tinykate/libkate/microkde/kdatepicker.h new file mode 100644 index 0000000..8fe8d66 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdatepicker.h @@ -0,0 +1,177 @@ +/* -*- C++ -*- + This file is part of the KDE libraries + Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) + (C) 1998-2001 Mirko Boehm (mirko@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 MICROKDE_KDATEPICKER_H +#define MICROKDE_KDATEPICKER_H +#include <qdatetime.h> +#include <qframe.h> + +class QLineEdit; +class QToolButton; +class KDateValidator; +class KDateTable; + +/** + * Provides a widget for calendar date input. + * + * Different from the + * previous versions, it now emits two types of signals, either + * @ref dateSelected() or @ref dateEntered() (see documentation for both + * signals). + * + * A line edit has been added in the newer versions to allow the user + * to select a date directly by entering numbers like 19990101 + * or 990101. + * + * @image kdatepicker.png KDatePicker + * + * @version $Id$ + * @author Tim Gilman, Mirko Boehm + * + * @short A date selection widget. + **/ +class KDatePicker: public QFrame +{ + Q_OBJECT +public: + /** The usual constructor. The given date will be displayed + * initially. + **/ + KDatePicker(QWidget *parent=0, + QDate=QDate::currentDate(), + const char *name=0); + /** + * The destructor. + **/ + virtual ~KDatePicker(); + + /** The size hint for date pickers. The size hint recommends the + * minimum size of the widget so that all elements may be placed + * without clipping. This sometimes looks ugly, so when using the + * size hint, try adding 28 to each of the reported numbers of + * pixels. + **/ + QSize sizeHint() const; + + /** + * Sets the date. + * + * @returns @p false and does not change anything + * if the date given is invalid. + **/ + bool setDate(const QDate&); + + /** + * Returns the selected date. + * @deprecated + **/ + const QDate& getDate() const; + + /** + * @returns the selected date. + */ + const QDate &date() const; + + /** + * Enables or disables the widget. + **/ + void setEnabled(bool); + + /** + * Sets the font size of the widgets elements. + **/ + void setFontSize(int); + /** + * Returns the font size of the widget elements. + */ + int fontSize() const + { return fontsize; } + +protected: + /// the resize event + void resizeEvent(QResizeEvent*); + /// the year forward button + QToolButton *yearForward; + /// the year backward button + QToolButton *yearBackward; + /// the month forward button + QToolButton *monthForward; + /// the month backward button + QToolButton *monthBackward; + /// the button for selecting the month directly + QToolButton *selectMonth; + /// the button for selecting the year directly + QToolButton *selectYear; + /// the line edit to enter the date directly + QLineEdit *line; + /// the validator for the line edit: + KDateValidator *val; + /// the date table + KDateTable *table; + /// the size calculated during resize events + // QSize sizehint; + /// the widest month string in pixels: + QSize maxMonthRect; +protected slots: + void dateChangedSlot(QDate); + void tableClickedSlot(); + void monthForwardClicked(); + void monthBackwardClicked(); + void yearForwardClicked(); + void yearBackwardClicked(); + void selectMonthClicked(); + void selectYearClicked(); + void lineEnterPressed(); +signals: + /** This signal is emitted each time the selected date is changed. + * Usually, this does not mean that the date has been entered, + * since the date also changes, for example, when another month is + * selected. + * @see dateSelected + */ + void dateChanged(QDate); + /** This signal is emitted each time a day has been selected by + * clicking on the table (hitting a day in the current month). It + * has the same meaning as dateSelected() in older versions of + * KDatePicker. + */ + void dateSelected(QDate); + /** This signal is emitted when enter is pressed and a VALID date + * has been entered before into the line edit. Connect to both + * dateEntered() and dateSelected() to receive all events where the + * user really enters a date. + */ + void dateEntered(QDate); + /** This signal is emitted when the day has been selected by + * clicking on it in the table. + */ + void tableClicked(); + +private: + /// the font size for the widget + int fontsize; + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class KDatePickerPrivate; + KDatePickerPrivate *d; +}; + +#endif // KDATEPICKER_H diff --git a/noncore/apps/tinykate/libkate/microkde/kdatetbl.cpp b/noncore/apps/tinykate/libkate/microkde/kdatetbl.cpp new file mode 100644 index 0000000..c56991d --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdatetbl.cpp @@ -0,0 +1,718 @@ +/* -*- C++ -*- + This file is part of the KDE libraries + Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) + (C) 1998-2001 Mirko Boehm (mirko@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. +*/ + +/////////////////// KDateTable widget class ////////////////////// +// +// Copyright (C) 1997 Tim D. Gilman +// (C) 1998-2001 Mirko Boehm +// Written using Qt (http://www.troll.no) for the +// KDE project (http://www.kde.org) +// +// This is a support class for the KDatePicker class. It just +// draws the calender table without titles, but could theoretically +// be used as a standalone. +// +// When a date is selected by the user, it emits a signal: +// dateSelected(QDate) + +#include <kglobal.h> +#include <kglobalsettings.h> +#include <kapplication.h> +#include <klocale.h> +#include <kdebug.h> +#include <knotifyclient.h> +#include "kdatetbl.h" +#include <qdatetime.h> +#include <qstring.h> +#include <qpen.h> +#include <qpainter.h> +#include <qdialog.h> +#include <assert.h> +#include <qapplication.h> + +KDateValidator::KDateValidator(QWidget* parent, const char* name) + : QValidator(parent, name) +{ +} + +QValidator::State +KDateValidator::validate(QString& text, int&) const +{ + QDate temp; + // ----- everything is tested in date(): + return date(text, temp); +} + +QValidator::State +KDateValidator::date(const QString& text, QDate& d) const +{ + QDate tmp = KGlobal::locale()->readDate(text); + if (!tmp.isNull()) + { + d = tmp; + return Acceptable; + } else + return Valid; +} + +void +KDateValidator::fixup( QString& ) const +{ + +} + +KDateTable::KDateTable(QWidget *parent, QDate date_, const char* name, WFlags f) + : QGridView(parent, name, f) +{ + setFontSize(10); + if(!date_.isValid()) + { + kdDebug() << "KDateTable ctor: WARNING: Given date is invalid, using current date." << endl; + date_=QDate::currentDate(); + } + setFocusPolicy( QWidget::StrongFocus ); + setNumRows(7); // 6 weeks max + headline + setNumCols(7); // 7 days a week + setHScrollBarMode(AlwaysOff); + setVScrollBarMode(AlwaysOff); +#if 0 + viewport()->setEraseColor(lightGray); +#endif + setDate(date_); // this initializes firstday, numdays, numDaysPrevMonth +} + +void +KDateTable::paintCell(QPainter *painter, int row, int col) +{ + QRect rect; + QString text; + QPen pen; + int w=cellWidth(); + int h=cellHeight(); + int pos; + QBrush brushBlue(blue); + QBrush brushLightblue(lightGray); + QFont font=KGlobalSettings::generalFont(); + // ----- + font.setPointSize(fontsize); + if(row==0) + { // we are drawing the headline + font.setBold(true); + painter->setFont(font); + bool normalday = true; + QString daystr; + if (KGlobal::locale()->weekStartsMonday()) + { + daystr = KGlobal::locale()->weekDayName(col+1, true); + if (col == 5 || col == 6) + normalday = false; + } else { + daystr = KGlobal::locale()->weekDayName(col==0? 7 : col, true); + if (col == 0 || col == 6) + normalday = false; + } + if (!normalday) + { + painter->setPen(lightGray); + painter->setBrush(brushLightblue); + painter->drawRect(0, 0, w, h); + painter->setPen(blue); + } else { + painter->setPen(blue); + painter->setBrush(brushBlue); + painter->drawRect(0, 0, w, h); + painter->setPen(white); + } + painter->drawText(0, 0, w, h-1, AlignCenter, + daystr, -1, &rect); + painter->setPen(black); + painter->moveTo(0, h-1); + painter->lineTo(w-1, h-1); + // ----- draw the weekday: + } else { + painter->setFont(font); + pos=7*(row-1)+col; + if (KGlobal::locale()->weekStartsMonday()) + pos++; + if(pos<firstday || (firstday+numdays<=pos)) + { // we are either + // ° painting a day of the previous month or + // ° painting a day of the following month + if(pos<firstday) + { // previous month + text.setNum(numDaysPrevMonth+pos-firstday+1); + } else { // following month + text.setNum(pos-firstday-numdays+1); + } + painter->setPen(gray); + } else { // paint a day of the current month + text.setNum(pos-firstday+1); + painter->setPen(black); + } + + pen=painter->pen(); + if(firstday+date.day()-1==pos) + { + if(hasFocus()) + { // draw the currently selected date + painter->setPen(red); + painter->setBrush(darkRed); + pen=white; + } else { + painter->setPen(darkGray); + painter->setBrush(darkGray); + pen=white; + } + } else { + painter->setBrush(lightGray); + painter->setPen(lightGray); + } + painter->drawRect(0, 0, w, h); + painter->setPen(pen); + painter->drawText(0, 0, w, h, AlignCenter, text, -1, &rect); + } + if(rect.width()>maxCell.width()) maxCell.setWidth(rect.width()); + if(rect.height()>maxCell.height()) maxCell.setHeight(rect.height()); +} + +void +KDateTable::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Qt::Key_Prior ) { + if ( date.month() == 1 ) { + KNotifyClient::beep(); + return; + } + int day = date.day(); + if ( day > 27 ) + while ( !QDate::isValid( date.year(), date.month()-1, day ) ) + day--; + setDate(QDate(date.year(), date.month()-1, day)); + return; + } + if ( e->key() == Qt::Key_Next ) { + if ( date.month() == 12 ) { + KNotifyClient::beep(); + return; + } + int day = date.day(); + if ( day > 27 ) + while ( !QDate::isValid( date.year(), date.month()+1, day ) ) + day--; + setDate(QDate(date.year(), date.month()+1, day)); + return; + } + + int dayoff = KGlobal::locale()->weekStartsMonday() ? 1 : 0; + + int temp=firstday+date.day()-dayoff; + int pos = temp; + + if ( e->key() == Qt::Key_Up ) { + pos -= 7; + } + if ( e->key() == Qt::Key_Down ) { + pos += 7; + } + if ( e->key() == Qt::Key_Left ) { + pos--; + } + if ( e->key() == Qt::Key_Right ) { + pos++; + } + + if(pos+dayoff<=firstday) + { // this day is in the previous month + KNotifyClient::beep(); + return; + } + if(firstday+numdays<pos+dayoff) + { // this date is in the next month + KNotifyClient::beep(i18n( "Month not long enough" )); + return; + } + + if ( pos == temp ) + return; + + setDate(QDate(date.year(), date.month(), pos-firstday+dayoff)); + updateCell(temp/7+1, temp%7); // Update the previously selected cell + updateCell(pos/7+1, pos%7); // Update the selected cell + assert(QDate(date.year(), date.month(), pos-firstday+dayoff).isValid()); +} + +void +KDateTable::viewportResizeEvent(QResizeEvent * e) +{ + QGridView::viewportResizeEvent(e); + + setCellWidth(viewport()->width()/7); + setCellHeight(viewport()->height()/7); +} + +void +KDateTable::setFontSize(int size) +{ + int count; + QFontMetrics metrics(fontMetrics()); + QRect rect; + // ----- store rectangles: + fontsize=size; + // ----- find largest day name: + maxCell.setWidth(0); + maxCell.setHeight(0); + for(count=0; count<7; ++count) + { + rect=metrics.boundingRect(KGlobal::locale()->weekDayName(count+1, true)); + maxCell.setWidth(QMAX(maxCell.width(), rect.width())); + maxCell.setHeight(QMAX(maxCell.height(), rect.height())); + } + // ----- compare with a real wide number and add some space: + rect=metrics.boundingRect(QString::fromLatin1("88")); + maxCell.setWidth(QMAX(maxCell.width()+2, rect.width())); + maxCell.setHeight(QMAX(maxCell.height()+4, rect.height())); +} + +void +KDateTable::contentsMousePressEvent(QMouseEvent *e) +{ + if(e->type()!=QEvent::MouseButtonPress) + { // the KDatePicker only reacts on mouse press events: + return; + } + if(!isEnabled()) + { + KNotifyClient::beep(); + return; + } + + int dayoff = KGlobal::locale()->weekStartsMonday() ? 1 : 0; + // ----- + int row, col, pos, temp; + QPoint mouseCoord; + // ----- + mouseCoord = e->pos(); + row=rowAt(mouseCoord.y()); + col=columnAt(mouseCoord.x()); + if(row<0 || col<0) + { // the user clicked on the frame of the table + return; + } + pos=7*(row-1)+col+1; + if(pos+dayoff<=firstday) + { // this day is in the previous month + KNotifyClient::beep(); + return; + } + if(firstday+numdays<pos+dayoff) + { // this date is in the next month + KNotifyClient::beep(); + return; + } + temp=firstday+date.day()-dayoff-1; + setDate(QDate(date.year(), date.month(), pos-firstday+dayoff)); + updateCell(temp/7+1, temp%7); // Update the previously selected cell + updateCell(row, col); // Update the selected cell + // assert(QDate(date.year(), date.month(), pos-firstday+dayoff).isValid()); + emit(tableClicked()); +} + +bool +KDateTable::setDate(const QDate& date_) +{ + bool changed=false; + QDate temp; + // ----- + if(!date_.isValid()) + { + kdDebug() << "KDateTable::setDate: refusing to set invalid date." << endl; + return false; + } + if(date!=date_) + { + date=date_; + changed=true; + } + temp.setYMD(date.year(), date.month(), 1); + firstday=temp.dayOfWeek(); + if(firstday==1) firstday=8; + numdays=date.daysInMonth(); + if(date.month()==1) + { // set to december of previous year + temp.setYMD(date.year()-1, 12, 1); + } else { // set to previous month + temp.setYMD(date.year(), date.month()-1, 1); + } + numDaysPrevMonth=temp.daysInMonth(); + if(changed) + { + repaintContents(false); + } + emit(dateChanged(date)); + return true; +} + +const QDate& +KDateTable::getDate() const +{ + return date; +} + +void KDateTable::focusInEvent( QFocusEvent *e ) +{ + repaintContents(false); + QGridView::focusInEvent( e ); +} + +void KDateTable::focusOutEvent( QFocusEvent *e ) +{ + repaintContents(false); + QGridView::focusOutEvent( e ); +} + +QSize +KDateTable::sizeHint() const +{ + if(maxCell.height()>0 && maxCell.width()>0) + { + return QSize(maxCell.width()*numCols()+2*frameWidth(), + (maxCell.height()+2)*numRows()+2*frameWidth()); + } else { + kdDebug() << "KDateTable::sizeHint: obscure failure - " << endl; + return QSize(-1, -1); + } +} + +KDateInternalMonthPicker::KDateInternalMonthPicker +(int fontsize, QWidget* parent, const char* name) + : QGridView(parent, name), + result(0) // invalid +{ + QRect rect; + QFont font; + // ----- + activeCol = -1; + activeRow = -1; + font=KGlobalSettings::generalFont(); + font.setPointSize(fontsize); + setFont(font); + setHScrollBarMode(AlwaysOff); + setVScrollBarMode(AlwaysOff); + setFrameStyle(QFrame::NoFrame); + setNumRows(4); + setNumCols(3); + // enable to find drawing failures: + // setTableFlags(Tbl_clipCellPainting); +#if 0 + viewport()->setEraseColor(lightGray); // for consistency with the datepicker +#endif + // ----- find the preferred size + // (this is slow, possibly, but unfortunatly it is needed here): + QFontMetrics metrics(font); + for(int i=1; i <= 12; ++i) + { + rect=metrics.boundingRect(KGlobal::locale()->monthName(i, false)); + if(max.width()<rect.width()) max.setWidth(rect.width()); + if(max.height()<rect.height()) max.setHeight(rect.height()); + } + +} + +QSize +KDateInternalMonthPicker::sizeHint() const +{ + return QSize((max.width()+6)*numCols()+2*frameWidth(), + (max.height()+6)*numRows()+2*frameWidth()); +} + +int +KDateInternalMonthPicker::getResult() const +{ + return result; +} + +void +KDateInternalMonthPicker::setupPainter(QPainter *p) +{ + p->setPen(black); +} + +void +KDateInternalMonthPicker::viewportResizeEvent(QResizeEvent*) +{ + setCellWidth(width()/3); + setCellHeight(height()/4); +} + +void +KDateInternalMonthPicker::paintCell(QPainter* painter, int row, int col) +{ + int index; + QString text; + // ----- find the number of the cell: + index=3*row+col+1; + text=KGlobal::locale()->monthName(index, false); + painter->drawText(0, 0, cellWidth(), cellHeight(), AlignCenter, text); + if ( activeCol == col && activeRow == row ) + painter->drawRect( 0, 0, cellWidth(), cellHeight() ); +} + +void +KDateInternalMonthPicker::contentsMousePressEvent(QMouseEvent *e) +{ + if(!isEnabled() || e->button() != LeftButton) + { + KNotifyClient::beep(); + return; + } + // ----- + int row, col; + QPoint mouseCoord; + // ----- + mouseCoord = e->pos(); + row=rowAt(mouseCoord.y()); + col=columnAt(mouseCoord.x()); + + if(row<0 || col<0) + { // the user clicked on the frame of the table + activeCol = -1; + activeRow = -1; + } else { + activeCol = col; + activeRow = row; + updateCell( row, col /*, false */ ); + } +} + +void +KDateInternalMonthPicker::contentsMouseMoveEvent(QMouseEvent *e) +{ + if (e->state() & LeftButton) + { + int row, col; + QPoint mouseCoord; + // ----- + mouseCoord = e->pos(); + row=rowAt(mouseCoord.y()); + col=columnAt(mouseCoord.x()); + int tmpRow = -1, tmpCol = -1; + if(row<0 || col<0) + { // the user clicked on the frame of the table + if ( activeCol > -1 ) + { + tmpRow = activeRow; + tmpCol = activeCol; + } + activeCol = -1; + activeRow = -1; + } else { + bool differentCell = (activeRow != row || activeCol != col); + if ( activeCol > -1 && differentCell) + { + tmpRow = activeRow; + tmpCol = activeCol; + } + if ( differentCell) + { + activeRow = row; + activeCol = col; + updateCell( row, col /*, false */ ); // mark the new active cell + } + } + if ( tmpRow > -1 ) // repaint the former active cell + updateCell( tmpRow, tmpCol /*, true */ ); + } +} + +void +KDateInternalMonthPicker::contentsMouseReleaseEvent(QMouseEvent *e) +{ + if(!isEnabled()) + { + return; + } + // ----- + int row, col, pos; + QPoint mouseCoord; + // ----- + mouseCoord = e->pos(); + row=rowAt(mouseCoord.y()); + col=columnAt(mouseCoord.x()); + if(row<0 || col<0) + { // the user clicked on the frame of the table + emit(closeMe(0)); + } + pos=3*row+col+1; + result=pos; + emit(closeMe(1)); +} + + + +KDateInternalYearSelector::KDateInternalYearSelector +(int fontsize, QWidget* parent, const char* name) + : QLineEdit(parent, name), + val(new QIntValidator(this)), + result(0) +{ + QFont font; + // ----- + font=KGlobalSettings::generalFont(); + font.setPointSize(fontsize); + setFont(font); +#if 0 + setFrameStyle(QFrame::NoFrame); +#endif + // we have to respect the limits of QDate here, I fear: + val->setRange(0, 8000); + setValidator(val); + connect(this, SIGNAL(returnPressed()), SLOT(yearEnteredSlot())); +} + +void +KDateInternalYearSelector::yearEnteredSlot() +{ + bool ok; + int year; + QDate date; + // ----- check if this is a valid year: + year=text().toInt(&ok); + if(!ok) + { + KNotifyClient::beep(); + return; + } + date.setYMD(year, 1, 1); + if(!date.isValid()) + { + KNotifyClient::beep(); + return; + } + result=year; + emit(closeMe(1)); +} + +int +KDateInternalYearSelector::getYear() +{ + return result; +} + +void +KDateInternalYearSelector::setYear(int year) +{ + QString temp; + // ----- + temp.setNum(year); + setText(temp); +} + +KPopupFrame::KPopupFrame(QWidget* parent, const char* name) + : QFrame(parent, name, WType_Popup), + result(0), // rejected + main(0) +{ + setFrameStyle(QFrame::Box|QFrame::Raised); + setMidLineWidth(2); +} + +void +KPopupFrame::keyPressEvent(QKeyEvent* e) +{ + if(e->key()==Key_Escape) + { + result=0; // rejected + qApp->exit_loop(); + } +} + +void +KPopupFrame::close(int r) +{ + result=r; + qApp->exit_loop(); +} + +void +KPopupFrame::setMainWidget(QWidget* m) +{ + main=m; + if(main!=0) + { + resize(main->width()+2*frameWidth(), main->height()+2*frameWidth()); + } +} + +void +KPopupFrame::resizeEvent(QResizeEvent*) +{ + if(main!=0) + { + main->setGeometry(frameWidth(), frameWidth(), + width()-2*frameWidth(), height()-2*frameWidth()); + } +} + +void +KPopupFrame::popup(const QPoint &pos) +{ + // Make sure the whole popup is visible. + QRect d = QApplication::desktop()->frameGeometry(); + int x = pos.x(); + int y = pos.y(); + int w = width(); + int h = height(); + if (x+w > d.x()+d.width()) + x = d.width() - w; + if (y+h > d.y()+d.height()) + y = d.height() - h; + if (x < d.x()) + x = 0; + if (y < d.y()) + y = 0; + + // Pop the thingy up. + move(x, y); + show(); +} + +int +KPopupFrame::exec(QPoint pos) +{ + popup(pos); + repaint(); + qApp->enter_loop(); + hide(); + return result; +} + +int +KPopupFrame::exec(int x, int y) +{ + return exec(QPoint(x, y)); +} + +void KPopupFrame::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +void KDateTable::virtual_hook( int, void* ) +{ /*BASE::virtual_hook( id, data );*/ } + +#include "kdatetbl.moc" diff --git a/noncore/apps/tinykate/libkate/microkde/kdatetbl.h b/noncore/apps/tinykate/libkate/microkde/kdatetbl.h new file mode 100644 index 0000000..df7b7ef --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdatetbl.h @@ -0,0 +1,308 @@ +/* -*- C++ -*- + This file is part of the KDE libraries + Copyright (C) 1997 Tim D. Gilman (tdgilman@best.org) + (C) 1998-2001 Mirko Boehm (mirko@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 KDATETBL_H +#define KDATETBL_H + +#include <qvalidator.h> +#include <qgridview.h> +#include <qlineedit.h> +#include <qdatetime.h> + +/** +* A table containing month names. It is used to pick a month directly. +* @internal +* @version $Id$ +* @author Tim Gilman, Mirko Boehm +*/ +class KDateInternalMonthPicker : public QGridView +{ + Q_OBJECT +protected: + /** + * Store the month that has been clicked [1..12]. + */ + int result; + /** + * the cell under mouse cursor when LBM is pressed + */ + short int activeCol; + short int activeRow; + /** + * Contains the largest rectangle needed by the month names. + */ + QRect max; +signals: + /** + * This is send from the mouse click event handler. + */ + void closeMe(int); +public: + /** + * The constructor. + */ + KDateInternalMonthPicker(int fontsize, QWidget* parent, const char* name=0); + /** + * The size hint. + */ + QSize sizeHint() const; + /** + * Return the result. 0 means no selection (reject()), 1..12 are the + * months. + */ + int getResult() const; +protected: + /** + * Set up the painter. + */ + void setupPainter(QPainter *p); + /** + * The resize event. + */ + void viewportResizeEvent(QResizeEvent*); + /** + * Paint a cell. This simply draws the month names in it. + */ + virtual void paintCell(QPainter* painter, int row, int col); + /** + * Catch mouse click and move events to paint a rectangle around the item. + */ + void contentsMousePressEvent(QMouseEvent *e); + void contentsMouseMoveEvent(QMouseEvent *e); + /** + * Emit monthSelected(int) when a cell has been released. + */ + void contentsMouseReleaseEvent(QMouseEvent *e); + +private: + class KDateInternalMonthPrivate; + KDateInternalMonthPrivate *d; +}; + +/** Year selection widget. +* @internal +* @version $Id$ +* @author Tim Gilman, Mirko Boehm +*/ +class KDateInternalYearSelector : public QLineEdit +{ + Q_OBJECT +protected: + QIntValidator *val; + int result; +public slots: + void yearEnteredSlot(); +signals: + void closeMe(int); +public: + KDateInternalYearSelector(int fontsize, + QWidget* parent=0, + const char* name=0); + int getYear(); + void setYear(int year); + +private: + class KDateInternalYearPrivate; + KDateInternalYearPrivate *d; +}; + +/** + * Frame with popup menu behaviour. + * @author Tim Gilman, Mirko Boehm + * @version $Id$ + */ +class KPopupFrame : public QFrame +{ + Q_OBJECT +protected: + /** + * The result. It is returned from exec() when the popup window closes. + */ + int result; + /** + * Catch key press events. + */ + void keyPressEvent(QKeyEvent* e); + /** + * The only subwidget that uses the whole dialog window. + */ + QWidget *main; +public slots: + /** + * Close the popup window. This is called from the main widget, usually. + * @p r is the result returned from exec(). + */ + void close(int r); +public: + /** + * The contructor. Creates a dialog without buttons. + */ + KPopupFrame(QWidget* parent=0, const char* name=0); + /** + * Set the main widget. You cannot set the main widget from the constructor, + * since it must be a child of the frame itselfes. + * Be careful: the size is set to the main widgets size. It is up to you to + * set the main widgets correct size before setting it as the main + * widget. + */ + void setMainWidget(QWidget* m); + /** + * The resize event. Simply resizes the main widget to the whole + * widgets client size. + */ + void resizeEvent(QResizeEvent*); + /** + * Open the popup window at position pos. + */ + void popup(const QPoint &pos); + /** + * Execute the popup window. + */ + int exec(QPoint p); + /** + * Dito. + */ + int exec(int x, int y); + +private: + + virtual bool close(bool alsoDelete) { return QFrame::close(alsoDelete); } +protected: + virtual void virtual_hook( int id, void* data ); +private: + class KPopupFramePrivate; + KPopupFramePrivate *d; +}; + +/** +* Validates user-entered dates. +*/ +class KDateValidator : public QValidator +{ +public: + KDateValidator(QWidget* parent=0, const char* name=0); + virtual State validate(QString&, int&) const; + virtual void fixup ( QString & input ) const; + State date(const QString&, QDate&) const; +}; + +/** + * Date selection table. + * This is a support class for the KDatePicker class. It just + * draws the calender table without titles, but could theoretically + * be used as a standalone. + * + * When a date is selected by the user, it emits a signal: + * dateSelected(QDate) + * + * @internal + * @version $Id$ + * @author Tim Gilman, Mirko Boehm + */ +class KDateTable : public QGridView +{ + Q_OBJECT +public: + /** + * The constructor. + */ + KDateTable(QWidget *parent=0, + QDate date=QDate::currentDate(), + const char* name=0, WFlags f=0); + /** + * Returns a recommended size for the widget. + * To save some time, the size of the largest used cell content is + * calculated in each paintCell() call, since all calculations have + * to be done there anyway. The size is stored in maxCell. The + * sizeHint() simply returns a multiple of maxCell. + */ + virtual QSize sizeHint() const; + /** + * Set the font size of the date table. + */ + void setFontSize(int size); + /** + * Select and display this date. + */ + bool setDate(const QDate&); + const QDate& getDate() const; + + +protected: + /** + * Paint a cell. + */ + virtual void paintCell(QPainter*, int, int); + /** + * Handle the resize events. + */ + virtual void viewportResizeEvent(QResizeEvent *); + /** + * React on mouse clicks that select a date. + */ + virtual void contentsMousePressEvent(QMouseEvent *); + virtual void keyPressEvent( QKeyEvent *e ); + virtual void focusInEvent( QFocusEvent *e ); + virtual void focusOutEvent( QFocusEvent *e ); + /** + * The font size of the displayed text. + */ + int fontsize; + /** + * The currently selected date. + */ + QDate date; + /** + * The day of the first day in the month [1..7]. + */ + int firstday; + /** + * The number of days in the current month. + */ + int numdays; + /** + * The number of days in the previous month. + */ + int numDaysPrevMonth; + /** + * unused + */ + bool unused_hasSelection; + /** + * Save the size of the largest used cell content. + */ + QRect maxCell; +signals: + /** + * The selected date changed. + */ + void dateChanged(QDate); + /** + * A date has been selected by clicking on the table. + */ + void tableClicked(); + +protected: + virtual void virtual_hook( int id, void* data ); +private: + class KDateTablePrivate; + KDateTablePrivate *d; +}; + +#endif // KDATETBL_H diff --git a/noncore/apps/tinykate/libkate/microkde/kdebug.h b/noncore/apps/tinykate/libkate/microkde/kdebug.h new file mode 100644 index 0000000..9042644 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdebug.h @@ -0,0 +1,112 @@ +#ifndef MINIKDE_KDEBUG_H +#define MINIKDE_KDEBUG_H + +#include <stdio.h> + +#include <qstring.h> + +class kdbgstream; +typedef kdbgstream & (*KDBGFUNC)(kdbgstream &); // manipulator function + +class kdbgstream { + public: + kdbgstream(unsigned int _area, unsigned int _level, bool _print = true) : + area(_area), level(_level), print(_print) { } + kdbgstream(const char * initialString, unsigned int _area, unsigned int _level, bool _print = true) : + output(QString::fromLatin1(initialString)), area(_area), level(_level), print(_print) { } + ~kdbgstream() + { + if (!output.isEmpty()) { + fprintf(stderr,"ASSERT: debug output not ended with \\n\n"); + *this << "\n"; + } + } + kdbgstream &operator<<(bool i) { + if (!print) return *this; + output += QString::fromLatin1(i ? "true" : "false"); + return *this; + } + kdbgstream &operator<<(short i) { + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; + } + kdbgstream &operator<<(unsigned short i) { + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; + } + kdbgstream &operator<<(char i) { + if (!print) return *this; + QString tmp; tmp.setNum(int(i)); output += tmp; + return *this; + } + kdbgstream &operator<<(unsigned char i) { + if (!print) return *this; + QString tmp; tmp.setNum(static_cast<unsigned int>(i)); output += tmp; + return *this; + } + + kdbgstream &operator<<(int i) { + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; + } + kdbgstream &operator<<(unsigned int i) { + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; + } + kdbgstream &operator<<(long i) { + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; + } + kdbgstream &operator<<(unsigned long i) { + if (!print) return *this; + QString tmp; tmp.setNum(i); output += tmp; + return *this; + } + kdbgstream &operator<<(const QString& string) { + if (!print) return *this; + output += string; + if (output.at(output.length() -1 ) == '\n') + flush(); + return *this; + } + kdbgstream &operator<<(const char *string) { + if (!print) return *this; + output += QString::fromUtf8(string); + if (output.at(output.length() - 1) == '\n') + flush(); + return *this; + } + kdbgstream &operator<<(const QCString& string) { + *this << string.data(); + return *this; + } + kdbgstream& operator<<(KDBGFUNC f) { + if (!print) return *this; + return (*f)(*this); + } + kdbgstream& operator<<(double d) { + QString tmp; tmp.setNum(d); output += tmp; + return *this; + } + void flush() { + if (output.isEmpty() || !print) + return; + printf("%s",output.latin1()); + output = QString::null; + } + private: + QString output; + unsigned int area, level; + bool print; +}; + +inline kdbgstream &endl( kdbgstream &s) { s << "\n"; return s; } + +inline kdbgstream kdDebug(int area = 0) { return kdbgstream(area, 0); } + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kdialog.h b/noncore/apps/tinykate/libkate/microkde/kdialog.h new file mode 100644 index 0000000..56f6bb0 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdialog.h @@ -0,0 +1,16 @@ +#ifndef MINIKDE_KDIALOG_H +#define MINIKDE_KDIALOG_H + +#include <qdialog.h> + +class KDialog : public QDialog +{ + public: + KDialog( QWidget *parent=0, const char *name=0, bool modal=true ) : + QDialog( parent, name, modal ) {} + + static int spacingHint() { return 3; } + static int marginHint() { return 3; } +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kdialogbase.cpp b/noncore/apps/tinykate/libkate/microkde/kdialogbase.cpp new file mode 100644 index 0000000..8caefe0 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdialogbase.cpp @@ -0,0 +1,214 @@ +#include <qtabwidget.h> +#include <qpushbutton.h> +#include <qlayout.h> +#include <qframe.h> + +#include "klocale.h" +#include "kdebug.h" + +#include "kdialogbase.h" + +KDialogBase::KDialogBase() +{ +} + +KDialogBase::KDialogBase( QWidget *parent, const char *name, bool modal, + const QString &caption, + int buttonMask, ButtonCode defaultButton, + bool separator, + const QString &user1, + const QString &user2, + const QString &user3) : + KDialog( parent, name, modal ) +{ + init( caption, buttonMask, user1 ); +} + +KDialogBase::KDialogBase( int dialogFace, const QString &caption, + int buttonMask, ButtonCode defaultButton, + QWidget *parent, const char *name, bool modal, + bool separator, + const QString &user1, + const QString &user2, + const QString &user3) : + KDialog( parent, name, modal ) +{ + init( caption, buttonMask, user1 ); +} + +KDialogBase::~KDialogBase() +{ +} + +void KDialogBase::init( const QString &caption, int buttonMask, + const QString &user1 ) +{ + mMainWidget = 0; + mTabWidget = 0; + mPlainPage = 0; + mTopLayout = 0; + + if ( !caption.isEmpty() ) { + setCaption( caption ); + } + + if ( buttonMask & User1 ) { + mUser1Button = new QPushButton( user1, this ); + connect( mUser1Button, SIGNAL( clicked() ), SLOT( slotUser1() ) ); + } else { + mUser1Button = 0; + } + + if ( buttonMask & Ok ) { + mOkButton = new QPushButton( i18n("Ok"), this ); + connect( mOkButton, SIGNAL( clicked() ), SLOT( slotOk() ) ); + } else { + mOkButton = 0; + } + + if ( buttonMask & Apply ) { + mApplyButton = new QPushButton( i18n("Apply"), this ); + connect( mApplyButton, SIGNAL( clicked() ), SLOT( slotApply() ) ); + } else { + mApplyButton = 0; + } + + if ( buttonMask & Cancel ) { + mCancelButton = new QPushButton( i18n("Cancel"), this ); + connect( mCancelButton, SIGNAL( clicked() ), SLOT( slotCancel() ) ); + } else { + mCancelButton = 0; + } + + if ( buttonMask & Close ) { + mCloseButton = new QPushButton( i18n("Close"), this ); + connect( mCloseButton, SIGNAL( clicked() ), SLOT( slotClose() ) ); + } else { + mCloseButton = 0; + } +} + +QTabWidget *KDialogBase::tabWidget() +{ + if ( !mTabWidget ) { + mTabWidget = new QTabWidget( this ); + setMainWidget( mTabWidget ); + } + return mTabWidget; +} + +void KDialogBase::initLayout() +{ + delete mTopLayout; + mTopLayout = new QVBoxLayout( this ); + mTopLayout->setMargin( marginHint() ); + mTopLayout->setSpacing( spacingHint() ); + + mTopLayout->addWidget( mMainWidget ); + + QBoxLayout *buttonLayout = new QHBoxLayout; + mTopLayout->addLayout( buttonLayout ); + + if ( mUser1Button ) buttonLayout->addWidget( mUser1Button ); + if ( mOkButton ) buttonLayout->addWidget( mOkButton ); + if ( mApplyButton ) buttonLayout->addWidget( mApplyButton ); + if ( mCancelButton ) buttonLayout->addWidget( mCancelButton ); + if ( mCloseButton ) buttonLayout->addWidget( mCloseButton ); +} + +QFrame *KDialogBase::addPage( const QString &name ) +{ +// kdDebug() << "KDialogBase::addPage(): " << name << endl; + + QFrame *frame = new QFrame( tabWidget() ); + tabWidget()->addTab( frame, name ); + return frame; +} + +QFrame *KDialogBase::addPage( const QString &name, int, const QPixmap & ) +{ + return addPage( name ); +} + + +void KDialogBase::setMainWidget( QWidget *widget ) +{ + kdDebug() << "KDialogBase::setMainWidget()" << endl; + + mMainWidget = widget; + initLayout(); +} + + +void KDialogBase::enableButton( ButtonCode id, bool state ) +{ + QPushButton *button = 0; + switch ( id ) { + case Ok: + button = mOkButton; + break; + case Apply: + button = mApplyButton; + break; + default: + break; + } + if ( button ) { + button->setEnabled( state ); + } +} + +void KDialogBase::enableButtonOK( bool state ) +{ + enableButton( Ok, state ); +} + +void KDialogBase::enableButtonApply( bool state ) +{ + enableButton( Apply, state ); +} + + +int KDialogBase::pageIndex( QWidget *widget ) const +{ + return 0; +} + + +bool KDialogBase::showPage( int index ) +{ + return false; +} + +QFrame *KDialogBase::plainPage() +{ + if ( !mPlainPage ) { + mPlainPage = new QFrame( this ); + setMainWidget( mPlainPage ); + } + return mPlainPage; +} + +void KDialogBase::slotOk() +{ + accept(); +} + +void KDialogBase::slotApply() +{ +} + +void KDialogBase::slotCancel() +{ + reject(); +} + +void KDialogBase::slotClose() +{ + accept(); +} + +void KDialogBase::slotUser1() +{ + emit user1Clicked(); +} diff --git a/noncore/apps/tinykate/libkate/microkde/kdialogbase.h b/noncore/apps/tinykate/libkate/microkde/kdialogbase.h new file mode 100644 index 0000000..dfb85d2 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kdialogbase.h @@ -0,0 +1,105 @@ +#ifndef MINIKDE_KDIALOGBASE_H +#define MINIKDE_KDIALOGBASE_H + +#include <qframe.h> + +#include "kdialog.h" + +class QPushButton; +class QLayout; +class QTabWidget; +class QBoxLayout; + +class KDialogBase : public KDialog +{ + Q_OBJECT + public: + enum ButtonCode + { + Help = 0x00000001, + Default = 0x00000002, + Ok = 0x00000004, + Apply = 0x00000008, + Try = 0x00000010, + Cancel = 0x00000020, + Close = 0x00000040, + User1 = 0x00000080, + User2 = 0x00000100, + User3 = 0x00000200, + No = 0x00000080, + Yes = 0x00000100, + Details = 0x00000400, + Filler = 0x40000000, + Stretch = 0x80000000 + }; + + enum DialogType + { + TreeList, + Tabbed, + Plain, + Swallow, + IconList + }; + + KDialogBase(); + KDialogBase( QWidget *parent=0, const char *name=0, bool modal=true, + const QString &caption=QString::null, + int buttonMask=Ok|Apply|Cancel, ButtonCode defaultButton=Ok, + bool separator=false, + const QString &user1=QString::null, + const QString &user2=QString::null, + const QString &user3=QString::null); + KDialogBase( int dialogFace, const QString &caption, + int buttonMask, ButtonCode defaultButton, + QWidget *parent=0, const char *name=0, bool modal=true, + bool separator=false, + const QString &user1=QString::null, + const QString &user2=QString::null, + const QString &user3=QString::null); + virtual ~KDialogBase(); + + QFrame *addPage( const QString & ); + QFrame *addPage( const QString &, int, const QPixmap & ); + + void setMainWidget( QWidget *widget ); + + void enableButton( ButtonCode id, bool state ); + void enableButtonOK( bool state ); + void enableButtonApply( bool state ); + + int pageIndex( QWidget *widget ) const; + + bool showPage( int index ); + + QFrame *plainPage(); + + signals: + void user1Clicked(); + + protected slots: + virtual void slotOk(); + virtual void slotApply(); + virtual void slotCancel(); + virtual void slotClose(); + virtual void slotUser1(); + + private: + QTabWidget *tabWidget(); + void init( const QString &caption, int buttonMask, + const QString &user1=QString::null ); + void initLayout(); + + QWidget *mMainWidget; + QTabWidget *mTabWidget; + QFrame *mPlainPage; + QBoxLayout *mTopLayout; + + QPushButton *mUser1Button; + QPushButton *mCloseButton; + QPushButton *mOkButton; + QPushButton *mApplyButton; + QPushButton *mCancelButton; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kemailsettings.cpp b/noncore/apps/tinykate/libkate/microkde/kemailsettings.cpp new file mode 100644 index 0000000..9a9ad84 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kemailsettings.cpp @@ -0,0 +1,6 @@ +#include "kemailsettings.h" + +QString KEMailSettings::getSetting(KEMailSettings::Setting s) +{ + return QString::null; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kemailsettings.h b/noncore/apps/tinykate/libkate/microkde/kemailsettings.h new file mode 100644 index 0000000..cf43f17 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kemailsettings.h @@ -0,0 +1,32 @@ +#ifndef MINIKDE_KEMAILSETTINGS_H +#define MINIKDE_KEMAILSETTINGS_H + +#include <qstring.h> + +class KEMailSettings +{ + public: + enum Setting { + ClientProgram, + ClientTerminal, + RealName, + EmailAddress, + ReplyToAddress, + Organization, + OutServer, + OutServerLogin, + OutServerPass, + OutServerType, + OutServerCommand, + OutServerTLS, + InServer, + InServerLogin, + InServerPass, + InServerType, + InServerMBXType, + InServerTLS + }; + QString getSetting(KEMailSettings::Setting s); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kfiledialog.h b/noncore/apps/tinykate/libkate/microkde/kfiledialog.h new file mode 100644 index 0000000..61781f0 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kfiledialog.h @@ -0,0 +1,21 @@ +#ifndef MICROKDE_KFILEDIALOG_H +#define MICROKDE_KFILEDIALOG_H + +class KFileDialog +{ + public: + + static QString getSaveFileName( const QString &, + const QString &, QWidget * ) + { + return QString::null; + } + + static QString getOpenFileName( const QString &, + const QString &, QWidget * ) + { + return QString::null; + } +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kfontdialog.cpp b/noncore/apps/tinykate/libkate/microkde/kfontdialog.cpp new file mode 100644 index 0000000..d199936 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kfontdialog.cpp @@ -0,0 +1,6 @@ +#include "kfontdialog.h" + +int KFontDialog::getFont( const QFont & ) +{ + return 0; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kfontdialog.h b/noncore/apps/tinykate/libkate/microkde/kfontdialog.h new file mode 100644 index 0000000..a4bf23d --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kfontdialog.h @@ -0,0 +1,14 @@ +#ifndef MINIKDE_KFONTDIALOG_H +#define MINIKDE_KFONTDIALOG_H + +#include <qfont.h> + +class KFontDialog +{ + public: + enum { Accepted }; + + static int getFont( const QFont & ); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kglobal.cpp b/noncore/apps/tinykate/libkate/microkde/kglobal.cpp new file mode 100644 index 0000000..572768d --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kglobal.cpp @@ -0,0 +1,49 @@ +#include "kglobal.h" + +KLocale *KGlobal::mLocale = 0; +KConfig *KGlobal::mConfig = 0; +KIconLoader *KGlobal::mIconLoader = 0; +KStandardDirs *KGlobal::mDirs = 0; + +QString KGlobal::mAppName = "godot"; + +KLocale *KGlobal::locale() +{ + if ( !mLocale ) { + mLocale = new KLocale(); + } + + return mLocale; +} + +KConfig *KGlobal::config() +{ + if ( !mConfig ) { + mConfig = new KConfig( KStandardDirs::appDir() + mAppName + "rc" ); + } + + return mConfig; +} + +KIconLoader *KGlobal::iconLoader() +{ + if ( !mIconLoader ) { + mIconLoader = new KIconLoader(); + } + + return mIconLoader; +} + +KStandardDirs *KGlobal::dirs() +{ + if ( !mDirs ) { + mDirs = new KStandardDirs(); + } + + return mDirs; +} + +void KGlobal::setAppName( const QString &appName ) +{ + mAppName = appName; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kglobal.h b/noncore/apps/tinykate/libkate/microkde/kglobal.h new file mode 100644 index 0000000..8985bd4 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kglobal.h @@ -0,0 +1,27 @@ +#ifndef MINIKDE_KGLOBAL_H +#define MINIKDE_KGLOBAL_H + +#include "klocale.h" +#include "kiconloader.h" +#include "kstandarddirs.h" +#include "kconfig.h" + +class KGlobal { + public: + static KLocale *locale(); + static KConfig *config(); + static KIconLoader *iconLoader(); + static KStandardDirs *dirs(); + + static void setAppName( const QString & ); + + private: + static KLocale *mLocale; + static KConfig *mConfig; + static KIconLoader *mIconLoader; + static KStandardDirs *mDirs; + + static QString mAppName; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kglobalsettings.cpp b/noncore/apps/tinykate/libkate/microkde/kglobalsettings.cpp new file mode 100644 index 0000000..cb5fe4c --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kglobalsettings.cpp @@ -0,0 +1,17 @@ +#include "kglobalsettings.h" + +QFont KGlobalSettings::generalFont() +{ + return QFont("fixed",12); +} + +QColor KGlobalSettings::baseColor() +{ + return Qt::white; +} + +QColor KGlobalSettings::highlightColor() +{ + return Qt::blue; +} + diff --git a/noncore/apps/tinykate/libkate/microkde/kglobalsettings.h b/noncore/apps/tinykate/libkate/microkde/kglobalsettings.h new file mode 100644 index 0000000..34cdb49 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kglobalsettings.h @@ -0,0 +1,15 @@ +#ifndef MICROKDE_KGLOBALSETTINGS_H +#define MICROKDE_KGLOBALSETTINGS_H + +#include <qfont.h> +#include <qcolor.h> + +class KGlobalSettings +{ + public: + static QFont generalFont(); + static QColor baseColor(); + static QColor highlightColor(); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kiconloader.cpp b/noncore/apps/tinykate/libkate/microkde/kiconloader.cpp new file mode 100644 index 0000000..83a2cad --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kiconloader.cpp @@ -0,0 +1,33 @@ +#include <qpe/resource.h> + +#include "kiconloader.h" + +QPixmap KIconLoader::loadIcon( const QString &name, int ) +{ + return Resource::loadPixmap( "kate/" + name ); +} + +QString KIconLoader::iconPath( const QString &, int ) +{ + return QString::null; +} + +QPixmap BarIcon( const QString &name ) +{ + return Resource::loadPixmap( "kate/" + name ); +} + +QPixmap DesktopIcon( const QString &name, int ) +{ + return Resource::loadPixmap( "kate/" + name ); +} + +QPixmap SmallIcon( const QString &name ) +{ + return Resource::loadPixmap( "kate/" + name ); +} + +QPixmap SmallIconSet( const QString &name ) +{ + return Resource::loadPixmap( "kate/" + name ); +} diff --git a/noncore/apps/tinykate/libkate/microkde/kiconloader.h b/noncore/apps/tinykate/libkate/microkde/kiconloader.h new file mode 100644 index 0000000..c4f642e --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kiconloader.h @@ -0,0 +1,31 @@ +#ifndef MINIKDE_KICONLOADER_H +#define MINIKDE_KICONLOADER_H + +#include <qpixmap.h> +#include <qstring.h> + +class KIcon +{ + public: + enum Group { NoGroup=-1, Desktop=0, Toolbar, MainToolbar, Small, + Panel, LastGroup, User }; + enum StdSizes { SizeSmall=16, SizeMedium=32, SizeLarge=48 }; +}; + +class KIconLoader +{ + public: + QPixmap loadIcon( const QString &name, int ); + + QString iconPath( const QString &, int ); +}; + +QPixmap BarIcon(const QString& name); + +QPixmap DesktopIcon(const QString& name, int); + +QPixmap SmallIcon(const QString& name); + +QPixmap SmallIconSet( const QString &name ); + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/klineedit.h b/noncore/apps/tinykate/libkate/microkde/klineedit.h new file mode 100644 index 0000000..26956ad --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/klineedit.h @@ -0,0 +1,13 @@ +#ifndef MINIKDE_KLINEEDIT_H +#define MINIKDE_KLINEEDIT_H + +#include <qlineedit.h> + +class KLineEdit : public QLineEdit +{ + public: + KLineEdit( QWidget *parent=0, const char *name=0 ) : + QLineEdit( parent, name ) {} +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/klineeditdlg.h b/noncore/apps/tinykate/libkate/microkde/klineeditdlg.h new file mode 100644 index 0000000..4136054 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/klineeditdlg.h @@ -0,0 +1,8 @@ +#ifndef _mykdelineeditdlg_h_ +#define _mykdelineeditdlg_h_ + +#include <qinputdialog.h> + +#define KLineEditDlg QInputDialog + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/klistview.h b/noncore/apps/tinykate/libkate/microkde/klistview.h new file mode 100644 index 0000000..008acbc --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/klistview.h @@ -0,0 +1,24 @@ +#ifndef MICROKDE_KLISTVIEW_H +#define MICROKDE_KLISTVIEW_H + +#include <qlistview.h> +#include <qpoint.h> +#include <qstring.h> + +class KConfig; + +class KListView : public QListView +{ + Q_OBJECT + public: + KListView( QWidget *parent=0, const char *name=0 ) + : QListView( parent, name ) {} + + void saveLayout( KConfig *, const QString & ) {} + void restoreLayout( KConfig *, const QString & ) {} + + signals: + void doubleClicked( QListViewItem *, QPoint, int ); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/klocale.cpp b/noncore/apps/tinykate/libkate/microkde/klocale.cpp new file mode 100644 index 0000000..dfdb97a --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/klocale.cpp @@ -0,0 +1,530 @@ +#include <qregexp.h> + +#include "kdebug.h" + +#include "klocale.h" + +QString i18n(const char *text) +{ + return QString( text ); +} + +QString i18n(const char *,const char *text) +{ + return QString( text ); +} + +inline void put_it_in( QChar *buffer, uint& index, const QString &s ) +{ + for ( uint l = 0; l < s.length(); l++ ) + buffer[index++] = s.at( l ); +} + +inline void put_it_in( QChar *buffer, uint& index, int number ) +{ + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; +} + +static int readInt(const QString &str, uint &pos) +{ + if (!str.at(pos).isDigit()) return -1; + int result = 0; + for (; str.length() > pos && str.at(pos).isDigit(); pos++) + { + result *= 10; + result += str.at(pos).digitValue(); + } + + return result; +} + +QString KLocale::formatTime(const QTime &pTime, bool includeSecs) const +{ + const QString rst = timeFormat(); + + // only "pm/am" here can grow, the rest shrinks, but + // I'm rather safe than sorry + QChar *buffer = new QChar[rst.length() * 3 / 2 + 30]; + + uint index = 0; + bool escape = false; + int number = 0; + + for ( uint format_index = 0; format_index < rst.length(); format_index++ ) + { + if ( !escape ) + { + if ( rst.at( format_index ).unicode() == '%' ) + escape = true; + else + buffer[index++] = rst.at( format_index ); + } + else + { + switch ( rst.at( format_index ).unicode() ) + { + case '%': + buffer[index++] = '%'; + break; + case 'H': + put_it_in( buffer, index, pTime.hour() ); + break; + case 'I': + put_it_in( buffer, index, ( pTime.hour() + 11) % 12 + 1 ); + break; + case 'M': + put_it_in( buffer, index, pTime.minute() ); + break; + case 'S': + if (includeSecs) + put_it_in( buffer, index, pTime.second() ); + else + { + // we remove the seperator sign before the seconds and + // assume that works everywhere + --index; + break; + } + break; + case 'k': + number = pTime.hour(); + case 'l': + // to share the code + if ( rst.at( format_index ).unicode() == 'l' ) + number = (pTime.hour() + 11) % 12 + 1; + if ( number / 10 ) + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; + break; + case 'p': + { + QString s; + if ( pTime.hour() >= 12 ) + put_it_in( buffer, index, i18n("pm") ); + else + put_it_in( buffer, index, i18n("am") ); + break; + } + default: + buffer[index++] = rst.at( format_index ); + break; + } + escape = false; + } + } + QString ret( buffer, index ); + delete [] buffer; + return ret; +} + +QString KLocale::formatDate(const QDate &pDate, bool shortFormat) const +{ + const QString rst = shortFormat?dateFormatShort():dateFormat(); + + // I'm rather safe than sorry + QChar *buffer = new QChar[rst.length() * 3 / 2 + 50]; + + unsigned int index = 0; + bool escape = false; + int number = 0; + + for ( uint format_index = 0; format_index < rst.length(); ++format_index ) + { + if ( !escape ) + { + if ( rst.at( format_index ).unicode() == '%' ) + escape = true; + else + buffer[index++] = rst.at( format_index ); + } + else + { + switch ( rst.at( format_index ).unicode() ) + { + case '%': + buffer[index++] = '%'; + break; + case 'Y': + put_it_in( buffer, index, pDate.year() / 100 ); + case 'y': + put_it_in( buffer, index, pDate.year() % 100 ); + break; + case 'n': + number = pDate.month(); + case 'e': + // to share the code + if ( rst.at( format_index ).unicode() == 'e' ) + number = pDate.day(); + if ( number / 10 ) + buffer[index++] = number / 10 + '0'; + buffer[index++] = number % 10 + '0'; + break; + case 'm': + put_it_in( buffer, index, pDate.month() ); + break; + case 'b': + put_it_in( buffer, index, monthName(pDate.month(), true) ); + break; + case 'B': + put_it_in( buffer, index, monthName(pDate.month(), false) ); + break; + case 'd': + put_it_in( buffer, index, pDate.day() ); + break; + case 'a': + put_it_in( buffer, index, weekDayName(pDate.dayOfWeek(), true) ); + break; + case 'A': + put_it_in( buffer, index, weekDayName(pDate.dayOfWeek(), false) ); + break; + default: + buffer[index++] = rst.at( format_index ); + break; + } + escape = false; + } + } + QString ret( buffer, index ); + delete [] buffer; + return ret; +} + +QString KLocale::formatDateTime(const QDateTime &pDateTime, + bool shortFormat, + bool includeSeconds) const +{ + return i18n("concatenation of dates and time", "%1 %2") + .arg( formatDate( pDateTime.date(), shortFormat ) ) + .arg( formatTime( pDateTime.time(), includeSeconds ) ); +} + +QString KLocale::formatDateTime(const QDateTime &pDateTime) const +{ + return formatDateTime(pDateTime, true); +} + +QDate KLocale::readDate(const QString &intstr, bool* ok) const +{ + QDate date; + date = readDate(intstr, true, ok); + if (date.isValid()) return date; + return readDate(intstr, false, ok); +} + +QDate KLocale::readDate(const QString &intstr, bool shortFormat, bool* ok) const +{ + QString fmt = (shortFormat ? dateFormatShort() : dateFormat()).simplifyWhiteSpace(); + return readDate( intstr, fmt, ok ); +} + +QDate KLocale::readDate(const QString &intstr, const QString &fmt, bool* ok) const +{ + //kdDebug(173) << "KLocale::readDate intstr=" << intstr << " fmt=" << fmt << endl; + QString str = intstr.simplifyWhiteSpace().lower(); + int day = -1, month = -1; + // allow the year to be omitted if not in the format + int year = QDate::currentDate().year(); + uint strpos = 0; + uint fmtpos = 0; + + while (fmt.length() > fmtpos || str.length() > strpos) + { + if ( !(fmt.length() > fmtpos && str.length() > strpos) ) + goto error; + + QChar c = fmt.at(fmtpos++); + + if (c != '%') { + if (c.isSpace()) + strpos++; + else if (c != str.at(strpos++)) + goto error; + continue; + } + + // remove space at the begining + if (str.length() > strpos && str.at(strpos).isSpace()) + strpos++; + + c = fmt.at(fmtpos++); + switch (c) + { + case 'a': + case 'A': + // this will just be ignored + { // Cristian Tache: porting to Win: Block added because of "j" redefinition + for (int j = 1; j < 8; j++) { + QString s = weekDayName(j, c == 'a').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) + strpos += len; + } + break; + } + case 'b': + case 'B': + { // Cristian Tache: porting to Win: Block added because of "j" redefinition + for (int j = 1; j < 13; j++) { + QString s = monthName(j, c == 'b').lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) { + month = j; + strpos += len; + } + } + break; + } + case 'd': + case 'e': + day = readInt(str, strpos); + if (day < 1 || day > 31) + goto error; + + break; + + case 'n': + case 'm': + month = readInt(str, strpos); + if (month < 1 || month > 12) + goto error; + + break; + + case 'Y': + case 'y': + year = readInt(str, strpos); + if (year < 0) + goto error; + // Qt treats a year in the range 0-100 as 1900-1999. + // It is nicer for the user if we treat 0-68 as 2000-2068 + if (year < 69) + year += 2000; + else if (c == 'y') + year += 1900; + + break; + } + } + //kdDebug(173) << "KLocale::readDate day=" << day << " month=" << month << " year=" << year << endl; + if ( year != -1 && month != -1 && day != -1 ) + { + if (ok) *ok = true; + return QDate(year, month, day); + } + error: + if (ok) *ok = false; + return QDate(); // invalid date +} + +QTime KLocale::readTime(const QString &intstr, bool *ok) const +{ + QTime _time; + _time = readTime(intstr, true, ok); + if (_time.isValid()) return _time; + return readTime(intstr, false, ok); +} + +QTime KLocale::readTime(const QString &intstr, bool seconds, bool *ok) const +{ + QString str = intstr.simplifyWhiteSpace().lower(); + QString Format = timeFormat().simplifyWhiteSpace(); + if (!seconds) + Format.replace(QRegExp(QString::fromLatin1(".%S")), QString::null); + + int hour = -1, minute = -1, second = seconds ? -1 : 0; // don't require seconds + bool g_12h = false; + bool pm = false; + uint strpos = 0; + uint Formatpos = 0; + + while (Format.length() > Formatpos || str.length() > strpos) + { + if ( !(Format.length() > Formatpos && str.length() > strpos) ) goto error; + + QChar c = Format.at(Formatpos++); + + if (c != '%') + { + if (c.isSpace()) + strpos++; + else if (c != str.at(strpos++)) + goto error; + continue; + } + + // remove space at the begining + if (str.length() > strpos && str.at(strpos).isSpace()) + strpos++; + + c = Format.at(Formatpos++); + switch (c) + { + case 'p': + { + QString s; + s = i18n("pm").lower(); + int len = s.length(); + if (str.mid(strpos, len) == s) + { + pm = true; + strpos += len; + } + else + { + s = i18n("am").lower(); + len = s.length(); + if (str.mid(strpos, len) == s) { + pm = false; + strpos += len; + } + else + goto error; + } + } + break; + + case 'k': + case 'H': + g_12h = false; + hour = readInt(str, strpos); + if (hour < 0 || hour > 23) + goto error; + + break; + + case 'l': + case 'I': + g_12h = true; + hour = readInt(str, strpos); + if (hour < 1 || hour > 12) + goto error; + + break; + + case 'M': + minute = readInt(str, strpos); + if (minute < 0 || minute > 59) + goto error; + + break; + + case 'S': + second = readInt(str, strpos); + if (second < 0 || second > 59) + goto error; + + break; + } + } + if (g_12h) + { + hour %= 12; + if (pm) hour += 12; + } + + if (ok) *ok = true; + return QTime(hour, minute, second); + + error: + if (ok) *ok = false; + return QTime(-1, -1, -1); // return invalid date if it didn't work + // This will be removed in the near future, since it gives a warning on stderr. + // The presence of the bool* (since KDE-3.0) removes the need for an invalid QTime. +} + +bool KLocale::use12Clock() const +{ + return false; +} + +bool KLocale::weekStartsMonday() const +{ + return true; +} + +QString KLocale::weekDayName(int i,bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return i18n("Monday", "Mon"); + case 2: return i18n("Tuesday", "Tue"); + case 3: return i18n("Wednesday", "Wed"); + case 4: return i18n("Thursday", "Thu"); + case 5: return i18n("Friday", "Fri"); + case 6: return i18n("Saturday", "Sat"); + case 7: return i18n("Sunday", "Sun"); + } + else + switch ( i ) + { + case 1: return i18n("Monday"); + case 2: return i18n("Tuesday"); + case 3: return i18n("Wednesday"); + case 4: return i18n("Thursday"); + case 5: return i18n("Friday"); + case 6: return i18n("Saturday"); + case 7: return i18n("Sunday"); + } + + return QString::null; +} + +QString KLocale::monthName(int i,bool shortName) const +{ + if ( shortName ) + switch ( i ) + { + case 1: return i18n("January", "Jan"); + case 2: return i18n("February", "Feb"); + case 3: return i18n("March", "Mar"); + case 4: return i18n("April", "Apr"); + case 5: return i18n("May short", "May"); + case 6: return i18n("June", "Jun"); + case 7: return i18n("July", "Jul"); + case 8: return i18n("August", "Aug"); + case 9: return i18n("September", "Sep"); + case 10: return i18n("October", "Oct"); + case 11: return i18n("November", "Nov"); + case 12: return i18n("December", "Dec"); + } + else + switch (i) + { + case 1: return i18n("January"); + case 2: return i18n("February"); + case 3: return i18n("March"); + case 4: return i18n("April"); + case 5: return i18n("May long", "May"); + case 6: return i18n("June"); + case 7: return i18n("July"); + case 8: return i18n("August"); + case 9: return i18n("September"); + case 10: return i18n("October"); + case 11: return i18n("November"); + case 12: return i18n("December"); + } + + return QString::null; +} + +QString KLocale::country() const +{ + return QString::null; +} + +QString KLocale::dateFormat() const +{ + return "%A %d %B %Y"; +} + +QString KLocale::dateFormatShort() const +{ + return "%d.%m.%Y"; +} + +QString KLocale::timeFormat() const +{ + return "%H:%M:%S"; +} diff --git a/noncore/apps/tinykate/libkate/microkde/klocale.h b/noncore/apps/tinykate/libkate/microkde/klocale.h new file mode 100644 index 0000000..cff200b --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/klocale.h @@ -0,0 +1,53 @@ +#ifndef MINIKDE_KLOCALE_H +#define MINIKDE_KLOCALE_H + +#include <qstring.h> +#include <qdatetime.h> + + +#define I18N_NOOP(x) x + + +QString i18n(const char *text); +QString i18n(const char *hint, const char *text); + +// Qt3's uic generates i18n( "msg", "comment" ) calls which conflict +// with our i18n method. we use uic -tr tr2i18n to redirect +// to the right i18n() function +inline QString tr2i18n(const char* message, const char* =0) { + return i18n( message); +} + +class KLocale +{ + public: + + QString formatDate(const QDate &pDate, bool shortFormat = false) const; + QString formatTime(const QTime &pTime, bool includeSecs = false) const; + QString formatDateTime(const QDateTime &pDateTime) const; + QString formatDateTime(const QDateTime &pDateTime, + bool shortFormat, + bool includeSecs = false) const; + + QDate readDate(const QString &str, bool* ok = 0) const; + QDate readDate( const QString &intstr, const QString &fmt, bool* ok = 0) const; + QTime readTime(const QString &str, bool* ok = 0) const; + + bool use12Clock() const; + bool weekStartsMonday() const; + + QString weekDayName(int,bool=false) const; + QString monthName(int,bool=false) const; + + QString country() const; + + QString dateFormat() const; + QString dateFormatShort() const; + QString timeFormat() const; + + private: + QTime readTime(const QString &str, bool seconds, bool *ok) const; + QDate readDate(const QString &str, bool shortFormat, bool *ok) const; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kmessagebox.cpp b/noncore/apps/tinykate/libkate/microkde/kmessagebox.cpp new file mode 100644 index 0000000..fd305cd --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kmessagebox.cpp @@ -0,0 +1,90 @@ +#include "kmessagebox.h" +#include "klocale.h" + +#include <qmessagebox.h> + +void KMessageBox::sorry( QWidget *parent, + const QString &text, + const QString &caption, bool ) +{ + QString cap = caption; + + if (cap.isEmpty()) { + cap = i18n("Sorry"); + } + + QMessageBox::warning( parent, cap, text ); +} + +int KMessageBox::warningYesNoCancel(QWidget *parent, const QString &text) +{ + int result = QMessageBox::warning(parent,i18n("Warning"),text,QMessageBox::Yes, + QMessageBox::No, QMessageBox::Cancel); + switch (result) { + case QMessageBox::Yes: return Yes; + case QMessageBox::No: return No; + case QMessageBox::Cancel: return Cancel; + } +} + +int KMessageBox::questionYesNo(QWidget *parent, + const QString &text, + const QString &textYes, + const QString &textNo, + bool notify=true ) +{ + int result =QMessageBox::warning(parent,i18n("Question"),text,textYes,textNo); + if ( result == 0 ) return KMessageBox::Yes; + return KMessageBox::No; +} + + + + +int KMessageBox::warningContinueCancel( QWidget *parent, + const QString &text, + const QString &caption, + const QString &buttonContinue, + const QString &dontAskAgainName, + bool notify ) +{ + QString cap = caption; + + if (cap.isEmpty()) { + cap = i18n("Warning"); + } + + int result = QMessageBox::warning( parent, cap, text, i18n("Ok"), + i18n("Cancel") ); + + if ( result == 0 ) return KMessageBox::Continue; + return KMessageBox::Cancel; +} + +void KMessageBox::error( QWidget *parent, + const QString &text, + const QString &caption, bool notify ) +{ + QString cap = caption; + + if (cap.isEmpty()) { + cap = i18n("Error"); + } + + QMessageBox::critical( parent, cap, text ); +} + +void KMessageBox::information( QWidget *parent, + const QString &text, + const QString &caption, + const QString &, + bool ) +{ + QString cap = caption; + + if (cap.isEmpty()) { + cap = i18n("Information"); + } + + QMessageBox::information( parent, cap, text ); +} diff --git a/noncore/apps/tinykate/libkate/microkde/kmessagebox.h b/noncore/apps/tinykate/libkate/microkde/kmessagebox.h new file mode 100644 index 0000000..d7c971f --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kmessagebox.h @@ -0,0 +1,46 @@ +#ifndef MINIKDE_KMESSAGEBOX_H +#define MINIKDE_KMESSAGEBOX_H + +#include <qstring.h> + +class QWidget; + +class KMessageBox +{ + public: + enum { Ok = 1, Cancel = 2, Yes = 3, No = 4, Continue = 5 }; + + static void sorry(QWidget *parent, + const QString &text, + const QString &caption = QString::null, bool notify=true); + + static int warningContinueCancel(QWidget *parent, + const QString &text, + const QString &caption = QString::null, + const QString &buttonContinue = QString::null, + const QString &dontAskAgainName = QString::null, + bool notify=true ); + + + static int questionYesNo(QWidget *parent, + const QString &text, + const QString &textYes, + const QString &textNo, + bool notify=true ); + + static int warningYesNoCancel(QWidget *parent, const QString &text); + + + static void error(QWidget *parent, + const QString &text, + const QString &caption = QString::null, bool notify=true); + + static void information(QWidget *parent, + const QString &text, + const QString &caption = QString::null, + const QString &dontShowAgainName = QString::null, + bool notify=true); +}; + + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/knotifyclient.h b/noncore/apps/tinykate/libkate/microkde/knotifyclient.h new file mode 100644 index 0000000..118026a --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/knotifyclient.h @@ -0,0 +1,14 @@ +#ifndef MINIKDE_KNOTIFYCLIENT_H +#define MINIKDE_KNOTIFYCLIENT_H + +#include <qstring.h> + +class KNotifyClient +{ + public: + + static void beep() {} + static void beep( const QString & ) {} +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/knumvalidator.cpp b/noncore/apps/tinykate/libkate/microkde/knumvalidator.cpp new file mode 100644 index 0000000..67e632f --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/knumvalidator.cpp @@ -0,0 +1,8 @@ +#include <qlineedit.h> + +#include "knumvalidator.h" + +KIntValidator::KIntValidator( int a, int b, QLineEdit *c ) + : QIntValidator( a, b, c ) +{ +} diff --git a/noncore/apps/tinykate/libkate/microkde/knumvalidator.h b/noncore/apps/tinykate/libkate/microkde/knumvalidator.h new file mode 100644 index 0000000..92eda01 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/knumvalidator.h @@ -0,0 +1,14 @@ +#ifndef MINIKDE_KNUMVALIDATOR_H +#define MINIKDE_KNUMVALIDATOR_H + +#include <qvalidator.h> + +class QLineEdit; + +class KIntValidator : public QIntValidator +{ + public: + KIntValidator( int, int, QLineEdit * ); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kpopupmenu.h b/noncore/apps/tinykate/libkate/microkde/kpopupmenu.h new file mode 100644 index 0000000..fb35943 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kpopupmenu.h @@ -0,0 +1,8 @@ +#ifndef _MYKPOPUPMENU_H_ +#define _MYKPOPUPMENU_H_ + +#include <qpopupmenu.h> + +#define KPopupMenu QPopupMenu + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kprinter.h b/noncore/apps/tinykate/libkate/microkde/kprinter.h new file mode 100644 index 0000000..b99d689 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kprinter.h @@ -0,0 +1,8 @@ +#ifndef MINIKDE_KPRINTER_H +#define MINIKDE_KPRINTER_H + +#include <qprinter.h> + +#define KPrinter QPrinter + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kprocess.cpp b/noncore/apps/tinykate/libkate/microkde/kprocess.cpp new file mode 100644 index 0000000..62033e9 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kprocess.cpp @@ -0,0 +1,15 @@ +#include "kprocess.h" + +void KProcess::clearArguments() +{ +} + +KProcess & KProcess::operator<<( const QString & ) +{ + return *this; +} + +bool KProcess::start() +{ + return false; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kprocess.h b/noncore/apps/tinykate/libkate/microkde/kprocess.h new file mode 100644 index 0000000..96dce54 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kprocess.h @@ -0,0 +1,16 @@ +#ifndef MINIKDE_KPROCESS_H +#define MINIKDE_KPROCESS_H + +#include <qobject.h> + +class KProcess : public QObject +{ + public: + void clearArguments(); + + KProcess & operator<<( const QString & ); + + bool start(); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/krestrictedline.h b/noncore/apps/tinykate/libkate/microkde/krestrictedline.h new file mode 100644 index 0000000..200546c --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/krestrictedline.h @@ -0,0 +1,13 @@ +#ifndef MINIKDE_KRESTRICTEDLINE_H +#define MINIKDE_KRESTRICTEDLINE_H + +#include "klineedit.h" + +class KRestrictedLine : public KLineEdit +{ + public: + KRestrictedLine( QWidget *parent, const char *, const QString & ) : + KLineEdit( parent ) {} +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/krun.cpp b/noncore/apps/tinykate/libkate/microkde/krun.cpp new file mode 100644 index 0000000..a170add --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/krun.cpp @@ -0,0 +1,6 @@ +#include "krun.h" + +bool KRun::runCommand(const QString &, const QString &, const QString &) +{ + return false; +} diff --git a/noncore/apps/tinykate/libkate/microkde/krun.h b/noncore/apps/tinykate/libkate/microkde/krun.h new file mode 100644 index 0000000..1b63cb7 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/krun.h @@ -0,0 +1,13 @@ +#ifndef MINIKDE_KRUN_H +#define MINIKDE_KRUN_H + +#include <qstring.h> + +class KRun +{ + public: + static bool runCommand(const QString &a, const QString &b=QString::null, + const QString &c=QString::null); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kseparator.h b/noncore/apps/tinykate/libkate/microkde/kseparator.h new file mode 100644 index 0000000..9fc0b51 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kseparator.h @@ -0,0 +1,8 @@ +#ifndef MINIKDE_KSEPARATOR_H +#define MINIKDE_KSEPARATOR_H + +class KSeparator +{ +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/ksharedptr.h b/noncore/apps/tinykate/libkate/microkde/ksharedptr.h new file mode 100644 index 0000000..55ed2e9 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/ksharedptr.h @@ -0,0 +1,142 @@ +/* This file is part of the KDE libraries + Copyright (c) 1999 Waldo Bastian <bastian@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 KSharedPTR_H +#define KSharedPTR_H + +/** + * Reference counting for shared objects. If you derive your object + * from this class, then you may use it in conjunction with + * @ref KSharedPtr to control the lifetime of your object. + * + * Specifically, all classes that derive from KShared have an internal + * counter keeping track of how many other objects have a reference to + * their object. If used with @ref KSharedPtr, then your object will + * not be deleted until all references to the object have been + * released. + * + * You should probably not ever use any of the methods in this class + * directly -- let the @ref KSharedPtr take care of that. Just derive + * your class from KShared and forget about it. + * + * @author Waldo Bastian <bastian@kde.org> + * @version $Id$ + */ +class KShared { +public: + /** + * Standard constructor. This will initialize the reference count + * on this object to 0 + */ + KShared() : count(0) { } + + /** + * Copy constructor. This will @em not actually copy the objects + * but it will initialize the reference count on this object to 0 + */ + KShared( const KShared & ) : count(0) { } + + /** + * Overloaded assignment operator + */ + KShared &operator=(const KShared & ) { return *this; } + + /** + * Increases the reference count by one + */ + void _KShared_ref() { count++; } + + /** + * Releases a reference (decreases the reference count by one). If + * the count goes to 0, this object will delete itself + */ + void _KShared_unref() { if (!--count) delete this; } + + /** + * Return the current number of references held + * + * @return Number of references + */ + int _KShared_count() { return count; } + +protected: + virtual ~KShared() { } + int count; // ### KDE 3.0: rename to something like _KShared_count + // or make private +}; + +/** + * Can be used to control the lifetime of an object that has derived + * @ref KShared. As long a someone holds a KSharedPtr on some KShared + * object it won't become deleted but is deleted once its reference + * count is 0. This struct emulates C++ pointers perfectly. So just + * use it like a simple C++ pointer. + * + * KShared and KSharedPtr are preferred over QShared / QSharedPtr + * since they are more safe. + * + * @author Waldo Bastian <bastian@kde.org> + * @version $Id$ + */ +template< class T > +struct KSharedPtr +{ +public: + KSharedPtr() + : ptr(0) { } + KSharedPtr( T* t ) + : ptr(t) { if ( ptr ) ptr->_KShared_ref(); } + KSharedPtr( const KSharedPtr& p ) + : ptr(p.ptr) { if ( ptr ) ptr->_KShared_ref(); } + + ~KSharedPtr() { if ( ptr ) ptr->_KShared_unref(); } + + KSharedPtr<T>& operator= ( const KSharedPtr<T>& p ) { + if ( ptr == p.ptr ) return *this; + if ( ptr ) ptr->_KShared_unref(); + ptr = p.ptr; + if ( ptr ) ptr->_KShared_ref(); + return *this; + } + KSharedPtr<T>& operator= ( T* p ) { + if ( ptr == p ) return *this; + if ( ptr ) ptr->_KShared_unref(); + ptr = p; + if ( ptr ) ptr->_KShared_ref(); + return *this; + } + bool operator== ( const KSharedPtr<T>& p ) const { return ( ptr == p.ptr ); } + bool operator!= ( const KSharedPtr<T>& p ) const { return ( ptr != p.ptr ); } + bool operator== ( const T* p ) const { return ( ptr == p ); } + bool operator!= ( const T* p ) const { return ( ptr != p ); } + bool operator!() const { return ( ptr == 0 ); } + operator T*() const { return ptr; } + + T* data() { return ptr; } + const T* data() const { return ptr; } + + const T& operator*() const { return *ptr; } + T& operator*() { return *ptr; } + const T* operator->() const { return ptr; } + T* operator->() { return ptr; } + + int count() const { return ptr->_KShared_count(); } // for debugging purposes +private: + T* ptr; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/ksimpleconfig.h b/noncore/apps/tinykate/libkate/microkde/ksimpleconfig.h new file mode 100644 index 0000000..1efd982 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/ksimpleconfig.h @@ -0,0 +1,12 @@ +#ifndef MINIKDE_KSIMPLECONFIG_H +#define MINIKDE_KSIMPLECONFIG_H + +#include "kconfig.h" + +class KSimpleConfig : public KConfig +{ + public: + KSimpleConfig( const QString &file ) : KConfig( file ) {} +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kstandarddirs.cpp b/noncore/apps/tinykate/libkate/microkde/kstandarddirs.cpp new file mode 100644 index 0000000..befa667 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kstandarddirs.cpp @@ -0,0 +1,39 @@ +#include "kdebug.h" + +#include "kstandarddirs.h" + +QString KStandardDirs::mAppDir = QString::null; + +QString locate( const char *type, const QString& filename ) +{ + QString path = KStandardDirs::appDir() + type + "_" + filename; + + kdDebug() << "locate: '" << path << "'" << endl; + + return path; +} + +QString locateLocal( const char *type, const QString& filename ) +{ + return locate( type, filename ); +} + +QStringList KStandardDirs::findAllResources( const QString &, const QString &, bool, bool) +{ + QStringList list; + list.append("/cpp.xml"); + return list; +// return QStringList(); +} + +QString KStandardDirs::findResourceDir( const QString &, const QString & ) +{ + return QString::null; +} + +void KStandardDirs::setAppDir( const QString &appDir ) +{ + mAppDir = appDir; + + if ( mAppDir.right( 1 ) != "/" ) mAppDir += "/"; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kstandarddirs.h b/noncore/apps/tinykate/libkate/microkde/kstandarddirs.h new file mode 100644 index 0000000..fa5e460 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kstandarddirs.h @@ -0,0 +1,23 @@ +#ifndef MINIKDE_KSTANDARDDIRS_H +#define MINIKDE_KSTANDARDDIRS_H + +#include <qstring.h> +#include <qstringlist.h> + +QString locate( const char *type, const QString& filename ); +QString locateLocal( const char *type, const QString& filename ); + +class KStandardDirs +{ + public: + QStringList findAllResources( const QString &, const QString &, bool, bool); + QString findResourceDir( const QString &, const QString & ); + + static void setAppDir( const QString & ); + static QString appDir() { return mAppDir; } + + private: + static QString mAppDir; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kstaticdeleter.h b/noncore/apps/tinykate/libkate/microkde/kstaticdeleter.h new file mode 100644 index 0000000..190f3e4 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kstaticdeleter.h @@ -0,0 +1,35 @@ +/* + * This file is part of the KDE Libraries + * Copyright (C) 2000 Stephan Kulow <coolo@kde.org> + * 2001 KDE Team + * + * 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 _KSTATIC_DELETER_H_ +#define _KSTATIC_DELETER_H_ + +template<class type> +class KStaticDeleter +{ + public: + KStaticDeleter() {}; + type *setObject( type *obj, bool isArray = false) { return obj; } + virtual ~KStaticDeleter() {}; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kstddirs.h b/noncore/apps/tinykate/libkate/microkde/kstddirs.h new file mode 100644 index 0000000..fa5e460 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kstddirs.h @@ -0,0 +1,23 @@ +#ifndef MINIKDE_KSTANDARDDIRS_H +#define MINIKDE_KSTANDARDDIRS_H + +#include <qstring.h> +#include <qstringlist.h> + +QString locate( const char *type, const QString& filename ); +QString locateLocal( const char *type, const QString& filename ); + +class KStandardDirs +{ + public: + QStringList findAllResources( const QString &, const QString &, bool, bool); + QString findResourceDir( const QString &, const QString & ); + + static void setAppDir( const QString & ); + static QString appDir() { return mAppDir; } + + private: + static QString mAppDir; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/ktempfile.cpp b/noncore/apps/tinykate/libkate/microkde/ktempfile.cpp new file mode 100644 index 0000000..b9166bd --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/ktempfile.cpp @@ -0,0 +1,25 @@ +#include <qtextstream.h> + +#include "ktempfile.h" + +KTempFile::KTempFile() +{ +} + +KTempFile::KTempFile( const QString &filename, const QString &extension ) +{ +} + +void KTempFile::setAutoDelete( bool ) +{ +} + +QString KTempFile::name() +{ + return QString::null; +} + +QTextStream *KTempFile::textStream() +{ + return 0; +} diff --git a/noncore/apps/tinykate/libkate/microkde/ktempfile.h b/noncore/apps/tinykate/libkate/microkde/ktempfile.h new file mode 100644 index 0000000..20dfa82 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/ktempfile.h @@ -0,0 +1,20 @@ +#ifndef MINIKDE_KTEMPFILE_H +#define MINIKDE_KTEMPFILE_H + +#include <qstring.h> + +class QTextStream; + +class KTempFile +{ + public: + KTempFile(); + KTempFile( const QString &filename, const QString &extension ); + + void setAutoDelete( bool ); + QString name(); + + QTextStream *textStream(); +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kunload.h b/noncore/apps/tinykate/libkate/microkde/kunload.h new file mode 100644 index 0000000..1c3d00f --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kunload.h @@ -0,0 +1,6 @@ +#ifndef MINIKDE_KUNLOAD_H +#define MINIKDE_KUNLOAD_H + +#define _UNLOAD(p) + +#endif diff --git a/noncore/apps/tinykate/libkate/microkde/kurlrequester.cpp b/noncore/apps/tinykate/libkate/microkde/kurlrequester.cpp new file mode 100644 index 0000000..29d173b --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kurlrequester.cpp @@ -0,0 +1,14 @@ +#include "klineedit.h" + +#include "kurlrequester.h" + +KURLRequester::KURLRequester( QWidget *parent ) : + QWidget( parent ) +{ + mLineEdit = new KLineEdit( parent ); +} + +KLineEdit *KURLRequester::lineEdit() +{ + return mLineEdit; +} diff --git a/noncore/apps/tinykate/libkate/microkde/kurlrequester.h b/noncore/apps/tinykate/libkate/microkde/kurlrequester.h new file mode 100644 index 0000000..8b39196 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/microkde/kurlrequester.h @@ -0,0 +1,17 @@ +#ifndef MINIKDE_KURLREQUESTER_H +#define MINIKDE_KURLREQUESTER_H + +class KLineEdit; + +class KURLRequester : public QWidget +{ + public: + KURLRequester( QWidget *parent ); + + KLineEdit *lineEdit(); + + private: + KLineEdit *mLineEdit; +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/qt3back/README b/noncore/apps/tinykate/libkate/qt3back/README new file mode 100644 index 0000000..e329aee --- a/dev/null +++ b/noncore/apps/tinykate/libkate/qt3back/README @@ -0,0 +1,12 @@ +This is a backport I got from Scott Manson, I just added an additional #ifndef QT_NO_COMPAT in the .cpp file around a match +function + +************************* + This is ___NOT___ the original version from Trolltech, so don't blame them if something is wrong. +************************* + +Use it at your own risk, neither Trolltech, Scott Manson nor I take any responsibility, if it damages your system or causes +unexpected behaviour or causes loss of data + +Joseph Wenninger +<jowenn@kde.org> diff --git a/noncore/apps/tinykate/libkate/qt3back/qregexp3.cpp b/noncore/apps/tinykate/libkate/qt3back/qregexp3.cpp new file mode 100644 index 0000000..a2c680f --- a/dev/null +++ b/noncore/apps/tinykate/libkate/qt3back/qregexp3.cpp @@ -0,0 +1,3767 @@ +/**************************************************************************** +** $Id$ +** +** Implementation of QRegExp class +** +** Created : 950126 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ +#if QT_VERSION >=300 +#error QRegExp3 is now in QT 3 use QRegExp instead +#endif + +#include "qarray.h" +#include "qbitarray.h" +#include "qcache.h" +#include "qintdict.h" +#include "qmap.h" +#if QT_VERSION < 300 +#include "./qregexp3.h" +#else +#include "qregexp.h" +#endif +#include "qstring.h" +#include "qtl.h" +#include "qvector.h" + +#include <limits.h> + +/* + WARNING! Be sure to read qregexp.tex before modifying this file. +*/ + +/*! + \class QRegExp3 qregexp.h + + \brief The QRegExp class provides pattern matching using regular expressions. + + \ingroup tools + \ingroup misc + \ingroup shared + + + Regular expressions, "regexps", provide a way to find patterns + within text. This is useful in many contexts, for example: + + <ol> + <li>\e Validation. A regexp can be used to check whether a piece of + text meets some criteria, e.g. is an integer or contains no + whitespace. + <li>\e Searching. Regexps provide a much more powerful means of + searching text than simple string matching does. For example we can + create a regexp which says "find one of the words 'mail', 'letter' + or 'correspondence' but not any of the words 'email', 'mailman' + 'mailer', 'letterbox' etc." + <li><em>Search and Replace.</em> A regexp can be used to replace a + pattern with a piece of text, for example replace all occurrences of + '&' with '\&' except where the '&' is already followed by + 'amp;'. + <li><em>String Splitting.</em> A regexp can be used to identify + where a string should be split into its component fields, e.g. + splitting tab delimited strings. + </ol> + + We present a very brief introduction to regexps, a description of + Qt's regexp language, some code examples, and finally the function + documentation. QRegExp is modelled on Perl's regexp engine and fully + supports Unicode. QRegExp may also be used in the weaker 'wildcard' + (globbing) mode which works in a similar way to command shells. A + good text on regexps is <i>Mastering Regular Expressions: Powerful + Techniques for Perl and Other Tools</i> by Jeffrey E. Friedl, ISBN + 1565922573. + + Experienced regexp users may prefer to skip the introduction and + go directly to the relevant information: + + <ul> + <li><a href="#characters-and-abbreviations-for-sets-of-characters"> + Characters and Abbreviations for Sets of Characters</a> + <li><a href="#sets-of-characters">Sets of Characters</a> + <li><a href="#quantifiers">Quantifiers</a> + <li><a href="#capturing-text">Capturing Text</a> + <li><a href="#assertions">Assertions</a> + <li><a href="#wildcard-matching">Wildcard Matching (globbing)</a> + <li><a href="#perl-users">Notes for Perl Users</a> + <li><a href="#code-examples">Code Examples</a> + <li><a href="#member-function-documentation">Member Function Documentation</a> + </ul> + + <b>Introduction</b> + + Regexps are built up from expressions, quantifiers and assertions. + The simplest form of expression is simply a character, e.g. <b>x</b> + or <b>5</b>. An expression can also be a set of characters. For + example, <b>[ABCD]</b>, will match an <b>A</b> or a <b>B</b> or a + <b>C</b> or a <b>D</b>. As a shorthand we could write this as + <b>[A-D]</b>. If we want to match any of the captital letters in the + English alphabet we can write <b>[A-Z]</b>. A quantifier tells the + regexp engine how many occurrences of the expression we want, e.g. + <b>x{1,1}</b> means match an <b>x</b> which occurs at least once and + at most once. We'll look at assertions and more complex expressions + later. Note that regexps cannot be used to check for balanced + brackets or tags (unless you know the maximum level of nesting). + + + We'll start by writing a regexp to match integers in the range 0 to + 99. We will require at least one digit so we will start with + <b>[0-9]{1,1}</b> which means match a digit exactly once. This + regexp alone will match integers in the range 0 to 9. To match one + or two digits we can increase the maximum number of occurrences so + the regexp becomes <b>[0-9]{1,2}</b> meaning match a digit at least + once and at most twice. However, this regexp as it stands will not + match correctly. This regexp will match one or two digits \e within + a string. To ensure that we match against the whole string we must + use the anchor assertions. We need <b>^</b> (caret) which when it is + the first character in the regexp means that the regexp must match + from the beginning of the string. And we also need <b>$</b> (dollar) + which when it is the last character in the regexp means that the + regexp must match until the end of the string. So now our regexp is + <b>^[0-9]{1,2}$</b>. Note that assertions do not match any + characters. + + If you've seen regexps elsewhere they may have looked different from + the one above. This is because some sets of characters and some + quantifiers are so common that they have special symbols to + represent them. <b>[0-9]</b> can be replaced with the symbol + <b>\d</b>. The quantifier to match exactly one occurrence, + <b>{1,1}</b>, can be replaced with the expression itself. This means + that <b>x{1,1}</b> is exactly the same as <b>x</b> alone. So our 0 + to 99 matcher could be written: <b>^\d{1,2}$</b>, although most + people would write it <b>^\d\d?$</b>. The <b>?</b> is the same as + the quantifier <b>{0,1}</b>, i.e. a minimum of no occurrences a + maximum of one occurrence. This is used to make an expression + optional. The regexp <b>^\d\d?$</b> means "from the beginning of the + string match one digit followed by zero or one digits and then the + end of the string". + + Our second example is matching the words 'mail', 'letter' or + 'correspondence' but without matching 'email', 'mailman', 'mailer', + 'letterbox' etc. We'll start by just matching 'mail'. In full the + regexp is, <b>m{1,1}a{1,1}i{1,1}l{1,1}</b>, but since an expression + itself is automatically quantified by <b>{1,1}</b> we can simply + write this as <b>mail</b>; an 'm' followed by an 'a' followed by an + 'i' followed by an 'l'. The symbol '|' (bar) is used for \e + alternation, so our regexp now becomes + <b>mail|letter|correspondence</b> which means match 'mail' \e or + 'letter' \e or 'correspondence'. Whilst this regexp will find the + words we want it will also find words we don't want such as 'email'. + We will start by putting our regexp in parenthesis + <b>(mail|letter|correspondence)</b>. Parenthesis have two effects, + firstly they group expressions together and secondly they identify + parts of the regexp that we wish to <a href="#capturing-text">capture</a>. + Our regexp still matches any of the three words but now they are + grouped together as a unit. This is useful for building up more + complex regexps. It is also useful because it allows us to examine + which of the words actually matched. We need to use another + assertion, this time <b>\b</b> "word boundary": + <b>\b(mail|letter|correspondence)\b</b>. This regexp means "match a + word boundary followed by the expression in parenthesis followed by + another word boundary". The <b>\b</b> assertion matches at a \e + position in the regexp not a \e character in the regexp. A word + boundary is any non-word character such as a space a newline or the + beginning or end of the string. + + For our third example we want to replace ampersands with the HTML + entity '\&'. The regexp to match is simple: <b>\&</b>, i.e. + match one ampersand. Unfortunately this will mess up our text if + some of the ampersands have already been turned into HTML entities. + So what we really want to say is replace an ampersand providing it + is not followed by 'amp;'. For this we need the negative lookahead + assertion and our regexp becomes: <b>\&(?!amp;)</b>. The negative + lookahead assertion is introduced with '(?!' and finishes at the + ')'. It means that the text it contains, 'amp;' in our example, must + \e not follow the expression that preceeds it. + + Regexps provide a rich language that can be used in a variety of + ways. For example suppose we want to count all the occurrences of + 'Eric' and 'Eirik' in a string. Two valid regexps to match these are + <b>\\</b><b>b(Eric|Eirik)</b><b>\\</b><b>b</b> and + <b>\\</b><b>bEi?ri[ck]</b><b>\\</b><b>b</b>. We need the word boundary + '\b' so we don't get 'Ericsson' etc. The second regexp actually + matches more than we want, 'Eric', 'Erik', 'Eiric' and 'Eirik'. + + We will implement some the examples above in the + <a href="#code-examples">code examples</a> section. + + <a name="characters-and-abbreviations-for-sets-of-characters"> + <b>Characters and Abbreviations for Sets of Characters</b></a> + + <ul> + + <li><b>c</b> Any character represents itself unless it has a special regexp + meaning. Thus <b>c</b> matches the character \e c. + + <li><b>\\</b><b>c</b> A character that follows a backslash matches the + character itself except where mentioned below. For example if you + wished to match a literal caret at the beginning of a string you + would write <b>\^</b>. + + <li><b>\\</b><b>a</b> This matches the ASCII bell character (BEL, 0x07). + <li><b>\\</b><b>f</b> This matches the ASCII form feed character (FF, 0x0C). + <li><b>\\</b><b>n</b> This matches the ASCII line feed character (LF, 0x0A), (Unix newline). + <li><b>\\</b><b>r</b> This matches the ASCII carriage return character (CR, 0x0D). + <li><b>\\</b><b>t</b> This matches the ASCII horizontal tab character (HT, 0x09). + <li><b>\\</b><b>v</b> This matches the ASCII vertical tab character (VT, 0x0B). + <li><b>\\</b><b>xhhhh</b> This matches the Unicode character corresponding + to the hexadecimal number hhhh (between 0x0000 and 0xFFFF). \0ooo + (i.e., \zero ooo) matches the ASCII/Latin-1 character corresponding + to the octal number ooo (between 0 and 0377). + <li><b>. (dot)</b> This matches any character (including newline). + <li><b>\\</b><b>d</b> This matches a digit (see QChar::isDigit()). + <li><b>\\</b><b>D</b> This matches a non-digit. + <li><b>\\</b><b>s</b> This matches a whitespace (see QChar::isSpace()). + <li><b>\\</b><b>S</b> This matches a non-whitespace. + <li><b>\\</b><b>w</b> This matches a word character (see QChar::isLetterOrNumber()). + <li><b>\\</b><b>W</b> This matches a non-word character. + <li><b>\\</b><b>n</b> The n<sup>th</sup> + <a href="#capturing-text">backreference</a>, e.g. \1, \2, etc. + </ul> + + <em>Note that the C++ compiler transforms backslashes in strings so + to include a <b>\\</b> in a regexp you will need to enter it twice, + i.e. <b>\\</b><b>\\</b>.</em> + + <a name="sets-of-characters"><b>Sets of Characters</b></a> + + Square brackets are used to match any character in the set of + characters contained within the square brackets. All the character + set abbreviations described above can be used within square + brackets. Apart from the character set abbreviations and the + following two exceptions no characters have special meanings in + square brackets. + + <ul> + + <li><b>^</b> The caret negates the character set if it occurs as the + first character, i.e. immediately after the opening square bracket. + For example, <b>[abc]</b> matches 'a' or 'b' or 'c', but + <b>[^abc]</b> matches anything \e except 'a' or 'b' or 'c'. + + <li><b>-</b> The dash is used to indicate a range of characters, for + example <b>[W-Z]</b> matches 'W' or 'X' or 'Y' or 'Z'. + + </ul> + + Using the predefined character set abbreviations is more portable + than using character ranges across platforms and languages. For + example, <b>[0-9]</b> matches a digit in Western alphabets but + <b>\d</b> matches a digit in \e any alphabet. + + Note that in most regexp literature sets of characters are called + "character classes". + + <a name="quantifiers"><b>Quantifiers</b></a> + + By default an expression is automatically quantified by + <b>{1,1}</b>, i.e. it should occur exactly once. In the following + list <b><i>E</i></b> stands for any expression. An expression is a + character or an abbreviation for a set of characters or a set of + characters in square brackets or any parenthesised expression. + + <ul> + + <li><b><i>E</i>?</b> Matches zero or one occurrence of <i>E</i>. + This quantifier means "the previous expression is optional" since it + will match whether or not the expression occurs in the string. + It is the same as <b><i>E</i>{0,1}</b>. For example <b>dents?</b> + will match 'dent' and 'dents'. + + <li><b><i>E</i>+</b> Matches one or more occurrences of <i>E</i>. + This is the same as <b><i>E</i>{1,MAXINT}</b>. For example, + <b>0+</b> will match '0', '00', '000', etc. + + <li><b><i>E</i>*</b> Matches zero or more occurrences of <i>E</i>. + This is the same as <b><i>E</i>{0,MAXINT}</b>. The <b>*</b> + quantifier is often used by a mistake. Since it matches \e zero or + more occurrences it will match no occurrences at all. For example if + we want to match strings that end in whitespace and use the regexp + <b>\s*$</b> we would get a match on every string. This is because we + have said find zero or more whitespace followed by the end of string, + so even strings that don't end in whitespace will match. The regexp + we want in this case is <b>\s+$</b> to match strings that have at + least one whitespace at the end. + + <li><b><i>E</i>{n}</b> Matches exactly \e n occurrences of the + expression. This is the same as repeating the expression \e n times. + For example, <b>x{5}</b> is the same as <b>xxxxx</b>. It is also the + same as <b><i>E</i>{n,n}</b>, e.g. <b>x{5,5}</b>. + + <li><b><i>E</i>{n,}</b> Matches at least \e n occurrences of the + expression. This is the same as <b><i>E</i>{n,MAXINT}</b>. + + <li><b><i>E</i>{,m}</b> Matches at most \e m occurrences of the + expression. This is the same as <b><i>E</i>{0,m}</b>. + + <li><b><i>E</i>{n,m}</b> Matches at least \e n occurrences of the + expression and at most \e m occurrences of the expression. + + </ul> + + (MAXINT is implementation dependent but will not be smaller than + 16384.) + + If we wish to apply a quantifier to more than just the preceeding + character we can use parenthesis to group characters together in an + expression. For example, <b>tag+</b> matches a 't' followed by an + 'a' followed by at least one 'g', whereas <b>(tag)+</b> matches at + least one occurrence of 'tag'. + + Note that quantifiers are "greedy", they will match as much text as + they can. For example, <b>0+</b> will match as many zeros as it can + from the first zero it finds, e.g. '2.<u>000</u>5'. Quantifiers can + be made non-greedy, see setMinimal(). + + <a name="capturing-text"><b>Capturing Text</b></a> + + Parenthesis allow us to group elements together so that we can + quantify and capture them. For example if we have the expression + <b>mail|letter|correspondence</b> that matches a string we know that + \e one of the words matched but not which one. Using parenthesis + allows us to "capture" whatever is matched within their bounds, so + if we used <b>(mail|letter|correspondence)</b> and matched this + regexp against the string "I sent you some email" we can use the + cap() or capturedTexts() functions to extract the matched + characters, in this case 'mail'. + + We can use captured text within the regexp itself. To refer to the + captured text we use \e backreferences which are indexed from 1 the + same as for cap(). For example we could search for duplicate words + in a string using <b>\b(\w+)\W+\1\b</b> which means match a word + boundary followed by one or more word characters followed by one or + more non-word characters followed by the same text as the first + parenthesised expression followed by a word boundary. + + If we want to use parenthesis purely for grouping and not for + capturing we use the non-capturing syntax, e.g. + <b>(?:green|blue)</b>. Non-capturing parenthesis begin '(?:' and end + ')'. In this example we match either 'green' or 'blue' but we do not + capture the match so we can only know whether or not we matched but + not which color we actually found. Using non-capturing parenthesis + is more efficient than using capturing parenthesis since the regexp + engine has to do less book-keeping. + + Both capturing and non-capturing parenthesis may be nested. + + <a name="assertions"><b>Assertions</b></a> + + Assertions make some statement about the text at the point where + they occur in the regexp but they do not match any characters. + In the following list <b><i>E</i></b> stands for any expression. + + <ul> + <li><b>^</b> If the caret is the first character in the regexp + (apart from opening parenthesis) it signifies the beginning of the + string. It has no special meaning elsewhere (except as the first + character of a set of characters in square brackets). For example, + <b>^#include</b> will only match strings which \e begin with the + characters '#include'. + + <li><b>$</b> If the dollar is the last character in the regexp + (apart from closing parenthesis) it signifies the end of the string. + It has no special meaning elsewhere. For example, <b>\d\s*$</b> + will match strings which end with a digit optionally followed by + whitespace. + + <li><b>\\</b><b>b</b> A word boundary. For example the regexp + <b>\\</b><b>bOK</b>\\</b><b>b</b> means match immediately after a + word boundary (e.g. start of string or whitespace) the letter 'O' + then the letter 'K' immediately before another word boundary (e.g. + end of string or whitespace). But note that the assertion does not + actually match any whitespace so if we write + <b>(</b><b>\\</b><b>bOK</b>\\</b><b>b)</b> and we have a match it + will only contain 'OK' even if the string is "Its <u>OK</u> now". + + <li><b>\\</b><b>B</b> A non-word boundary. This assertion is true + wherever <b>\\</b><b>b</b> is false. For example if we searched for + <b>\\</b><b>Bon</b>\\</b><b>B</b> in "Left on" the match would fail + (space and end of string aren't non-word boundaries), but it would + match in "t<u>on</u>ne". + + <li><b>(?=<i>E</i>)</b> Positive lookahead. This assertion is true + if the expression matches at this point in the regex. This assertion + does not match any characters. For example, + <b>^#define\s+(\w+)(?=MAX)</b> will match strings which begin with + '#define' followed by at least one whitespace followed by at least + one word character followed by 'MAX'. The first set of parenthesis + will capture the word character(s) matched. This regexp will not + match '#define DEBUG' but will match '#define <u>INT</u>MAX + 32767'. + + <li><b>(?!<i>E</i>)</b> Negative lookahead. This assertion is true + if the expression does not match at this point in the regex. This + assertion does not match any characters. For example, + <b>^#define\s+(\w+)\s*$</b> will match strings which begin with + '#define' followed by at least one whitespace followed by at least + one word character optionally followed by whitespace. This regexp + will match define's that exist but have no value, i.e. it will not + match '#define INTMAX 32767' but it will match '#define <u>DEBUG</u>'. + + </ul> + + <a name="wildcard-matching"><b>Wildcard Matching (globbing)</b></a> + + Most command shells such as \e bash or \e cmd support "file + globbing", the ability to identify a group of files by using + wildcards. Wildcard matching is much simpler than full regexps and + has only four features: + + <ul> + + <li><b>c</b> Any character represents itself apart from those + mentioned below. Thus <b>c</b> matches the character \e c. + + <li><b>?</b> This matches any single character. It is the same as + <b>.</b> in full regexps. + + <li><b>*</b> This matches zero or more of any characters. It is the + same as <b>.*</b> in full regexps. + + <li><b>[...]</b> Sets of characters can be represented in square + brackets the same as for full regexps. + + <!-- JASMIN: Are the character classes, \w, etc supported in + wildcards? --> + + </ul> + + For example if we are in wildcard mode and have strings which + contain filenames we could identify HTML files with <b>*.html</b>. + This will match zero or more characters followed by a dot followed + by 'h', 't', 'm' and 'l'. + + <a name="perl-users"><b>Notes for Perl Users</b></a> + + Most of the character class abbreviations supported by Perl are + supported by QRegExp, see + <a href="#characters-and-abbreviations-for-sets-of-characters"> + characters and abbreviations for sets of characters</a>. + + QRegExp's quantifiers are the same as Perl's greedy quantifiers. + Non-greedy matching cannot be applied to individual quantifiers, but + can be applied to all the quantifiers in the pattern. For example, + to match the Perl regex <b>ro+?m</b> requires: + \code + QRegExp rx( "ro+m" ); + rx.setMinimal( TRUE ); + \endcode + + The equivalent of Perl's <tt>/i</tt> option is + setCaseSensitive(FALSE). + + Perl's <tt>/g</tt> option can be emulated using a + <a href="#cap_in_a_loop">loop</a>. + + In QRegExp <b>.</b> matches any character, therefore all QRegExp + regexps have the equivalent of Perl's <tt>/s</tt> option. QRegExp + does not have an equivalent to Perl's <tt>/m</tt> option, but this + can be emulated in various ways for example by splitting the input + into lines or by looping with a regexp that searches for newlines. + + Because QRegExp is string oriented there are no \A, \Z or \z + assertions. The \G assertion is not supported but can be emulated in + a loop. + + Perl's $& is cap(0) or capturedTexts()[0]. There are no QRegExp + equivalents for $`, $' or $+. $1, $2 etc correspond to + cap(1) or capturedTexts()[1], cap(2) or capturedTexts()[2], etc. + + To substitute a pattern use QString::replace(). + + Perl's extended <tt>/x</tt> syntax is not supported, nor are regexp + comments (?#comment) or directives, e.g. (?i). + + Both zero-width positive and zero-width negative lookahead + assertions (?=pattern) and (?!pattern) are supported with the same + syntax as Perl. Perl's lookbehind assertions, "independent" + subexpressions and conditional expressions are not supported. + + Non-capturing parenthesis are also supported, with the same + (?:pattern) syntax. + + See QStringList::split() and QStringList::join() for equivalents to + Perl's split and join functions. + + Note: because C++ transforms \\'s they must be written \e twice in + code, e.g. <b>\\</b><b>b</b> must be written <b>\\</b><b>\\</b><b>b</b>. + + <a name="code-examples"><b>Code Examples</b></a> + + \code + QRegExp rx( "^\\d\\d?$" ); // Match integers 0 to 99 + rx.search( "123" ); // Returns -1 (no match) + rx.search( "-6" ); // Returns -1 (no match) + rx.search( "6" ); // Returns 0 (matched as position 0) + \endcode + + The third string matches '<u>6</u>'. This is a simple validation + regexp for integers in the range 0 to 99. + + \code + QRegExp rx( "^\\S+$" ); // Match strings which have no whitespace + rx.search( "Hello world" ); // Returns -1 (no match) + rx.search( "This_is-OK" ); // Returns 0 (matched at position 0) + \endcode + + The second string matches '<u>This_is-OK</u>'. We've used the + character set abbreviation '\S' (non-whitespace) and the anchors to + match strings which contain no whitespace. + + In the following example we match strings containing 'mail' or + 'letter' or 'correspondence' but only match whole words i.e. not + 'email' + + \code + QRegExp rx( "\\b(mail|letter|correspondence)\\b" ); + rx.search( "I sent you an email" ); // Returns -1 (no match) + rx.search( "Please write the letter" ); // Returns 17 (matched at position 17) + \endcode + + The second string matches "Please write the <u>letter</u>". The word + 'letter' is also captured (because of the parenthesis). We can see + what text we've captured like this: + + \code + QString captured = rx.cap( 1 ); // captured contains "letter" + \endcode + + This will capture the text from the first set of capturing + parenthesis (counting capturing left parenthesis from left to + right). The parenthesis are counted from 1 since cap( 0 ) is the + whole matched regexp (equivalent to '&' in most regexp engines). + + \code + QRegExp rx( "&(?!amp;)" ); // Match ampersands but not & + QString line1 = "This & that"; + line1.replace( rx, "&" ); + // line1 == "This & that" + QString line2 = "His & hers & theirs"; + line2.replace( rx, "&" ); + // line2 == "His & hers & theirs" + \endcode + + Here we've passed the QRegExp to QString's replace() function to + replace the matched text with new text. + + \code + QString str = "One Eric another Eirik, and an Ericsson. How many Eiriks, Eric?"; + QRegExp rx( "\\b(Eric|Eirik)\\b" ); // Match Eric or Eirik + int pos = 0; // Where we are in the string + int count = 0; // How many Eric and Eirik's we've counted + while ( pos >= 0 ) { + pos = rx.search( str, pos ); + if ( pos >= 0 ) { + pos++; // Move along in str + count++; // Count our Eric or Eirik + } + } + \endcode + + We've used the search() function to repeatedly match the regexp in + the string. Note that instead of moving forward by one character at + a time <tt>pos++</tt> we could have written <tt>pos += + rx.matchedLength()</tt> to skip over the already matched string. The + count will equal 3, matching 'One <u>Eric</u> another <u>Eirik</u>, + and an Ericsson. How many Eiriks, <u>Eric</u>?'; it doesn't match + 'Ericsson' or 'Eiriks' because they are not bounded by non-word + boundaries. + + One common use of regexps is to split lines of delimited data into + their component fields. + + \code + str = "Trolltech AS\twww.trolltech.com\tNorway"; + QString company, web, country; + rx.setPattern( "^([^\t]+)\t([^\t]+)\t([^\t]+)$" ); + if ( rx.search( str ) != -1 ) { + company = rx.cap( 1 ); + web = rx.cap( 2 ); + country = rx.cap( 3 ); + } + \endcode + + In this example our input lines have the format company name, web + address and country. Unfortunately the regexp is rather long and not + very versatile -- the code will break if we add any more fields. A + simpler and better solution is to look for the separator, '\t' in + this case, and take the surrounding text. The QStringList split() + function can take a separator string or regexp as an argument and + split a string accordingly. + + \code + QStringList field = QStringList::split( "\t", str ); + \endcode + + Here field[0] is the company, field[1] the web address and so on. + + To immitate the matching of a shell we can use wildcard mode. + + \code + QRegExp rx( "*.html" ); // Invalid regexp: * doesn't quantify anything + rx.setWildcard( TRUE ); // Now its a valid wildcard regexp + rx.search( "index.html" ); // Returns 0 (matched at position 0) + rx.search( "default.htm" ); // Returns -1 (no match) + rx.search( "readme.txt" ); // Returns -1 (no match) + \endcode + + Wildcard matching can be convenient because of its simplicity, but + any wildcard regex can be defined using full regexps, e.g. + <b>.*\.html$</b>. Notice that we can't match both \c .html and \c + .htm files with a wildcard unless we use <b>*.htm*</b> which will + also match 'test.html.bak'. A full regexp gives us the precision we + need, <b>.*\.html?$</b>. + + QRegExp can match case insensitively using setCaseSensitive(), and + can use non-greedy matching, see setMinimal(). By default QRegExp + uses full regexps but this can be changed with setWildcard(). + Searching can be forward with search() or backward with searchRev(). + Captured text can be accessed using capturedTexts() which returns a + string list of all captured strings, or using cap() which returns + the captured string for the given index. The pos() function takes a + match index and returns the position in the string where the match + was made (or -1 if there was no match). + + \sa QRegExpValidator QString QStringList + + <a name="member-function-documentation"/> +*/ + +static const int NumBadChars = 128; +#define BadChar( ch ) ( (ch).cell() % NumBadChars ) + +static const int NoOccurrence = INT_MAX; +static const int EmptyCapture = INT_MAX; +static const int InftyLen = INT_MAX; +static const int InftyRep = 1000; +static const int EOS = -1; + +#ifndef QT_NO_REGEXP_OPTIM +static int engCount = 0; +static QArray<int> *noOccurrences = 0; +static QArray<int> *firstOccurrenceAtZero = 0; +#endif + +/* + Merges two QArrays of ints and puts the result into the first one. +*/ +static void mergeInto( QArray<int> *a, const QArray<int>& b ) +{ + int asize = a->size(); + int bsize = b.size(); + if ( asize == 0 ) { + *a = b.copy(); +#ifndef QT_NO_REGEXP_OPTIM + } else if ( bsize == 1 && (*a)[asize - 1] < b[0] ) { + a->resize( asize + 1 ); + (*a)[asize] = b[0]; +#endif + } else if ( bsize >= 1 ) { + int csize = asize + bsize; + QArray<int> c( csize ); + int i = 0, j = 0, k = 0; + while ( i < asize ) { + if ( j < bsize ) { + if ( (*a)[i] == b[j] ) { + i++; + csize--; + } else if ( (*a)[i] < b[j] ) { + c[k++] = (*a)[i++]; + } else { + c[k++] = b[j++]; + } + } else { + memcpy( c.data() + k, (*a).data() + i, + (asize - i) * sizeof(int) ); + break; + } + } + c.resize( csize ); + if ( j < bsize ) + memcpy( c.data() + k, b.data() + j, (bsize - j) * sizeof(int) ); + *a = c; + } +} + +/* + Merges two disjoint QMaps of (int, int) pairs and puts the result into the + first one. +*/ +static void mergeInto( QMap<int, int> *a, const QMap<int, int>& b ) +{ + QMap<int, int>::ConstIterator it; + for ( it = b.begin(); it != b.end(); ++it ) + a->insert( it.key(), *it ); +} + +/* + Returns the value associated to key k in QMap m of (int, int) pairs, or 0 if + no such value is explicitly present. +*/ +static int at( const QMap<int, int>& m, int k ) +{ + QMap<int, int>::ConstIterator it = m.find( k ); + if ( it == m.end() ) + return 0; + else + return *it; +} + +#ifndef QT_NO_REGEXP_WILDCARD +/* + Translates a wildcard pattern to an equivalent regular expression pattern + (e.g., *.cpp to .*\.cpp). +*/ +static QString wc2rx( const QString& wc ) +{ + int wclen = wc.length(); + QString rx = QString::fromLatin1( "" ); + int i = 0; + while ( i < wclen ) { + QChar c = wc[i++]; + switch ( c.unicode() ) { + case '*': + rx += QString::fromLatin1( ".*" ); + break; + case '?': + rx += QChar( '.' ); + break; + case '$': + case '(': + case ')': + case '+': + case '.': + case '\\': + case '^': + case '{': + case '|': + case '}': + rx += QChar( '\\' ); + rx += c; + break; + case '[': + rx += c; + if ( wc[i] == QChar('^') ) + rx += wc[i++]; + if ( i < wclen ) { + if ( rx[i] == ']' ) + rx += wc[i++]; + while ( i < wclen && wc[i] != QChar(']') ) { + if ( wc[i] == '\\' ) + rx += QChar( '\\' ); + rx += wc[i++]; + } + } + break; + default: + rx += c; + } + } + return rx; +} +#endif + +/* + The class QRegExpEngine encapsulates a modified nondeterministic finite + automaton (NFA). +*/ +class QRegExpEngine : public QShared +{ +public: +#ifndef QT_NO_REGEXP_CCLASS + /* + The class CharClass represents a set of characters, such as can be found + in regular expressions (e.g., [a-z] denotes the set {a, b, ..., z}). + */ + class CharClass + { + public: + CharClass(); + CharClass( const CharClass& cc ) { operator=( cc ); } + + CharClass& operator=( const CharClass& cc ); + + void clear(); + bool negative() const { return n; } + void setNegative( bool negative ); + void addCategories( int cats ); + void addRange( ushort from, ushort to ); + void addSingleton( ushort ch ) { addRange( ch, ch ); } + + bool in( QChar ch ) const; +#ifndef QT_NO_REGEXP_OPTIM + const QArray<int>& firstOccurrence() const { return occ1; } +#endif + +#if defined(QT_DEBUG) + void dump() const; +#endif + + private: + /* + The struct Range represents a range of characters (e.g., [0-9] denotes + range 48 to 57). + */ + struct Range + { + ushort from; // 48 + ushort to; // 57 + }; + + int c; // character classes + QArray<Range> r; // character ranges + bool n; // negative? +#ifndef QT_NO_REGEXP_OPTIM + QArray<int> occ1; // first-occurrence array +#endif + }; +#else + struct CharClass + { + int x; // dummy + +#ifndef QT_NO_REGEXP_OPTIM + const QArray<int>& firstOccurrence() const { + return *firstOccurrenceAtZero; + } +#endif + }; +#endif + + QRegExpEngine( bool caseSensitive ) { setup( caseSensitive ); } + QRegExpEngine( const QString& rx, bool caseSensitive ); +#ifndef QT_NO_REGEXP_OPTIM + ~QRegExpEngine(); +#endif + + bool isValid() const { return valid; } + bool caseSensitive() const { return cs; } + int numCaptures() const { return realncap; } + QArray<int> match( const QString& str, int pos, bool minimal, + bool oneTest ); + int matchedLength() const { return mmMatchedLen; } + + int createState( QChar ch ); + int createState( const CharClass& cc ); +#ifndef QT_NO_REGEXP_BACKREF + int createState( int bref ); +#endif + + void addCatTransitions( const QArray<int>& from, const QArray<int>& to ); +#ifndef QT_NO_REGEXP_CAPTURE + void addPlusTransitions( const QArray<int>& from, const QArray<int>& to, + int atom ); +#endif + +#ifndef QT_NO_REGEXP_ANCHOR_ALT + int anchorAlternation( int a, int b ); + int anchorConcatenation( int a, int b ); +#else + int anchorAlternation( int a, int b ) { return a & b; } + int anchorConcatenation( int a, int b ) { return a | b; } +#endif + void addAnchors( int from, int to, int a ); + +#ifndef QT_NO_REGEXP_OPTIM + void setupGoodStringHeuristic( int earlyStart, int lateStart, + const QString& str ); + void setupBadCharHeuristic( int minLen, const QArray<int>& firstOcc ); + void heuristicallyChooseHeuristic(); +#endif + +#if defined(QT_DEBUG) + void dump() const; +#endif + +private: + enum { CharClassBit = 0x10000, BackRefBit = 0x20000 }; + + /* + The struct State represents one state in a modified NFA. The input + characters matched are stored in the state instead of on the transitions, + something possible for an automaton constructed from a regular expression. + */ + struct State + { +#ifndef QT_NO_REGEXP_CAPTURE + int atom; // which atom does this state belong to? +#endif + int match; // what does it match? (see CharClassBit and BackRefBit) + QArray<int> outs; // out-transitions + QMap<int, int> *reenter; // atoms reentered when transiting out + QMap<int, int> *anchors; // anchors met when transiting out + +#ifndef QT_NO_REGEXP_CAPTURE + State( int a, int m ) + : atom( a ), match( m ), reenter( 0 ), anchors( 0 ) { } +#else + State( int m ) + : match( m ), reenter( 0 ), anchors( 0 ) { } +#endif + ~State() { delete reenter; delete anchors; } + }; + +#ifndef QT_NO_REGEXP_LOOKAHEAD + /* + The struct Lookahead represents a lookahead a la Perl (e.g., (?=foo) and + (?!bar)). + */ + struct Lookahead + { + QRegExpEngine *eng; // NFA representing the embedded regular expression + bool neg; // negative lookahead? + + Lookahead( QRegExpEngine *eng0, bool neg0 ) + : eng( eng0 ), neg( neg0 ) { } + ~Lookahead() { delete eng; } + }; +#endif + +#ifndef QT_NO_REGEXP_CAPTURE + /* + The struct Atom represents one node in the hierarchy of regular expression + atoms. + */ + struct Atom + { + int parent; // index of parent in array of atoms + int capture; // index of capture, from 1 to ncap + }; +#endif + +#ifndef QT_NO_REGEXP_ANCHOR_ALT + /* + The struct AnchorAlternation represents a pair of anchors with OR + semantics. + */ + struct AnchorAlternation + { + int a; // this anchor... + int b; // ...or this one + }; +#endif + + enum { InitialState = 0, FinalState = 1 }; + void setup( bool caseSensitive ); + int setupState( int match ); + + /* + Let's hope that 13 lookaheads and 14 back-references are enough. + */ + enum { MaxLookaheads = 13, MaxBackRefs = 14 }; + enum { Anchor_Dollar = 0x00000001, Anchor_Caret = 0x00000002, + Anchor_Word = 0x00000004, Anchor_NonWord = 0x00000008, + Anchor_FirstLookahead = 0x00000010, + Anchor_BackRef1Empty = Anchor_FirstLookahead << MaxLookaheads, + Anchor_BackRef0Empty = Anchor_BackRef1Empty >> 1, + Anchor_Alternation = Anchor_BackRef1Empty << MaxBackRefs, + + Anchor_LookaheadMask = ( Anchor_FirstLookahead - 1 ) ^ + ( (Anchor_FirstLookahead << MaxLookaheads) - 1 ) }; +#ifndef QT_NO_REGEXP_CAPTURE + int startAtom( bool capture ); + void finishAtom( int atom ) { cf = f[atom].parent; } +#endif + +#ifndef QT_NO_REGEXP_LOOKAHEAD + int addLookahead( QRegExpEngine *eng, bool negative ); +#endif + +#ifndef QT_NO_REGEXP_CAPTURE + bool isBetterCapture( const int *begin1, const int *end1, const int *begin2, + const int *end2 ); +#endif + bool testAnchor( int i, int a, const int *capBegin ); + +#ifndef QT_NO_REGEXP_OPTIM + bool goodStringMatch(); + bool badCharMatch(); +#else + bool bruteMatch(); +#endif + bool matchHere(); + + QVector<State> s; // array of states + int ns; // number of states +#ifndef QT_NO_REGEXP_CAPTURE + QArray<Atom> f; // atom hierarchy + int nf; // number of atoms + int cf; // current atom +#endif + int realncap; // number of captures, seen from the outside + int ncap; // number of captures, seen from the inside +#ifndef QT_NO_REGEXP_CCLASS + QVector<CharClass> cl; // array of character classes +#endif +#ifndef QT_NO_REGEXP_LOOKAHEAD + QVector<Lookahead> ahead; // array of lookaheads +#endif +#ifndef QT_NO_REGEXP_ANCHOR_ALT + QArray<AnchorAlternation> aa; // array of (a, b) pairs of anchors +#endif +#ifndef QT_NO_REGEXP_OPTIM + bool caretAnchored; // does the regexp start with ^? +#endif + bool valid; // is the regular expression valid? + bool cs; // case sensitive? +#ifndef QT_NO_REGEXP_BACKREF + int nbrefs; // number of back-references +#endif + +#ifndef QT_NO_REGEXP_OPTIM + bool useGoodStringHeuristic; // use goodStringMatch? otherwise badCharMatch + + int goodEarlyStart; // the index where goodStr can first occur in a match + int goodLateStart; // the index where goodStr can last occur in a match + QString goodStr; // the string that any match has to contain + + int minl; // the minimum length of a match + QArray<int> occ1; // first-occurrence array +#endif + + /* + The class Box is an abstraction for a regular expression fragment. It can + also be seen as one node in the syntax tree of a regular expression with + synthetized attributes. + + It's interface is ugly for performance reasons. + */ + class Box + { + public: + Box( QRegExpEngine *engine ); + Box( const Box& b ) { operator=( b ); } + + Box& operator=( const Box& b ); + + void clear() { operator=(Box(eng)); } + void set( QChar ch ); + void set( const CharClass& cc ); +#ifndef QT_NO_REGEXP_BACKREF + void set( int bref ); +#endif + + void cat( const Box& b ); + void orx( const Box& b ); + void plus( int atom ); + void opt(); + void catAnchor( int a ); +#ifndef QT_NO_REGEXP_OPTIM + void setupHeuristics(); +#endif + +#if defined(QT_DEBUG) + void dump() const; +#endif + + private: + void addAnchorsToEngine( const Box& to ) const; + + QRegExpEngine *eng; // the automaton under construction + QArray<int> ls; // the left states (firstpos) + QArray<int> rs; // the right states (lastpos) + QMap<int, int> lanchors; // the left anchors + QMap<int, int> ranchors; // the right anchors + int skipanchors; // the anchors to match if the box is skipped + +#ifndef QT_NO_REGEXP_OPTIM + int earlyStart; // the index where str can first occur + int lateStart; // the index where str can last occur + QString str; // a string that has to occur in any match + QString leftStr; // a string occurring at the left of this box + QString rightStr; // a string occurring at the right of this box + int maxl; // the maximum length of this box (possibly InftyLen) +#endif + + int minl; // the minimum length of this box +#ifndef QT_NO_REGEXP_OPTIM + QArray<int> occ1; // first-occurrence array +#endif + }; + friend class Box; + + /* + This is the lexical analyzer for regular expressions. + */ + enum { Tok_Eos, Tok_Dollar, Tok_LeftParen, Tok_MagicLeftParen, + Tok_PosLookahead, Tok_NegLookahead, Tok_RightParen, Tok_CharClass, + Tok_Caret, Tok_Quantifier, Tok_Bar, Tok_Word, Tok_NonWord, + Tok_Char = 0x10000, Tok_BackRef = 0x20000 }; + int getChar(); + int getEscape(); +#ifndef QT_NO_REGEXP_INTERVAL + int getRep( int def ); +#endif +#ifndef QT_NO_REGEXP_LOOKAHEAD + void skipChars( int n ); +#endif + void startTokenizer( const QChar *rx, int len ); + int getToken(); + + const QChar *yyIn; // a pointer to the input regular expression pattern + int yyPos0; // the position of yyTok in the input pattern + int yyPos; // the position of the next character to read + int yyLen; // the length of yyIn + int yyCh; // the last character read + CharClass *yyCharClass; // attribute for Tok_CharClass tokens + int yyMinRep; // attribute for Tok_Quantifier + int yyMaxRep; // ditto + bool yyError; // syntax error or overflow during parsing? + + /* + This is the syntactic analyzer for regular expressions. + */ + int parse( const QChar *rx, int len ); + void parseAtom( Box *box ); + void parseFactor( Box *box ); + void parseTerm( Box *box ); + void parseExpression( Box *box ); + + int yyTok; // the last token read + bool yyMayCapture; // set this to FALSE to disable capturing + + /* + This is the engine state during matching. + */ + const QString *mmStr; // a pointer to the input QString + const QChar *mmIn; // a pointer to the input string data + int mmPos; // the current position in the string + int mmLen; // the length of the input string + bool mmMinimal; // minimal matching? + QArray<int> mmCaptured; // an array of pairs (start, len) + QArray<int> mmCapturedNoMatch; // an array of pairs (-1, -1) + QArray<int> mmBigArray; // big QArray<int> array + int *mmInNextStack; // is state is mmNextStack? + int *mmCurStack; // stack of current states + int *mmNextStack; // stack of next states + int *mmCurCapBegin; // start of current states' captures + int *mmNextCapBegin; // start of next states' captures + int *mmCurCapEnd; // end of current states' captures + int *mmNextCapEnd; // end of next states' captures + int *mmTempCapBegin; // start of temporary captures + int *mmTempCapEnd; // end of temporary captures + int *mmCapBegin; // start of captures for a next state + int *mmCapEnd; // end of captures for a next state + int *mmSlideTab; // bump-along slide table for bad-character heuristic + int mmSlideTabSize; // size of slide table +#ifndef QT_NO_REGEXP_BACKREF + QIntDict<int> mmSleeping; // dictionary of back-reference sleepers +#endif + int mmMatchedLen; // length of match or of matched string for partial match +}; + +QRegExpEngine::QRegExpEngine( const QString& rx, bool caseSensitive ) +#ifndef QT_NO_REGEXP_BACKREF + : mmSleeping( 101 ) +#endif +{ + setup( caseSensitive ); + valid = ( parse(rx.unicode(), rx.length()) == (int) rx.length() ); +} + +#ifndef QT_NO_REGEXP_OPTIM +QRegExpEngine::~QRegExpEngine() +{ + if ( --engCount == 0 ) { + delete noOccurrences; + noOccurrences = 0; + delete firstOccurrenceAtZero; + firstOccurrenceAtZero = 0; + } +} +#endif + +/* + Tries to match in str and returns an array of (begin, length) pairs for + captured text. If there is no match, all pairs are (-1, -1). +*/ +QArray<int> QRegExpEngine::match( const QString& str, int pos, bool minimal, + bool oneTest ) +{ + mmStr = &str; + mmIn = str.unicode(); + if ( mmIn == 0 ) + mmIn = &QChar::null; + mmPos = pos; + mmLen = str.length(); + mmMinimal = minimal; + mmMatchedLen = 0; + + bool matched = FALSE; + if ( valid && mmPos >= 0 && mmPos <= mmLen ) { +#ifndef QT_NO_REGEXP_OPTIM + if ( mmPos <= mmLen - minl ) { + if ( caretAnchored || oneTest ) + matched = matchHere(); + else if ( useGoodStringHeuristic ) + matched = goodStringMatch(); + else + matched = badCharMatch(); + } +#else + matched = oneTest ? matchHere() : bruteMatch(); +#endif + } + + if ( matched ) { + mmCaptured.detach(); + mmCaptured[0] = mmPos; + mmCaptured[1] = mmMatchedLen; + for ( int j = 0; j < realncap; j++ ) { + int len = mmCapEnd[j] - mmCapBegin[j]; + mmCaptured[2 + 2 * j] = len > 0 ? mmPos + mmCapBegin[j] : 0; + mmCaptured[2 + 2 * j + 1] = len; + } + return mmCaptured; + } else { + return mmCapturedNoMatch; + } +} + +/* + The three following functions add one state to the automaton and return the + number of the state. +*/ + +int QRegExpEngine::createState( QChar ch ) +{ + return setupState( ch.unicode() ); +} + +int QRegExpEngine::createState( const CharClass& cc ) +{ +#ifndef QT_NO_REGEXP_CCLASS + int n = cl.size(); + cl.resize( n + 1 ); + cl.insert( n, new CharClass(cc) ); + return setupState( CharClassBit | n ); +#else + Q_UNUSED( cc ); + return setupState( CharClassBit ); +#endif +} + +#ifndef QT_NO_REGEXP_BACKREF +int QRegExpEngine::createState( int bref ) +{ + if ( bref > nbrefs ) { + nbrefs = bref; + if ( nbrefs > MaxBackRefs ) { + yyError = TRUE; + return 0; + } + } + return setupState( BackRefBit | bref ); +} +#endif + +/* + The two following functions add a transition between all pairs of states + (i, j) where i is fond in from, and j is found in to. + + Cat-transitions are distinguished from plus-transitions for capturing. +*/ + +void QRegExpEngine::addCatTransitions( const QArray<int>& from, + const QArray<int>& to ) +{ + for ( int i = 0; i < (int) from.size(); i++ ) { + State *st = s[from[i]]; + mergeInto( &st->outs, to ); + } +} + +#ifndef QT_NO_REGEXP_CAPTURE +void QRegExpEngine::addPlusTransitions( const QArray<int>& from, + const QArray<int>& to, int atom ) +{ + for ( int i = 0; i < (int) from.size(); i++ ) { + State *st = s[from[i]]; + QArray<int> oldOuts = st->outs.copy(); + mergeInto( &st->outs, to ); + if ( f[atom].capture >= 0 ) { + if ( st->reenter == 0 ) + st->reenter = new QMap<int, int>; + for ( int j = 0; j < (int) to.size(); j++ ) { + if ( !st->reenter->contains(to[j]) && + oldOuts.bsearch(to[j]) < 0 ) + st->reenter->insert( to[j], atom ); + } + } + } +} +#endif + +#ifndef QT_NO_REGEXP_ANCHOR_ALT +/* + Returns an anchor that means a OR b. +*/ +int QRegExpEngine::anchorAlternation( int a, int b ) +{ + if ( ((a & b) == a || (a & b) == b) && ((a | b) & Anchor_Alternation) == 0 ) + return a & b; + + int n = aa.size(); + aa.resize( n + 1 ); + aa[n].a = a; + aa[n].b = b; + return Anchor_Alternation | n; +} + +/* + Returns an anchor that means a AND b. +*/ +int QRegExpEngine::anchorConcatenation( int a, int b ) +{ + if ( ((a | b) & Anchor_Alternation) == 0 ) + return a | b; + if ( (b & Anchor_Alternation) != 0 ) + qSwap( a, b ); + int aprime = anchorConcatenation( aa[a ^ Anchor_Alternation].a, b ); + int bprime = anchorConcatenation( aa[a ^ Anchor_Alternation].b, b ); + return anchorAlternation( aprime, bprime ); +} +#endif + +/* + Adds anchor a on a transition caracterised by its from state and its to state. +*/ +void QRegExpEngine::addAnchors( int from, int to, int a ) +{ + State *st = s[from]; + if ( st->anchors == 0 ) + st->anchors = new QMap<int, int>; + if ( st->anchors->contains(to) ) + a = anchorAlternation( (*st->anchors)[to], a ); + st->anchors->insert( to, a ); +} + +#ifndef QT_NO_REGEXP_OPTIM +/* + The two following functions provide the engine with the information needed by + its matching heuristics. +*/ + +void QRegExpEngine::setupGoodStringHeuristic( int earlyStart, int lateStart, + const QString& str ) +{ + goodEarlyStart = earlyStart; + goodLateStart = lateStart; + goodStr = cs ? str : str.lower(); +} + +void QRegExpEngine::setupBadCharHeuristic( int minLen, + const QArray<int>& firstOcc ) +{ + minl = minLen; + occ1 = cs ? firstOcc : *firstOccurrenceAtZero; +} + +/* + This function chooses between the good-string and the bad-character + heuristics. It computes two scores and chooses the heuristic with the highest + score. + + Here are some common-sense constraints on the scores that should be respected + if the formulas are ever modified: (1) If goodStr is empty, the good-string + heuristic scores 0. (2) If the search is case insensitive, the good-string + heuristic should be used, unless it scores 0. (Case insensitivity + turns all entries of occ1 to 0.) (3) If (goodLateStart - goodEarlyStart) is + big, the good-string heuristic should score less. +*/ +void QRegExpEngine::heuristicallyChooseHeuristic() +{ + int i; + + if ( minl == 0 ) + return; + + /* + Magic formula: The good string has to constitute a good proportion of the + minimum-length string, and appear at a more-or-less known index. + */ + int goodStringScore = ( 64 * goodStr.length() / minl ) - + ( goodLateStart - goodEarlyStart ); + + /* + Less magic formula: We pick a couple of characters at random, and check + whether they are good or bad. + */ + int badCharScore = 0; + int step = QMAX( 1, NumBadChars / 32 ); + for ( i = 1; i < NumBadChars; i += step ) { + if ( occ1[i] == NoOccurrence ) + badCharScore += minl; + else + badCharScore += occ1[i]; + } + badCharScore /= minl; + + useGoodStringHeuristic = ( goodStringScore > badCharScore ); +} +#endif + +#if defined(QT_DEBUG) +void QRegExpEngine::dump() const +{ + int i, j; + qDebug( "Case %ssensitive engine", cs ? "" : "in" ); + qDebug( " States" ); + for ( i = 0; i < ns; i++ ) { + qDebug( " %d%s", i, + i == InitialState ? " (initial)" : + i == FinalState ? " (final)" : "" ); +#ifndef QT_NO_REGEXP_CAPTURE + qDebug( " in atom %d", s[i]->atom ); +#endif + int m = s[i]->match; + if ( (m & CharClassBit) != 0 ) { + qDebug( " match character class %d", m ^ CharClassBit ); +#ifndef QT_NO_REGEXP_CCLASS + cl[m ^ CharClassBit]->dump(); +#else + qDebug( " negative character class" ); +#endif + } else if ( (m & BackRefBit) != 0 ) { + qDebug( " match back-reference %d", m ^ BackRefBit ); + } else if ( m >= 0x20 && m <= 0x7e ) { + qDebug( " match 0x%.4x (%c)", m, m ); + } else { + qDebug( " match 0x%.4x", m ); + } + for ( j = 0; j < (int) s[i]->outs.size(); j++ ) { + int next = s[i]->outs[j]; + qDebug( " -> %d", next ); + if ( s[i]->reenter != 0 && s[i]->reenter->contains(next) ) + qDebug( " [reenter %d]", (*s[i]->reenter)[next] ); + if ( s[i]->anchors != 0 && at(*s[i]->anchors, next) != 0 ) + qDebug( " [anchors 0x%.8x]", (*s[i]->anchors)[next] ); + } + } +#ifndef QT_NO_REGEXP_CAPTURE + if ( nf > 0 ) { + qDebug( " Atom Parent Capture" ); + for ( i = 0; i < nf; i++ ) + qDebug( " %6d %6d %6d", i, f[i].parent, f[i].capture ); + } +#endif +#ifndef QT_NO_REGEXP_ANCHOR_ALT + for ( i = 0; i < (int) aa.size(); i++ ) + qDebug( " Anchor alternation 0x%.8x: 0x%.8x 0x%.9x", i, aa[i].a, + aa[i].b ); +#endif +} +#endif + +void QRegExpEngine::setup( bool caseSensitive ) +{ +#ifndef QT_NO_REGEXP_OPTIM + if ( engCount++ == 0 ) { + noOccurrences = new QArray<int>( NumBadChars ); + firstOccurrenceAtZero = new QArray<int>( NumBadChars ); + noOccurrences->fill( NoOccurrence ); + firstOccurrenceAtZero->fill( 0 ); + } +#endif + s.setAutoDelete( TRUE ); + s.resize( 32 ); + ns = 0; +#ifndef QT_NO_REGEXP_CAPTURE + f.resize( 32 ); + nf = 0; + cf = -1; +#endif + realncap = 0; + ncap = 0; +#ifndef QT_NO_REGEXP_CCLASS + cl.setAutoDelete( TRUE ); +#endif +#ifndef QT_NO_REGEXP_LOOKAHEAD + ahead.setAutoDelete( TRUE ); +#endif +#ifndef QT_NO_REGEXP_OPTIM + caretAnchored = TRUE; +#endif + valid = FALSE; + cs = caseSensitive; +#ifndef QT_NO_REGEXP_BACKREF + nbrefs = 0; +#endif +#ifndef QT_NO_REGEXP_OPTIM + useGoodStringHeuristic = FALSE; + minl = 0; + occ1 = *firstOccurrenceAtZero; +#endif + mmCapturedNoMatch.fill( -1, 2 ); +} + +int QRegExpEngine::setupState( int match ) +{ + if ( (ns & (ns + 1)) == 0 && ns + 1 >= (int) s.size() ) + s.resize( (ns + 1) << 1 ); +#ifndef QT_NO_REGEXP_CAPTURE + s.insert( ns, new State(cf, match) ); +#else + s.insert( ns, new State(match) ); +#endif + return ns++; +} + +#ifndef QT_NO_REGEXP_CAPTURE +/* + Functions startAtom() and finishAtom() should be called to delimit atoms. + When a state is created, it is assigned to the current atom. The information + is later used for capturing. +*/ +int QRegExpEngine::startAtom( bool capture ) +{ + if ( (nf & (nf + 1)) == 0 && nf + 1 >= (int) f.size() ) + f.resize( (nf + 1) << 1 ); + f[nf].parent = cf; + cf = nf++; + f[cf].capture = capture ? ncap++ : -1; + return cf; +} +#endif + +#ifndef QT_NO_REGEXP_LOOKAHEAD +/* + Creates a lookahead anchor. +*/ +int QRegExpEngine::addLookahead( QRegExpEngine *eng, bool negative ) +{ + int n = ahead.size(); + if ( n == MaxLookaheads ) { + yyError = TRUE; + return 0; + } + ahead.resize( n + 1 ); + ahead.insert( n, new Lookahead(eng, negative) ); + return Anchor_FirstLookahead << n; +} +#endif + +#ifndef QT_NO_REGEXP_CAPTURE +/* + We want the longest leftmost captures. +*/ +bool QRegExpEngine::isBetterCapture( const int *begin1, const int *end1, + const int *begin2, const int *end2 ) +{ + for ( int i = 0; i < ncap; i++ ) { + int delta = begin2[i] - begin1[i]; // it has to start early... + if ( delta == 0 ) + delta = end1[i] - end2[i]; // ...and end late (like a party) + + if ( delta != 0 ) + return delta > 0; + } + return FALSE; +} +#endif + +/* + Returns TRUE if anchor a matches at position mmPos + i in the input string, + otherwise FALSE. +*/ +bool QRegExpEngine::testAnchor( int i, int a, const int *capBegin ) +{ + int j; + +#ifndef QT_NO_REGEXP_ANCHOR_ALT + if ( (a & Anchor_Alternation) != 0 ) { + return testAnchor( i, aa[a ^ Anchor_Alternation].a, capBegin ) || + testAnchor( i, aa[a ^ Anchor_Alternation].b, capBegin ); + } +#endif + + if ( (a & Anchor_Caret) != 0 ) { + if ( mmPos + i != 0 ) + return FALSE; + } + if ( (a & Anchor_Dollar) != 0 ) { + if ( mmPos + i != mmLen ) + return FALSE; + } +#ifndef QT_NO_REGEXP_ESCAPE + if ( (a & (Anchor_Word | Anchor_NonWord)) != 0 ) { + bool before = FALSE, after = FALSE; + if ( mmPos + i != 0 ) + before = mmIn[mmPos + i - 1].isLetterOrNumber(); + if ( mmPos + i != mmLen ) + after = mmIn[mmPos + i].isLetterOrNumber(); + if ( (a & Anchor_Word) != 0 && (before == after) ) + return FALSE; + if ( (a & Anchor_NonWord) != 0 && (before != after) ) + return FALSE; + } +#endif +#ifndef QT_NO_REGEXP_LOOKAHEAD + bool catchx = TRUE; + + if ( (a & Anchor_LookaheadMask) != 0 ) { + QConstString cstr = QConstString( (QChar *) mmIn + mmPos + i, + mmLen - mmPos - i ); + for ( j = 0; j < (int) ahead.size(); j++ ) { + if ( (a & (Anchor_FirstLookahead << j)) != 0 ) { + catchx = ( ahead[j]->eng->match(cstr.string(), 0, TRUE, + TRUE)[0] == 0 ); + if ( catchx == ahead[j]->neg ) + return FALSE; + } + } + } +#endif +#ifndef QT_NO_REGEXP_CAPTURE +#ifndef QT_NO_REGEXP_BACKREF + for ( j = 0; j < nbrefs; j++ ) { + if ( (a & (Anchor_BackRef1Empty << j)) != 0 ) { + if ( capBegin[j] != EmptyCapture ) + return FALSE; + } + } +#endif +#endif + return TRUE; +} + +#ifndef QT_NO_REGEXP_OPTIM +/* + The three following functions are what Jeffrey Friedl would call transmissions + (or bump-alongs). Using one or the other should make no difference, except + in performance. +*/ + +bool QRegExpEngine::goodStringMatch() +{ + int k = mmPos + goodEarlyStart; + + while ( (k = mmStr->find(goodStr, k, cs)) != -1 ) { + int from = k - goodLateStart; + int to = k - goodEarlyStart; + if ( from > mmPos ) + mmPos = from; + + while ( mmPos <= to ) { + if ( matchHere() ) + return TRUE; + mmPos++; + } + k++; + } + return FALSE; +} + +bool QRegExpEngine::badCharMatch() +{ + int slideHead = 0; + int slideNext = 0; + int i; + int lastPos = mmLen - minl; + memset( mmSlideTab, 0, mmSlideTabSize * sizeof(int) ); + + /* + Set up the slide table, used for the bad-character heuristic, using + the table of first occurrence of each character. + */ + for ( i = 0; i < minl; i++ ) { + int sk = occ1[BadChar(mmIn[mmPos + i])]; + if ( sk == NoOccurrence ) + sk = i + 1; + if ( sk > 0 ) { + int k = i + 1 - sk; + if ( k < 0 ) { + sk = i + 1; + k = 0; + } + if ( sk > mmSlideTab[k] ) + mmSlideTab[k] = sk; + } + } + + if ( mmPos > lastPos ) + return FALSE; + + while ( TRUE ) { + if ( ++slideNext >= mmSlideTabSize ) + slideNext = 0; + if ( mmSlideTab[slideHead] > 0 ) { + if ( mmSlideTab[slideHead] - 1 > mmSlideTab[slideNext] ) + mmSlideTab[slideNext] = mmSlideTab[slideHead] - 1; + mmSlideTab[slideHead] = 0; + } else { + if ( matchHere() ) + return TRUE; + } + + if ( mmPos == lastPos ) + break; + + /* + Update the slide table. This code has much in common with the + initialization code. + */ + int sk = occ1[BadChar(mmIn[mmPos + minl])]; + if ( sk == NoOccurrence ) { + mmSlideTab[slideNext] = minl; + } else if ( sk > 0 ) { + int k = slideNext + minl - sk; + if ( k >= mmSlideTabSize ) + k -= mmSlideTabSize; + if ( sk > mmSlideTab[k] ) + mmSlideTab[k] = sk; + } + slideHead = slideNext; + mmPos++; + } + return FALSE; +} +#else +bool QRegExpEngine::bruteMatch() +{ + while ( mmPos <= mmLen ) { + if ( matchHere() ) + return TRUE; + mmPos++; + } + return FALSE; +} +#endif + +/* + Here's the core of the engine. It tries to do a match here and now. +*/ +bool QRegExpEngine::matchHere() +{ + int ncur = 1, nnext = 0; + int i = 0, j, k, m; + bool match = FALSE; + + mmMatchedLen = -1; + mmCurStack[0] = InitialState; + +#ifndef QT_NO_REGEXP_CAPTURE + if ( ncap > 0 ) { + for ( j = 0; j < ncap; j++ ) { + mmCurCapBegin[j] = EmptyCapture; + mmCurCapEnd[j] = EmptyCapture; + } + } +#endif + +#ifndef QT_NO_REGEXP_BACKREF + int *zzZ = 0; + + while ( (ncur > 0 || mmSleeping.count() > 0) && i <= mmLen - mmPos && + !match ) +#else + while ( ncur > 0 && i <= mmLen - mmPos && !match ) +#endif + { + int ch = ( i < mmLen - mmPos ) ? mmIn[mmPos + i].unicode() : 0; + for ( j = 0; j < ncur; j++ ) { + int cur = mmCurStack[j]; + State *scur = s[cur]; + QArray<int>& outs = scur->outs; + for ( k = 0; k < (int) outs.size(); k++ ) { + int next = outs[k]; + State *snext = s[next]; + bool in = TRUE; +#ifndef QT_NO_REGEXP_BACKREF + int needSomeSleep = 0; +#endif + + /* + First, check if the anchors are anchored properly. + */ + if ( scur->anchors != 0 ) { + int a = at( *scur->anchors, next ); + if ( a != 0 && !testAnchor(i, a, mmCurCapBegin + j * ncap) ) + in = FALSE; + } + /* + If indeed they are, check if the input character is correct + for this transition. + */ + if ( in ) { + m = snext->match; + if ( (m & (CharClassBit | BackRefBit)) == 0 ) { + if ( cs ) + in = ( m == ch ); + else + in = ( QChar(m).lower() == QChar(ch).lower() ); + } else if ( next == FinalState ) { + mmMatchedLen = i; + match = mmMinimal; + in = TRUE; + } else if ( (m & CharClassBit) != 0 ) { +#ifndef QT_NO_REGEXP_CCLASS + const CharClass *cc = cl[m ^ CharClassBit]; + if ( cs ) + in = cc->in( ch ); + else if ( cc->negative() ) + in = cc->in( QChar(ch).lower() ) && + cc->in( QChar(ch).upper() ); + else + in = cc->in( QChar(ch).lower() ) || + cc->in( QChar(ch).upper() ); +#endif +#ifndef QT_NO_REGEXP_BACKREF + } else { /* ( (m & BackRefBit) != 0 ) */ + int bref = m ^ BackRefBit; + int ell = j * ncap + ( bref - 1 ); + + in = bref <= ncap && mmCurCapBegin[ell] != EmptyCapture; + if ( in ) { + if ( cs ) + in = ( mmIn[mmPos + mmCurCapBegin[ell]] + == QChar(ch) ); + else + in = ( mmIn[mmPos + mmCurCapBegin[ell]].lower() + == QChar(ch).lower() ); + } + + if ( in ) { + int delta; + if ( mmCurCapEnd[ell] == EmptyCapture ) + delta = i - mmCurCapBegin[ell]; + else + delta = mmCurCapEnd[ell] - mmCurCapBegin[ell]; + + in = ( delta <= mmLen - mmPos ); + if ( in && delta > 1 ) { + int n; + if ( cs ) { + for ( n = 1; n < delta; n++ ) { + if ( mmIn[mmPos + + mmCurCapBegin[ell] + n] != + mmIn[mmPos + i + n] ) + break; + } + } else { + for ( n = 1; n < delta; n++ ) { + QChar a = mmIn[mmPos + + mmCurCapBegin[ell] + n]; + QChar b = mmIn[mmPos + i + n]; + if ( a.lower() != b.lower() ) + break; + } + } + in = ( n == delta ); + if ( in ) + needSomeSleep = delta - 1; + } + } +#endif + } + } + + /* + All is right. We must now update our data structures. + */ + if ( in ) { +#ifndef QT_NO_REGEXP_CAPTURE + int *capBegin, *capEnd; +#endif + /* + If the next state was not encountered yet, all is fine. + */ + if ( (m = mmInNextStack[next]) == -1 ) { + m = nnext++; + mmNextStack[m] = next; + mmInNextStack[next] = m; +#ifndef QT_NO_REGEXP_CAPTURE + capBegin = mmNextCapBegin + m * ncap; + capEnd = mmNextCapEnd + m * ncap; + + /* + Otherwise, we'll first maintain captures in temporary + arrays, and decide at the end whether it's best to keep + the previous capture zones or the new ones. + */ + } else { + capBegin = mmTempCapBegin; + capEnd = mmTempCapEnd; +#endif + } + +#ifndef QT_NO_REGEXP_CAPTURE + /* + Updating the capture zones is much of a task. + */ + if ( ncap > 0 ) { + memcpy( capBegin, mmCurCapBegin + j * ncap, + ncap * sizeof(int) ); + memcpy( capEnd, mmCurCapEnd + j * ncap, + ncap * sizeof(int) ); + int c = scur->atom, n = snext->atom; + int p = -1, q = -1; + int cap; + + /* + Lemma 1. For any x in the range [0..nf), we have + f[x].parent < x. + + Proof. By looking at startAtom(), it is clear that + cf < nf holds all the time, and thus that + f[nf].parent < nf. + */ + + /* + If we are reentering an atom, we empty all capture + zones inside it. + */ + if ( scur->reenter != 0 && + (q = at(*scur->reenter, next)) != 0 ) { + QBitArray b; + b.fill( FALSE, nf ); + b.setBit( q, TRUE ); + for ( int ell = q + 1; ell < nf; ell++ ) { + if ( b.testBit(f[ell].parent) ) { + b.setBit( ell, TRUE ); + cap = f[ell].capture; + if ( cap >= 0 ) { + capBegin[cap] = EmptyCapture; + capEnd[cap] = EmptyCapture; + } + } + } + p = f[q].parent; + + /* + Otherwise, close the capture zones we are leaving. + We are leaving f[c].capture, f[f[c].parent].capture, + f[f[f[c].parent].parent].capture, ..., until + f[x].capture, with x such that f[x].parent is the + youngest common ancestor for c and n. + + We go up along c's and n's ancestry until we find x. + */ + } else { + p = c; + q = n; + while ( p != q ) { + if ( p > q ) { + cap = f[p].capture; + if ( cap >= 0 ) { + if ( capBegin[cap] == i ) { + capBegin[cap] = EmptyCapture; + capEnd[cap] = EmptyCapture; + } else { + capEnd[cap] = i; + } + } + p = f[p].parent; + } else { + q = f[q].parent; + } + } + } + + /* + In any case, we now open the capture zones we are + entering. We work upwards from n until we reach p + (the parent of the atom we reenter or the youngest + common ancestor). + */ + while ( n > p ) { + cap = f[n].capture; + if ( cap >= 0 ) { + capBegin[cap] = i; + capEnd[cap] = EmptyCapture; + } + n = f[n].parent; + } + /* + If the next state was already in mmNextStack, we must + choose carefully which capture zones we want to keep. + */ + if ( capBegin == mmTempCapBegin && + isBetterCapture(capBegin, capEnd, + mmNextCapBegin + m * ncap, + mmNextCapEnd + m * ncap) ) { + memcpy( mmNextCapBegin + m * ncap, capBegin, + ncap * sizeof(int) ); + memcpy( mmNextCapEnd + m * ncap, capEnd, + ncap * sizeof(int) ); + } + } +#ifndef QT_NO_REGEXP_BACKREF + /* + We are done with updating the capture zones. It's now + time to put the next state to sleep, if it needs to, and + to remove it from mmNextStack. + */ + if ( needSomeSleep > 0 ) { + zzZ = new int[1 + 2 * ncap]; + zzZ[0] = next; + if ( ncap > 0 ) { + memcpy( zzZ + 1, capBegin, ncap * sizeof(int) ); + memcpy( zzZ + 1 + ncap, capEnd, + ncap * sizeof(int) ); + } + mmInNextStack[mmNextStack[--nnext]] = -1; + mmSleeping.insert( i + needSomeSleep, zzZ ); + } +#endif +#endif + } + } + } +#ifndef QT_NO_REGEXP_CAPTURE + /* + If we reached the final state, hurray! Copy the captured zone. + */ + if ( ncap > 0 && (m = mmInNextStack[FinalState]) != -1 ) { + memcpy( mmCapBegin, mmNextCapBegin + m * ncap, ncap * sizeof(int) ); + memcpy( mmCapEnd, mmNextCapEnd + m * ncap, ncap * sizeof(int) ); + } +#ifndef QT_NO_REGEXP_BACKREF + /* + It's time to wake up the sleepers. + */ + if ( mmSleeping.count() > 0 ) { + while ( (zzZ = mmSleeping.take(i)) != 0 ) { + int next = zzZ[0]; + int *capBegin = zzZ + 1; + int *capEnd = zzZ + 1 + ncap; + bool copyOver = TRUE; + + if ( (m = mmInNextStack[zzZ[0]]) == -1 ) { + m = nnext++; + mmNextStack[m] = next; + mmInNextStack[next] = m; + } else { + copyOver = isBetterCapture( mmNextCapBegin + m * ncap, + mmNextCapEnd + m * ncap, + capBegin, capEnd ); + } + if ( copyOver ) { + memcpy( mmNextCapBegin + m * ncap, capBegin, + ncap * sizeof(int) ); + memcpy( mmNextCapEnd + m * ncap, capEnd, + ncap * sizeof(int) ); + } + delete[] zzZ; + } + } +#endif +#endif + for ( j = 0; j < nnext; j++ ) + mmInNextStack[mmNextStack[j]] = -1; + + qSwap( mmCurStack, mmNextStack ); +#ifndef QT_NO_REGEXP_CAPTURE + qSwap( mmCurCapBegin, mmNextCapBegin ); + qSwap( mmCurCapEnd, mmNextCapEnd ); +#endif + ncur = nnext; + nnext = 0; + i++; + } + +#ifndef QT_NO_REGEXP_BACKREF + /* + If minimal matching is enabled, we might have some sleepers left. + */ + while ( !mmSleeping.isEmpty() ) { + zzZ = mmSleeping.take( *QIntDictIterator<int>(mmSleeping) ); + delete[] zzZ; + } +#endif + + match = ( mmMatchedLen >= 0 ); + if ( !match ) + mmMatchedLen = i - 1; + return match; +} + +#ifndef QT_NO_REGEXP_CCLASS + +QRegExpEngine::CharClass::CharClass() + : c( 0 ), n( FALSE ) +#ifndef QT_NO_REGEXP_OPTIM + , occ1( *noOccurrences ) +#endif +{ +} + +QRegExpEngine::CharClass& QRegExpEngine::CharClass::operator=( + const CharClass& cc ) +{ + c = cc.c; + r = cc.r.copy(); + n = cc.n; +#ifndef QT_NO_REGEXP_OPTIM + occ1 = cc.occ1; +#endif + return *this; +} + +void QRegExpEngine::CharClass::clear() +{ + c = 0; + r.resize( 0 ); + n = FALSE; +} + +void QRegExpEngine::CharClass::setNegative( bool negative ) +{ + n = negative; +#ifndef QT_NO_REGEXP_OPTIM + occ1 = *firstOccurrenceAtZero; +#endif +} + +void QRegExpEngine::CharClass::addCategories( int cats ) +{ + c |= cats; +#ifndef QT_NO_REGEXP_OPTIM + occ1 = *firstOccurrenceAtZero; +#endif +} + +void QRegExpEngine::CharClass::addRange( ushort from, ushort to ) +{ + if ( from > to ) + qSwap( from, to ); + int n = r.size(); + r.resize( n + 1 ); + r[n].from = from; + r[n].to = to; + +#ifndef QT_NO_REGEXP_OPTIM + int i; + + if ( to - from < NumBadChars ) { + occ1.detach(); + if ( from % NumBadChars <= to % NumBadChars ) { + for ( i = from % NumBadChars; i <= to % NumBadChars; i++ ) + occ1[i] = 0; + } else { + for ( i = 0; i <= to % NumBadChars; i++ ) + occ1[i] = 0; + for ( i = from % NumBadChars; i < NumBadChars; i++ ) + occ1[i] = 0; + } + } else { + occ1 = *firstOccurrenceAtZero; + } +#endif +} + +bool QRegExpEngine::CharClass::in( QChar ch ) const +{ +#ifndef QT_NO_REGEXP_OPTIM + if ( occ1[BadChar(ch)] == NoOccurrence ) + return n; +#endif + + if ( c != 0 && (c & (1 << (int) ch.category())) != 0 ) + return !n; + for ( int i = 0; i < (int) r.size(); i++ ) { + if ( ch.unicode() >= r[i].from && ch.unicode() <= r[i].to ) + return !n; + } + return n; +} + +#if defined(QT_DEBUG) +void QRegExpEngine::CharClass::dump() const +{ + int i; + qDebug( " %stive character class", n ? "nega" : "posi" ); +#ifndef QT_NO_REGEXP_CCLASS + if ( c != 0 ) + qDebug( " categories 0x%.8x", c ); +#endif + for ( i = 0; i < (int) r.size(); i++ ) + qDebug( " 0x%.4x through 0x%.4x", r[i].from, r[i].to ); +} +#endif +#endif + +QRegExpEngine::Box::Box( QRegExpEngine *engine ) + : eng( engine ), skipanchors( 0 ) +#ifndef QT_NO_REGEXP_OPTIM + , earlyStart( 0 ), lateStart( 0 ), maxl( 0 ), occ1( *noOccurrences ) +#endif +{ + minl = 0; +} + +QRegExpEngine::Box& QRegExpEngine::Box::operator=( const Box& b ) +{ + eng = b.eng; + ls = b.ls; + rs = b.rs; + lanchors = b.lanchors; + ranchors = b.ranchors; + skipanchors = b.skipanchors; +#ifndef QT_NO_REGEXP_OPTIM + earlyStart = b.earlyStart; + lateStart = b.lateStart; + str = b.str; + leftStr = b.leftStr; + rightStr = b.rightStr; + maxl = b.maxl; + occ1 = b.occ1; +#endif + minl = b.minl; + return *this; +} + +void QRegExpEngine::Box::set( QChar ch ) +{ + ls.resize( 1 ); + ls[0] = eng->createState( ch ); + rs = ls; + rs.detach(); +#ifndef QT_NO_REGEXP_OPTIM + str = ch; + leftStr = ch; + rightStr = ch; + maxl = 1; + occ1.detach(); + occ1[BadChar(ch)] = 0; +#endif + minl = 1; +} + +void QRegExpEngine::Box::set( const CharClass& cc ) +{ + ls.resize( 1 ); + ls[0] = eng->createState( cc ); + rs = ls; + rs.detach(); +#ifndef QT_NO_REGEXP_OPTIM + maxl = 1; + occ1 = cc.firstOccurrence(); +#endif + minl = 1; +} + +#ifndef QT_NO_REGEXP_BACKREF +void QRegExpEngine::Box::set( int bref ) +{ + ls.resize( 1 ); + ls[0] = eng->createState( bref ); + rs = ls; + rs.detach(); + if ( bref >= 1 && bref <= MaxBackRefs ) + skipanchors = Anchor_BackRef0Empty << bref; +#ifndef QT_NO_REGEXP_OPTIM + maxl = InftyLen; +#endif + minl = 0; +} +#endif + +void QRegExpEngine::Box::cat( const Box& b ) +{ + eng->addCatTransitions( rs, b.ls ); + addAnchorsToEngine( b ); + if ( minl == 0 ) { + mergeInto( &lanchors, b.lanchors ); + if ( skipanchors != 0 ) { + for ( int i = 0; i < (int) b.ls.size(); i++ ) { + int a = eng->anchorConcatenation( at(lanchors, b.ls[i]), + skipanchors ); + lanchors.insert( b.ls[i], a ); + } + } + mergeInto( &ls, b.ls ); + } + if ( b.minl == 0 ) { + mergeInto( &ranchors, b.ranchors ); + if ( b.skipanchors != 0 ) { + for ( int i = 0; i < (int) rs.size(); i++ ) { + int a = eng->anchorConcatenation( at(ranchors, rs[i]), + b.skipanchors ); + ranchors.insert( rs[i], a ); + } + } + mergeInto( &rs, b.rs ); + } else { + ranchors = b.ranchors; + rs = b.rs; + } + +#ifndef QT_NO_REGEXP_OPTIM + if ( maxl != InftyLen ) { + if ( rightStr.length() + b.leftStr.length() > + QMAX(str.length(), b.str.length()) ) { + earlyStart = minl - rightStr.length(); + lateStart = maxl - rightStr.length(); + str = rightStr + b.leftStr; + } else if ( b.str.length() > str.length() ) { + earlyStart = minl + b.earlyStart; + lateStart = maxl + b.lateStart; + str = b.str; + } + } + + if ( (int) leftStr.length() == maxl ) + leftStr += b.leftStr; + if ( (int) b.rightStr.length() == b.maxl ) + rightStr += b.rightStr; + else + rightStr = b.rightStr; + + if ( maxl == InftyLen || b.maxl == InftyLen ) + maxl = InftyLen; + else + maxl += b.maxl; + + occ1.detach(); + for ( int i = 0; i < NumBadChars; i++ ) { + if ( b.occ1[i] != NoOccurrence && minl + b.occ1[i] < occ1[i] ) + occ1[i] = minl + b.occ1[i]; + } +#endif + + minl += b.minl; + if ( minl == 0 ) + skipanchors = eng->anchorConcatenation( skipanchors, b.skipanchors ); + else + skipanchors = 0; +} + +void QRegExpEngine::Box::orx( const Box& b ) +{ + mergeInto( &ls, b.ls ); + mergeInto( &lanchors, b.lanchors ); + mergeInto( &rs, b.rs ); + mergeInto( &ranchors, b.ranchors ); + skipanchors = eng->anchorAlternation( skipanchors, b.skipanchors ); + +#ifndef QT_NO_REGEXP_OPTIM + occ1.detach(); + for ( int i = 0; i < NumBadChars; i++ ) { + if ( occ1[i] > b.occ1[i] ) + occ1[i] = b.occ1[i]; + } + earlyStart = 0; + lateStart = 0; + str = QString::null; + leftStr = QString::null; + rightStr = QString::null; + if ( b.maxl > maxl ) + maxl = b.maxl; +#endif + if ( b.minl < minl ) + minl = b.minl; +} + +void QRegExpEngine::Box::plus( int atom ) +{ +#ifndef QT_NO_REGEXP_CAPTURE + eng->addPlusTransitions( rs, ls, atom ); +#else + Q_UNUSED( atom ); + eng->addCatTransitions( rs, ls ); +#endif + addAnchorsToEngine( *this ); +#ifndef QT_NO_REGEXP_OPTIM + maxl = InftyLen; +#endif +} + +void QRegExpEngine::Box::opt() +{ +#ifndef QT_NO_REGEXP_OPTIM + earlyStart = 0; + lateStart = 0; + str = QString::null; + leftStr = QString::null; + rightStr = QString::null; +#endif + skipanchors = 0; + minl = 0; +} + +void QRegExpEngine::Box::catAnchor( int a ) +{ + if ( a != 0 ) { + for ( int i = 0; i < (int) rs.size(); i++ ) { + a = eng->anchorConcatenation( at(ranchors, rs[i]), a ); + ranchors.insert( rs[i], a ); + } + if ( minl == 0 ) + skipanchors = eng->anchorConcatenation( skipanchors, a ); + } +} + +#ifndef QT_NO_REGEXP_OPTIM +void QRegExpEngine::Box::setupHeuristics() +{ + eng->setupGoodStringHeuristic( earlyStart, lateStart, str ); + + /* + A regular expression such as 112|1 has occ1['2'] = 2 and minl = 1 at this + point. An entry of occ1 has to be at most minl or infinity for the rest + of the algorithm to go well. + + We waited until here before normalizing these cases (instead of doing it + in Box::orx()) because sometimes things improve by themselves; consider + (112|1)34. + */ + for ( int i = 0; i < NumBadChars; i++ ) { + if ( occ1[i] != NoOccurrence && occ1[i] >= minl ) + occ1[i] = minl; + } + eng->setupBadCharHeuristic( minl, occ1 ); + + eng->heuristicallyChooseHeuristic(); +} +#endif + +#if defined(QT_DEBUG) +void QRegExpEngine::Box::dump() const +{ + int i; + qDebug( "Box of at least %d character%s", minl, minl == 1 ? "" : "s" ); + qDebug( " Left states:" ); + for ( i = 0; i < (int) ls.size(); i++ ) { + if ( at(lanchors, ls[i]) == 0 ) + qDebug( " %d", ls[i] ); + else + qDebug( " %d [anchors 0x%.8x]", ls[i], lanchors[ls[i]] ); + } + qDebug( " Right states:" ); + for ( i = 0; i < (int) rs.size(); i++ ) { + if ( at(ranchors, ls[i]) == 0 ) + qDebug( " %d", rs[i] ); + else + qDebug( " %d [anchors 0x%.8x]", rs[i], ranchors[rs[i]] ); + } + qDebug( " Skip anchors: 0x%.8x", skipanchors ); +} +#endif + +void QRegExpEngine::Box::addAnchorsToEngine( const Box& to ) const +{ + for ( int i = 0; i < (int) to.ls.size(); i++ ) { + for ( int j = 0; j < (int) rs.size(); j++ ) { + int a = eng->anchorConcatenation( at(ranchors, rs[j]), + at(to.lanchors, to.ls[i]) ); + eng->addAnchors( rs[j], to.ls[i], a ); + } + } +} + +int QRegExpEngine::getChar() +{ + return ( yyPos == yyLen ) ? EOS : yyIn[yyPos++].unicode(); +} + +int QRegExpEngine::getEscape() +{ +#ifndef QT_NO_REGEXP_ESCAPE + const char tab[] = "afnrtv"; // no b, as \b means word boundary + const char backTab[] = "\a\f\n\r\t\v"; + ushort low; + int i; +#endif + ushort val; + int prevCh = yyCh; + + if ( prevCh == EOS ) { + yyError = TRUE; + return Tok_Char | '\\'; + } + yyCh = getChar(); +#ifndef QT_NO_REGEXP_ESCAPE + if ( (prevCh & ~0xff) == 0 ) { + const char *p = strchr( tab, prevCh ); + if ( p != 0 ) + return Tok_Char | backTab[p - tab]; + } +#endif + + switch ( prevCh ) { +#ifndef QT_NO_REGEXP_ESCAPE + case '0': + val = 0; + for ( i = 0; i < 3; i++ ) { + if ( yyCh >= '0' && yyCh <= '7' ) + val = ( val << 3 ) | ( yyCh - '0' ); + else + break; + yyCh = getChar(); + } + if ( (val & ~0377) != 0 ) + yyError = TRUE; + return Tok_Char | val; +#endif +#ifndef QT_NO_REGEXP_ESCAPE + case 'B': + return Tok_NonWord; +#endif +#ifndef QT_NO_REGEXP_CCLASS + case 'D': + // see QChar::isDigit() + yyCharClass->addCategories( 0x7fffffef ); + return Tok_CharClass; + case 'S': + // see QChar::isSpace() + yyCharClass->addCategories( 0x7ffff87f ); + yyCharClass->addRange( 0x0000, 0x0008 ); + yyCharClass->addRange( 0x000e, 0x001f ); + yyCharClass->addRange( 0x007f, 0x009f ); + return Tok_CharClass; + case 'W': + // see QChar::isLetterOrNumber() + yyCharClass->addCategories( 0x7ff07f8f ); + return Tok_CharClass; +#endif +#ifndef QT_NO_REGEXP_ESCAPE + case 'b': + return Tok_Word; +#endif +#ifndef QT_NO_REGEXP_CCLASS + case 'd': + // see QChar::isDigit() + yyCharClass->addCategories( 0x00000010 ); + return Tok_CharClass; + case 's': + // see QChar::isSpace() + yyCharClass->addCategories( 0x00000380 ); + yyCharClass->addRange( 0x0009, 0x000d ); + return Tok_CharClass; + case 'w': + // see QChar::isLetterOrNumber() + yyCharClass->addCategories( 0x000f8070 ); + return Tok_CharClass; +#endif +#ifndef QT_NO_REGEXP_ESCAPE + case 'x': + val = 0; + for ( i = 0; i < 4; i++ ) { + low = QChar( yyCh ).lower(); + if ( low >= '0' && low <= '9' ) + val = ( val << 4 ) | ( low - '0' ); + else if ( low >= 'a' && low <= 'f' ) + val = ( val << 4 ) | ( low - 'a' + 10 ); + else + break; + yyCh = getChar(); + } + return Tok_Char | val; +#endif + default: + if ( prevCh >= '1' && prevCh <= '9' ) { +#ifndef QT_NO_REGEXP_BACKREF + val = prevCh - '0'; + while ( yyCh >= '0' && yyCh <= '9' ) { + val = ( val *= 10 ) | ( yyCh - '0' ); + yyCh = getChar(); + } + return Tok_BackRef | val; +#else + yyError = TRUE; +#endif + } + return Tok_Char | prevCh; + } +} + +#ifndef QT_NO_REGEXP_INTERVAL +int QRegExpEngine::getRep( int def ) +{ + if ( yyCh >= '0' && yyCh <= '9' ) { + int rep = 0; + do { + rep = 10 * rep + yyCh - '0'; + if ( rep >= InftyRep ) { + yyError = TRUE; + rep = def; + } + yyCh = getChar(); + } while ( yyCh >= '0' && yyCh <= '9' ); + return rep; + } else { + return def; + } +} +#endif + +#ifndef QT_NO_REGEXP_LOOKAHEAD +void QRegExpEngine::skipChars( int n ) +{ + if ( n > 0 ) { + yyPos += n - 1; + yyCh = getChar(); + } +} +#endif + +void QRegExpEngine::startTokenizer( const QChar *rx, int len ) +{ + yyIn = rx; + yyPos0 = 0; + yyPos = 0; + yyLen = len; + yyCh = getChar(); + yyCharClass = new CharClass; + yyMinRep = 0; + yyMaxRep = 0; + yyError = FALSE; +} + +int QRegExpEngine::getToken() +{ +#ifndef QT_NO_REGEXP_CCLASS + ushort pendingCh = 0; + bool charPending; + bool rangePending; + int tok; +#endif + int prevCh = yyCh; + + yyPos0 = yyPos - 1; +#ifndef QT_NO_REGEXP_CCLASS + yyCharClass->clear(); +#endif + yyMinRep = 0; + yyMaxRep = 0; + yyCh = getChar(); + switch ( prevCh ) { + case EOS: + yyPos0 = yyPos; + return Tok_Eos; + case '$': + return Tok_Dollar; + case '(': + if ( yyCh == '?' ) { + prevCh = getChar(); + yyCh = getChar(); + switch ( prevCh ) { +#ifndef QT_NO_REGEXP_LOOKAHEAD + case '!': + return Tok_NegLookahead; + case '=': + return Tok_PosLookahead; +#endif + case ':': + return Tok_MagicLeftParen; + default: + yyError = TRUE; + return Tok_MagicLeftParen; + } + } else { + return Tok_LeftParen; + } + case ')': + return Tok_RightParen; + case '*': + yyMinRep = 0; + yyMaxRep = InftyRep; + return Tok_Quantifier; + case '+': + yyMinRep = 1; + yyMaxRep = InftyRep; + return Tok_Quantifier; + case '.': +#ifndef QT_NO_REGEXP_CCLASS + yyCharClass->setNegative( TRUE ); +#endif + return Tok_CharClass; + case '?': + yyMinRep = 0; + yyMaxRep = 1; + return Tok_Quantifier; + case '[': +#ifndef QT_NO_REGEXP_CCLASS + if ( yyCh == '^' ) { + yyCharClass->setNegative( TRUE ); + yyCh = getChar(); + } + charPending = FALSE; + rangePending = FALSE; + do { + if ( yyCh == '-' && charPending && !rangePending ) { + rangePending = TRUE; + yyCh = getChar(); + } else { + if ( charPending && !rangePending ) { + yyCharClass->addSingleton( pendingCh ); + charPending = FALSE; + } + if ( yyCh == '\\' ) { + yyCh = getChar(); + tok = getEscape(); + if ( tok == Tok_Word ) + tok = '\b'; + } else { + tok = Tok_Char | yyCh; + yyCh = getChar(); + } + if ( tok == Tok_CharClass ) { + if ( rangePending ) { + yyCharClass->addSingleton( '-' ); + yyCharClass->addSingleton( pendingCh ); + charPending = FALSE; + rangePending = FALSE; + } + } else if ( (tok & Tok_Char) != 0 ) { + if ( rangePending ) { + yyCharClass->addRange( pendingCh, tok ^ Tok_Char ); + charPending = FALSE; + rangePending = FALSE; + } else { + pendingCh = tok ^ Tok_Char; + charPending = TRUE; + } + } else { + yyError = TRUE; + } + } + } while ( yyCh != ']' && yyCh != EOS ); + if ( rangePending ) + yyCharClass->addSingleton( '-' ); + if ( charPending ) + yyCharClass->addSingleton( pendingCh ); + if ( yyCh == EOS ) + yyError = TRUE; + else + yyCh = getChar(); + return Tok_CharClass; +#else + yyError = TRUE; + return Tok_Char | '['; +#endif + case '\\': + return getEscape(); + case ']': + yyError = TRUE; + return Tok_Char | ']'; + case '^': + return Tok_Caret; +#ifndef QT_NO_REGEXP_INTERVAL + case '{': + yyMinRep = getRep( 0 ); + yyMaxRep = yyMinRep; + if ( yyCh == ',' ) { + yyCh = getChar(); + yyMaxRep = getRep( InftyRep ); + } + if ( yyMaxRep < yyMinRep ) + qSwap( yyMinRep, yyMaxRep ); + if ( yyCh != '}' ) + yyError = TRUE; + yyCh = getChar(); + return Tok_Quantifier; +#else + yyError = TRUE; + return Tok_Char | '{'; +#endif + case '|': + return Tok_Bar; + case '}': + yyError = TRUE; + return Tok_Char | '}'; + default: + return Tok_Char | prevCh; + } +} + +int QRegExpEngine::parse( const QChar *pattern, int len ) +{ + valid = TRUE; + startTokenizer( pattern, len ); + yyTok = getToken(); +#ifndef QT_NO_REGEXP_CAPTURE + yyMayCapture = TRUE; +#else + yyMayCapture = FALSE; +#endif + +#ifndef QT_NO_REGEXP_CAPTURE + int atom = startAtom( FALSE ); +#endif + CharClass anything; + Box box( this ); // create InitialState + box.set( anything ); + Box rightBox( this ); // create FinalState + rightBox.set( anything ); + + Box middleBox( this ); + parseExpression( &middleBox ); +#ifndef QT_NO_REGEXP_CAPTURE + finishAtom( atom ); +#endif +#ifndef QT_NO_REGEXP_OPTIM + middleBox.setupHeuristics(); +#endif + box.cat( middleBox ); + box.cat( rightBox ); + delete yyCharClass; + yyCharClass = 0; + + realncap = ncap; +#ifndef QT_NO_REGEXP_BACKREF + if ( nbrefs > ncap ) + ncap = nbrefs; +#endif + + mmCaptured.resize( 2 + 2 * realncap ); + mmCapturedNoMatch.fill( -1, 2 + 2 * realncap ); + + /* + We use one QArray<int> for all the big data used a lot in matchHere() and + friends. + */ +#ifndef QT_NO_REGEXP_OPTIM + mmSlideTabSize = QMAX( minl + 1, 16 ); +#else + mmSlideTabSize = 0; +#endif + mmBigArray.resize( (3 + 4 * ncap) * ns + 4 * ncap + mmSlideTabSize ); + + mmInNextStack = mmBigArray.data(); + memset( mmInNextStack, -1, ns * sizeof(int) ); + mmCurStack = mmInNextStack + ns; + mmNextStack = mmInNextStack + 2 * ns; + + mmCurCapBegin = mmInNextStack + 3 * ns; + mmNextCapBegin = mmCurCapBegin + ncap * ns; + mmCurCapEnd = mmCurCapBegin + 2 * ncap * ns; + mmNextCapEnd = mmCurCapBegin + 3 * ncap * ns; + + mmTempCapBegin = mmCurCapBegin + 4 * ncap * ns; + mmTempCapEnd = mmTempCapBegin + ncap; + mmCapBegin = mmTempCapBegin + 2 * ncap; + mmCapEnd = mmTempCapBegin + 3 * ncap; + + mmSlideTab = mmTempCapBegin + 4 * ncap; + + if ( yyError ) + return -1; + +#ifndef QT_NO_REGEXP_OPTIM + State *sinit = s[InitialState]; + caretAnchored = ( sinit->anchors != 0 ); + if ( caretAnchored ) { + QMap<int, int>& anchors = *sinit->anchors; + QMap<int, int>::ConstIterator a; + for ( a = anchors.begin(); a != anchors.end(); ++a ) { +#ifndef QT_NO_REGEXP_ANCHOR_ALT + if ( (*a & Anchor_Alternation) != 0 ) + break; +#endif + if ( (*a & Anchor_Caret) == 0 ) { + caretAnchored = FALSE; + break; + } + } + } +#endif + return yyPos0; +} + +void QRegExpEngine::parseAtom( Box *box ) +{ +#ifndef QT_NO_REGEXP_LOOKAHEAD + QRegExpEngine *eng = 0; + bool neg; + int len; +#endif + + switch ( yyTok ) { + case Tok_Dollar: + box->catAnchor( Anchor_Dollar ); + break; + case Tok_Caret: + box->catAnchor( Anchor_Caret ); + break; +#ifndef QT_NO_REGEXP_LOOKAHEAD + case Tok_PosLookahead: + case Tok_NegLookahead: + neg = ( yyTok == Tok_NegLookahead ); + eng = new QRegExpEngine( cs ); + len = eng->parse( yyIn + yyPos - 1, yyLen - yyPos + 1 ); + if ( len >= 0 ) + skipChars( len ); + else + yyError = TRUE; + box->catAnchor( addLookahead(eng, neg) ); + yyTok = getToken(); + if ( yyTok != Tok_RightParen ) + yyError = TRUE; + break; +#endif +#ifndef QT_NO_REGEXP_ESCAPE + case Tok_Word: + box->catAnchor( Anchor_Word ); + break; + case Tok_NonWord: + box->catAnchor( Anchor_NonWord ); + break; +#endif + case Tok_LeftParen: + case Tok_MagicLeftParen: + yyTok = getToken(); + parseExpression( box ); + if ( yyTok != Tok_RightParen ) + yyError = TRUE; + break; + case Tok_CharClass: + box->set( *yyCharClass ); + break; + default: + if ( (yyTok & Tok_Char) != 0 ) + box->set( QChar(yyTok ^ Tok_Char) ); +#ifndef QT_NO_REGEXP_BACKREF + else if ( (yyTok & Tok_BackRef) != 0 ) + box->set( yyTok ^ Tok_BackRef ); +#endif + else + yyError = TRUE; + } + yyTok = getToken(); +} + +void QRegExpEngine::parseFactor( Box *box ) +{ +#ifndef QT_NO_REGEXP_CAPTURE + int atom = startAtom( yyMayCapture && yyTok == Tok_LeftParen ); +#else + static const int atom = 0; +#endif + +#ifndef QT_NO_REGEXP_INTERVAL +#define YYREDO() \ + yyIn = in, yyPos0 = pos0, yyPos = pos, yyLen = len, yyCh = ch, \ + *yyCharClass = charClass, yyMinRep = 0, yyMaxRep = 0, yyTok = tok + + const QChar *in = yyIn; + int pos0 = yyPos0; + int pos = yyPos; + int len = yyLen; + int ch = yyCh; + CharClass charClass; + if ( yyTok == Tok_CharClass ) + charClass = *yyCharClass; + int tok = yyTok; + bool mayCapture = yyMayCapture; +#endif + + parseAtom( box ); +#ifndef QT_NO_REGEXP_CAPTURE + finishAtom( atom ); +#endif + + if ( yyTok == Tok_Quantifier ) { + if ( yyMaxRep == InftyRep ) { + box->plus( atom ); +#ifndef QT_NO_REGEXP_INTERVAL + } else if ( yyMaxRep == 0 ) { + box->clear(); +#endif + } + if ( yyMinRep == 0 ) + box->opt(); + +#ifndef QT_NO_REGEXP_INTERVAL + yyMayCapture = FALSE; + int alpha = ( yyMinRep == 0 ) ? 0 : yyMinRep - 1; + int beta = ( yyMaxRep == InftyRep ) ? 0 : yyMaxRep - ( alpha + 1 ); + + Box rightBox( this ); + int i; + + for ( i = 0; i < beta; i++ ) { + YYREDO(); + Box leftBox( this ); + parseAtom( &leftBox ); + leftBox.cat( rightBox ); + leftBox.opt(); + rightBox = leftBox; + } + for ( i = 0; i < alpha; i++ ) { + YYREDO(); + Box leftBox( this ); + parseAtom( &leftBox ); + leftBox.cat( rightBox ); + rightBox = leftBox; + } + rightBox.cat( *box ); + *box = rightBox; +#endif + yyTok = getToken(); +#ifndef QT_NO_REGEXP_INTERVAL + yyMayCapture = mayCapture; +#endif + } +#undef YYREDO +} + +void QRegExpEngine::parseTerm( Box *box ) +{ +#ifndef QT_NO_REGEXP_OPTIM + if ( yyTok != Tok_Eos && yyTok != Tok_RightParen && yyTok != Tok_Bar ) + parseFactor( box ); +#endif + while ( yyTok != Tok_Eos && yyTok != Tok_RightParen && yyTok != Tok_Bar ) { + Box rightBox( this ); + parseFactor( &rightBox ); + box->cat( rightBox ); + } +} + +void QRegExpEngine::parseExpression( Box *box ) +{ + parseTerm( box ); + while ( yyTok == Tok_Bar ) { + Box rightBox( this ); + yyTok = getToken(); + parseTerm( &rightBox ); + box->orx( rightBox ); + } +} + +/* + The class QRegExpPrivate contains the private data of a regular expression + other than the automaton. It makes it possible for many QRegExp objects to + use the same QRegExpEngine object with different QRegExpPrivate objects. +*/ +struct QRegExpPrivate +{ + QString pattern; // regular-expression or wildcard pattern + QString rxpattern; // regular-expression pattern +#ifndef QT_NO_REGEXP_WILDCARD + bool wc; // wildcard mode? +#endif + bool min; // minimal matching? (instead of maximal) +#ifndef QT_NO_REGEXP_CAPTURE + QString t; // last string passed to QRegExp::search() or searchRev() + QStringList capturedCache; // what QRegExp::capturedTexts() returned last +#endif + QArray<int> captured; // what QRegExpEngine::search() returned last + + QRegExpPrivate() { captured.fill( -1, 2 ); } +}; + +#ifndef QT_NO_REGEXP_OPTIM +static QCache<QRegExpEngine> *engineCache = 0; +#endif + +static QRegExpEngine *newEngine( const QString& pattern, bool caseSensitive ) +{ +#ifndef QT_NO_REGEXP_OPTIM + if ( engineCache != 0 ) { + QRegExpEngine *eng = engineCache->take( pattern ); + if ( eng == 0 || eng->caseSensitive() != caseSensitive ) { + delete eng; + } else { + eng->ref(); + return eng; + } + } +#endif + return new QRegExpEngine( pattern, caseSensitive ); +} + +static void derefEngine( QRegExpEngine *eng, const QString& pattern ) +{ + if ( eng != 0 && eng->deref() ) { +#ifndef QT_NO_REGEXP_OPTIM + if ( engineCache == 0 ) { + engineCache = new QCache<QRegExpEngine>; + engineCache->setAutoDelete( TRUE ); + } + if ( !pattern.isNull() && + engineCache->insert(pattern, eng, 4 + pattern.length() / 4) ) + return; +#else + Q_UNUSED( pattern ); +#endif + delete eng; + } +} + +/*! + Constructs an empty regexp. + + \sa isValid() +*/ +QRegExp3::QRegExp3() +{ + eng = new QRegExpEngine( TRUE ); + priv = new QRegExpPrivate; + priv->pattern = QString::null; +#ifndef QT_NO_REGEXP_WILDCARD + priv->wc = FALSE; +#endif + priv->min = FALSE; + compile( TRUE ); +} + +/*! + Constructs a regular expression object for the given \a pattern + string. The pattern must be given using wildcard notation if \a + wildcard is TRUE (default is FALSE). The pattern is case sensitive, + unless \a caseSensitive is FALSE. Matching is greedy (maximal), but + can be changed by calling setMinimal(). + + \sa setPattern() setCaseSensitive() setWildcard() setMinimal() +*/ +QRegExp3::QRegExp3( const QString& pattern, bool caseSensitive, bool wildcard ) +{ + eng = 0; + priv = new QRegExpPrivate; + priv->pattern = pattern; +#ifndef QT_NO_REGEXP_WILDCARD + priv->wc = wildcard; +#endif + priv->min = FALSE; + compile( caseSensitive ); +} + +/*! + Constructs a regular expression as a copy of \a rx. + + \sa operator=() +*/ +QRegExp3::QRegExp3( const QRegExp3& rx ) +{ + eng = 0; + priv = new QRegExpPrivate; + operator=( rx ); +} + +/*! + Destroys the regular expression and cleans up its internal data. +*/ +QRegExp3::~QRegExp3() +{ + derefEngine( eng, priv->rxpattern ); + delete priv; +} + +/*! + Copies the regular expression \a rx and returns a reference to the copy. + The case sensitivity, wildcard and minimal matching options are copied as + well. +*/ +QRegExp3& QRegExp3::operator=( const QRegExp3& rx ) +{ + rx.eng->ref(); + derefEngine( eng, priv->rxpattern ); + eng = rx.eng; + priv->pattern = rx.priv->pattern; + priv->rxpattern = rx.priv->rxpattern; +#ifndef QT_NO_REGEXP_WILDCARD + priv->wc = rx.priv->wc; +#endif + priv->min = rx.priv->min; +#ifndef QT_NO_REGEXP_CAPTURE + priv->t = rx.priv->t; + priv->capturedCache = rx.priv->capturedCache; +#endif + priv->captured = rx.priv->captured; + return *this; +} + +/*! + Returns TRUE if this regular expression is equal to \a rx, otherwise + returns FALSE. + + Two QRegExp3 objects are equal if they have the same pattern strings + and the same settings for case sensitivity, wildcard and minimal + matching. +*/ +bool QRegExp3::operator==( const QRegExp3& rx ) const +{ + return priv->pattern == rx.priv->pattern && + eng->caseSensitive() == rx.eng->caseSensitive() && +#ifndef QT_NO_REGEXP_WILDCARD + priv->wc == rx.priv->wc && +#endif + priv->min == rx.priv->min; +} + +/*! \fn bool QRegExp3::operator!=( const QRegExp& rx ) const + + Returns TRUE if this regular expression is not equal to \a rx, otherwise + FALSE. + + \sa operator==() +*/ + +/*! + Returns TRUE if the pattern string is empty, otherwise FALSE. + + If you call match() with an empty pattern on an empty string it will + return TRUE otherwise it returns FALSE since match() operates over the + whole string. If you call search() with an empty pattern on \e any + string it will return the start position (0 by default) since it will + match at the start position, because the empty pattern matches the + 'emptiness' at the start of the string, and the length of the match + returned by matchedLength() will be 0. + + See QString::isEmpty(). +*/ + +bool QRegExp3::isEmpty() const +{ + return priv->pattern.isEmpty(); +} + +/*! + Returns TRUE if the regular expression is valid, or FALSE if it's invalid. An + invalid regular expression never matches. + + The pattern <b>[a-z</b> is an example of an invalid pattern, since it lacks + a closing square bracket. + + Note that the validity of a regexp may also depend on the setting of + the wildcard flag, for example <b>*.html</b> is a valid wildcard + regexp but an invalid full regexp. +*/ +bool QRegExp3::isValid() const +{ + return eng->isValid(); +} + +/*! + Returns the pattern string of the regular expression. The pattern has either + regular expression syntax or wildcard syntax, depending on wildcard(). + + \sa setPattern() +*/ +QString QRegExp3::pattern() const +{ + return priv->pattern; +} + +/*! + Sets the pattern string to \a pattern and returns a reference to this regular + expression. The case sensitivity, wildcard and minimal matching options are + not changed. + + \sa pattern() +*/ +void QRegExp3::setPattern( const QString& pattern ) +{ + if ( priv->pattern != pattern ) { + priv->pattern = pattern; + compile( caseSensitive() ); + } +} + +/*! + Returns TRUE if case sensitivity is enabled, otherwise FALSE. The default is + TRUE. + + \sa setCaseSensitive() +*/ +bool QRegExp3::caseSensitive() const +{ + return eng->caseSensitive(); +} + +/*! + Sets case sensitive matching to \a sensitive. + + If \a sensitive is TRUE, <b>\\</b><b>.txt$</b> matches + <tt>readme.txt</tt> but not <tt>README.TXT</tt>. + + \sa caseSensitive() +*/ +void QRegExp3::setCaseSensitive( bool sensitive ) +{ + if ( sensitive != eng->caseSensitive() ) + compile( sensitive ); +} + +#ifndef QT_NO_REGEXP_WILDCARD +/*! + Returns TRUE if wildcard mode is enabled, otherwise FALSE. The default is + FALSE. + + \sa setWildcard() +*/ +bool QRegExp3::wildcard() const +{ + return priv->wc; +} + +/*! Sets the wildcard mode for the regular expression. The default is FALSE. + + Setting \a wildcard to TRUE enables simple shell-like wildcard + matching. + (See <a href="#wildcard-matching">wildcard matching (globbing)</a>.) + + For example, <b>r*.txt</b> matches the string <tt>readme.txt</tt> in wildcard + mode, but does not match <tt>readme</tt>. + + \sa wildcard() +*/ +void QRegExp3::setWildcard( bool wildcard ) +{ + if ( wildcard != priv->wc ) { + priv->wc = wildcard; + compile( caseSensitive() ); + } +} +#endif + +/*! Returns TRUE if minimal (non-greedy) matching is enabled, otherwise + returns FALSE. + + \sa setMinimal() +*/ +bool QRegExp3::minimal() const +{ + return priv->min; +} + +/*! + Enables or disables minimal matching. If \a minimal is FALSE, matching is + greedy (maximal) which is the default. + + For example, suppose we have the input string "We must be \<b>bold\</b>, + very \<b>bold\</b>!" and the pattern <b>\<b>.*\</b></b>. With + the default greedy (maximal) matching, the match is + "We must be <u>\<b>bold\</b>, very \<b>bold\</b></u>!". But with + minimal (non-greedy) matching the first match is: + "We must be <u>\<b>bold\</b></u>, very \<b>bold\</b>!" and the + second match is + "We must be \<b>bold\</b>, very <u>\<b>bold\</b></u>!". + In practice we might use the pattern <b>\<b>[^\<]+\</b></b>, + although this will still fail for nested tags. + + \sa minimal() +*/ +void QRegExp3::setMinimal( bool minimal ) +{ + priv->min = minimal; +} + +/*! + Returns TRUE if \a str is matched exactly by this regular expression + otherwise it returns FALSE. You can determine how much of the string was + matched by calling matchedLength(). + + For a given regexp string, R, <tt>match("R")</tt> is the equivalent + of <tt>search("^R$")</tt> since match() effectively encloses the + regexp in the start of string and end of string anchors. + + For example, if the regular expression is <b>blue</b>, then match() + returns TRUE only for input <tt>blue</tt>. For inputs + <tt>bluebell</tt>, <tt>blutak</tt> and <tt>lightblue</tt>, match() + returns FALSE and matchedLength() will return 4, 3 and 0 respectively. + + \sa search() searchRev() QRegExpValidator +*/ +bool QRegExp3::exactMatch( const QString& str ) +{ +#ifndef QT_NO_REGEXP_CAPTURE + priv->t = str; + priv->capturedCache.clear(); +#endif + + priv->captured = eng->match( str, 0, priv->min, TRUE ); + if ( priv->captured[1] == (int) str.length() ) { + return TRUE; + } else { + priv->captured.detach(); + priv->captured[0] = 0; + priv->captured[1] = eng->matchedLength(); + return FALSE; + } +} + +/*! \overload + + This version does not set matchedLength(), capturedTexts() and friends. +*/ +bool QRegExp3::exactMatch( const QString& str ) const +{ + return eng->match(str, 0, priv->min, TRUE)[0] == 0 && + eng->matchedLength() == (int) str.length(); +} + +/*! \obsolete + + Attempts to match in \a str, starting from position \a index. Returns the + position of the match, or -1 if there was no match. + + The length of the match is stored in \a *len, unless \a len is a null pointer. + + If \a indexIsStart is TRUE (the default), the position \a index in the string + will match the start of string anchor, <b>^</b>, in the regexp, if present. + Otherwise, position 0 in \a str will match. + + Use search() and matchedLength() instead of this function. + + If you really need the \a indexIsStart functionality, try this: + + \code + QRegExp3 rx( "some pattern" ); + int pos = rx.search( str.mid( index ) ); + if ( pos != -1 ) + pos += index; + int len = rx.matchedLength(); + \endcode +*/ +#ifndef QT_NO_COMPAT +int QRegExp3::match( const QString& str, int index, int *len, + bool indexIsStart ) +{ + int pos; + if ( indexIsStart ) { + pos = search( str.mid(index) ); + if ( pos >= 0 ) { + pos += index; + if ( len != 0 ) + *len = matchedLength(); + } else { + if ( len != 0 ) + *len = 0; + } + } else { + pos = search( str, index ); + if ( len != 0 ) + *len = matchedLength(); + } + return pos; +} +#endif + +/*! + Attempts to find a match in \a str from position \a start (0 by default). If + \a start is -1, the search starts at the last character; if -2, at the next to + last character; etc. + + Returns the position of the first match, or -1 if there was no match. + + You might prefer to use QString::find(), QString::contains() or even + QStringList::grep(). To replace matches use QString::replace(). + + Example: + \code + QString str = "offsets: 1.23 .50 71.00 6.00"; + QRegExp3 rx( "\\d*\\.\\d+" ); // very simple floating point matching + int count = 0; + int pos = 0; + while ( pos >= 0 ) { + pos = rx.search( str, pos ); + count++; + } + // pos will be 9, 14, 18 and finally 24; count will end up as 4. + \endcode + + \sa searchRev() match() matchedLength() capturedTexts() +*/ +// QChar versions + +#ifdef QCHAR_SUPPORT +const QString makeString(const QChar *str) +{ +// A sentinel value checked in case the QChar *ptr is never null terminated + const uint MAXLENGTH=65535; + + const QChar *s=str; + uint i=0; + while(i < MAXLENGTH && *s != QChar::null) { i++;s++ ;} + return QString(str,i); + +} +int QRegExp3::search(const QChar *str,int start) +{ + return search(makeString(str),start); +} +int QRegExp3::search(const QChar *str,int start) const +{ + return search(makeString(str),start); +} +int QRegExp3::searchRev(const QChar *str,int start) +{ + return searchRev(makeString(str),start); +} +int QRegExp3::searchRev(const QChar *str,int start) const +{ + return searchRev(makeString(str),start); +} +bool QRegExp3::exactMatch(const QChar *str) +{ + return exactMatch(makeString(str)); +} +bool QRegExp3::exactMatch(const QChar *str) const +{ + return exactMatch(makeString(str)); +} +#endif // QCHAR_SUPPORT + +int QRegExp3::search( const QString& str, int start ) +{ + if ( start < 0 ) + start += str.length(); +#ifndef QT_NO_REGEXP_CAPTURE + priv->t = str; + priv->capturedCache.clear(); +#endif + priv->captured = eng->match( str, start, priv->min, FALSE ); + return priv->captured[0]; +} + +/*! \overload + + This version does not set matchedLength(), capturedTexts() and friends. +*/ +int QRegExp3::search( const QString& str, int start ) const +{ + if ( start < 0 ) + start += str.length(); + return eng->match( str, start, priv->min, FALSE )[0]; +} + +/*! + Attempts to find a match backwards in \a str from position \a start. If + \a start is -1 (the default), the search starts at the last character; if -2, + at the next to last character; etc. + + Returns the position of the first match, or -1 if there was no match. + + You might prefer to use QString::findRev(). + + \sa search() matchedLength() capturedTexts() +*/ +int QRegExp3::searchRev( const QString& str, int start ) +{ + if ( start < 0 ) + start += str.length(); +#ifndef QT_NO_REGEXP_CAPTURE + priv->t = str; + priv->capturedCache.clear(); +#endif + if ( start < 0 || start > (int) str.length() ) { + priv->captured.detach(); + priv->captured.fill( -1 ); + return -1; + } + + while ( start >= 0 ) { + priv->captured = eng->match( str, start, priv->min, TRUE ); + if ( priv->captured[0] == start ) + return start; + start--; + } + return -1; +} + +/*! \overload + + This version does not set matchedLength(), capturedText() and friends. +*/ +int QRegExp3::searchRev( const QString& str, int start ) const +{ + if ( start < 0 ) + start += str.length(); + if ( start < 0 || start > (int) str.length() ) + return -1; + + while ( start >= 0 ) { + if ( eng->match(str, start, priv->min, TRUE)[0] == start ) + return start; + start--; + } + return -1; +} + +/*! + Returns the length of the last matched string, or -1 if there was no match. + + \sa match() search() +*/ +int QRegExp3::matchedLength() +{ + return priv->captured[1]; +} + +#ifndef QT_NO_REGEXP_CAPTURE +/*! + Returns a list of the captured text strings. + + The first string in the list is the entire matched string. Each + subsequent list element contains a string that matched a + (capturing) subexpression of the regexp. + + For example: + \code + QRegExp3 rx( "(\\d+)(\\s*)(cm|inch(es)?)" ); + int pos = rx.search( "Length: 36 inches" ); + QStringList list = rx.capturedTexts(); + // list is now ( "36 inches", "36", " ", "inches", "es" ). + \endcode + + The above example also captures elements + that may be present but which we have no interest in. This problem + can be solved by using non-capturing parenthesis: + + \code + QRegExp3 rx( "(\\d+)(?:\\s*)(cm|inch(?:es)?)" ); + int pos = rx.search( "Length: 36 inches" ); + QStringList list = rx.capturedTexts(); + // list is now ( "36 inches", "36", "inches" ). + \endcode + + Some regexps can match an indeterminate number of times. For example + if the input string is "Offsets: 12 14 99 231 7" and the regexp, + <tt>rx</tt>, is <b>(</b><b>\\</b><b>d+)+</b>, we would hope to get a + list of all the numbers matched. However, after calling + <tt>rx.search(str)</tt>, capturedTexts() will return the list ( "12", + "12" ), i.e. the entire match was "12" and the first subexpression + matched was "12". The correct approach is to use cap() in a + <a href="#cap_in_a_loop">loop</a>. + + The order of elements in the string list is as follows. The first + element is the entire matching string. Each subsequent element + corresponds to the next capturing open left parenthesis. Thus + capturedTexts()[1] is the text of the first capturing parenthesis, + capturedTexts()[2] is the text of the second and so on (corresponding + to $1, $2 etc. in some other regexp languages). + + \sa cap() pos() +*/ +QStringList QRegExp3::capturedTexts() +{ + if ( priv->capturedCache.isEmpty() ) { + for ( int i = 0; i < (int) priv->captured.size(); i += 2 ) { + QString m; + if ( priv->captured[i + 1] == 0 ) + m = QString::fromLatin1( "" ); + else if ( priv->captured[i] >= 0 ) + m = priv->t.mid( priv->captured[i], + priv->captured[i + 1] ); + priv->capturedCache.append( m ); + } + priv->t = QString::null; + } + return priv->capturedCache; +} + +/*! Returns the text captured by the \a nth subexpression. The entire match + has index 0 and the parenthesised subexpressions have indices starting + from 1 (excluding non-capturing parenthesis). + + \code + QRegExp3 rxlen( "(\\d+)(?:\\s*)(cm|inch)" ); + int pos = rxlen.search( "Length: 189cm" ); + if ( pos > -1 ) { + QString value = rxlen.cap( 1 ); // "189" + QString unit = rxlen.cap( 2 ); // "cm" + // ... + } + \endcode + + <a name="cap_in_a_loop"> + Some patterns may lead to a number of matches which cannot be + determined in advance, for example:</a> + + \code + QRegExp3 rx( "(\\d+)" ); + str = "Offsets: 12 14 99 231 7"; + QStringList list; + pos = 0; + while ( pos >= 0 ) { + pos = rx.search( str, pos ); + if ( pos > -1 ) { + list += rx.cap( 1 ); + pos += rx.matchedLength(); + } + } + // list contains: ( "12", "14", "99", "231", "7" ). + \endcode + + The order of elements matched by cap() is as follows. The first + element, cap( 0 ), is the entire matching string. Each subsequent + element corresponds to the next capturing open left parenthesis. Thus + cap( 1 ) is the text of the first capturing parenthesis, cap( 2 ) is + the text of the second and so on. + + \sa search() pos() capturedTexts() +*/ +QString QRegExp3::cap( int nth ) +{ + if ( nth < 0 || nth >= (int) priv->captured.size() / 2 ) + return QString::null; + else + return capturedTexts()[nth]; +} + +/*! Returns the position of the \a nth captured text in the + searched string. If \a nth is 0 (the default), pos() returns the + position of the whole match. + + Example: + \code + QRegExp3 rx( "/([a-z]+)/([a-z]+)" ); + rx.search( "Output /dev/null" ); // Returns 7 (position of /dev/null) + rx.pos( 0 ); // Returns 7 (position of /dev/null) + rx.pos( 1 ); // Returns 8 (position of dev) + rx.pos( 2 ); // Returns 12 (position of null) + \endcode + + Note that pos() returns -1 for zero-length matches. (For example, if + cap(4) would return an empty string, pos(4) returns -1.) This is due + to an implementation tradeoff. + + \sa capturedTexts() cap() +*/ +int QRegExp3::pos( int nth ) +{ + if ( nth < 0 || nth >= (int) priv->captured.size() / 2 ) + return -1; + else + return priv->captured[2 * nth]; +} +#endif + +void QRegExp3::compile( bool caseSensitive ) +{ + derefEngine( eng, priv->rxpattern ); +#ifndef QT_NO_REGEXP_WILDCARD + if ( priv->wc ) + priv->rxpattern = wc2rx( priv->pattern ); + else +#endif + priv->rxpattern = priv->pattern.isNull() ? QString::fromLatin1( "" ) + : priv->pattern; + eng = newEngine( priv->rxpattern, caseSensitive ); +#ifndef QT_NO_REGEXP_CAPTURE + priv->t = QString::null; + priv->capturedCache.clear(); +#endif + priv->captured.detach(); + priv->captured.fill( -1, 2 + 2 * eng->numCaptures() ); +} diff --git a/noncore/apps/tinykate/libkate/qt3back/qregexp3.h b/noncore/apps/tinykate/libkate/qt3back/qregexp3.h new file mode 100644 index 0000000..5b75131 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/qt3back/qregexp3.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** $Id$ +** +** Definition of QRegExp class +** +** Created : 950126 +** +** Copyright (C) 1992-2000 Trolltech AS. All rights reserved. +** +** This file is part of the tools module of the Qt GUI Toolkit. +** +** This file may be distributed under the terms of the Q Public License +** as defined by Trolltech AS of Norway and appearing in the file +** LICENSE.QPL included in the packaging of this file. +** +** This file may be distributed and/or modified under the terms of the +** GNU General Public License version 2 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. +** +** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition +** licenses may use this file in accordance with the Qt Commercial License +** Agreement provided with the Software. +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for +** information about Qt Commercial License Agreements. +** See http://www.trolltech.com/qpl/ for QPL licensing information. +** See http://www.trolltech.com/gpl/ for GPL licensing information. +** +** Contact info@trolltech.com if any conditions of this licensing are +** not clear to you. +** +**********************************************************************/ + +#ifndef QREGEXP3_H +#define QREGEXP3_H +#ifndef QT_H +#include "qstringlist.h" +#endif // QT_H + + +#if QT_VERSION >=300 +#include <qregexp.h> +#else +class QRegExpEngine; +struct QRegExpPrivate; + +class Q_EXPORT QRegExp3 +{ +public: + QRegExp3(); + QRegExp3( const QString& pattern, bool caseSensitive = TRUE, + bool wildcard = FALSE ); + QRegExp3( const QRegExp3& rx ); + ~QRegExp3(); + QRegExp3& operator=( const QRegExp3& rx ); + + bool operator==( const QRegExp3& rx ) const; + bool operator!=( const QRegExp3& rx ) const { return !operator==( rx ); } + + bool isEmpty() const; + bool isValid() const; + QString pattern() const; + void setPattern( const QString& pattern ); + bool caseSensitive() const; + void setCaseSensitive( bool sensitive ); +#ifndef QT_NO_REGEXP_WILDCARD + bool wildcard() const; + void setWildcard( bool wildcard ); +#endif + bool minimal() const; + void setMinimal( bool minimal ); + + bool exactMatch( const QString& str ); + bool exactMatch( const QString& str ) const; +#ifndef QT_NO_COMPAT + int match( const QString& str, int index, int *len = 0, + bool indexIsStart = TRUE ); +#endif + int search( const QString& str, int start = 0 ); + int search( const QString& str, int start = 0 ) const; +// QChar versions +#ifdef QCHAR_SUPPORT + int search(const QChar *str,int start=0); + int search(const QChar *str,int start=0) const; + int searchRev(const QChar *str,int start=-1); + int searchRev(const QChar *str,int start=-1) const ; + bool exactMatch(const QChar *str); + bool exactMatch(const QChar *str) const; +// end QChar versions +#endif + int searchRev( const QString& str, int start = -1 ); + int searchRev( const QString& str, int start = -1 ) const; + int matchedLength(); +#ifndef QT_NO_REGEXP_CAPTURE + QStringList capturedTexts(); + QString cap( int nth = 0 ); + int pos( int nth = 0 ); +#endif + +private: + void compile( bool caseSensitive ); + + QRegExpEngine *eng; + QRegExpPrivate *priv; +}; +#endif // QT_VERSION >= 300 +#endif // QREGEXP_H diff --git a/noncore/apps/tinykate/libkate/view/kateundohistory.cpp b/noncore/apps/tinykate/libkate/view/kateundohistory.cpp new file mode 100644 index 0000000..b7b9b56 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/view/kateundohistory.cpp @@ -0,0 +1,271 @@ +/* + Copyright (C) 1999 Glen Parker <glenebob@nwlink.com> + 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 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. + + -------------------------------------------------------------------- + + This implements a dialog used to display and control undo/redo history. + It uses a specialized QListBox subclass to provide a selection mechanism + that must: + 1) always have the first item selected, and + 2) maintain a contiguous multiple selection +*/ + +#include <stdio.h> + +#include <qwidget.h> +#include <qdialog.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qlistbox.h> +#include <qpushbutton.h> + +#include <klocale.h> + +#include "kateview.h" + +#include "kateundohistory.h" + +///////////////////////////////////////////////////////////////////// +// UndoHistory implementation +// +UndoHistory::UndoHistory(KateView *kWrite, QWidget *parent, const char *name, bool modal, WFlags f) + : QDialog(parent, name, modal, f) +{ + this->kWrite = kWrite; + + QPushButton *btn; + QLabel *lbl; + QHBoxLayout *hLayout; + QVBoxLayout *vLayout; + + hLayout = new QHBoxLayout(this, 5, 4); + + vLayout = new QVBoxLayout(hLayout); + lbl = new QLabel(i18n("Undo List"), this); + lbUndo = new UndoListBox(this); + vLayout->addWidget(lbl); + vLayout->addWidget(lbUndo); + + vLayout = new QVBoxLayout(hLayout); + lbl = new QLabel(i18n("Redo List"), this); + lbRedo = new UndoListBox(this); + vLayout->addWidget(lbl); + vLayout->addWidget(lbRedo); + + lbUndo->setMinimumSize(QSize(150,140)); + lbRedo->setMinimumSize(QSize(150,140)); + + connect(lbUndo, SIGNAL(sigSelected(int)), this, SLOT(slotUndoSelChanged(int))); + connect(lbRedo, SIGNAL(sigSelected(int)), this, SLOT(slotRedoSelChanged(int))); + + vLayout = new QVBoxLayout(hLayout); + + btnUndo = new QPushButton(this); + btnUndo->setText(i18n("&Undo")); + btnUndo->setEnabled(false); + btnUndo->setFixedSize(btnUndo->sizeHint()); + connect(btnUndo, SIGNAL(clicked()), this, SLOT(slotUndo())); + + vLayout->addWidget(btnUndo, 0); + + btnRedo = new QPushButton(this); + btnRedo->setText(i18n("&Redo")); + btnRedo->setEnabled(false); + btnRedo->setFixedSize(btnRedo->sizeHint()); + connect(btnRedo, SIGNAL(clicked()), this, SLOT(slotRedo())); + + vLayout->addWidget(btnRedo, 0); + + btn = new QPushButton(this); + btn->setText(i18n("&Close")); + btn->setFixedSize(btn->sizeHint()); + connect(btn, SIGNAL(clicked()), this, SLOT(close())); + + vLayout->addWidget(btn, 0, AlignBottom); + + newUndo(); +} + +UndoHistory::~UndoHistory() +{} + +void UndoHistory::newUndo() +{ + QValueList<int> undoList; + QValueList<int>::Iterator it; + + // we don't want a signal storm... + disconnect(lbUndo, SIGNAL(sigSelected(int)), this, SLOT(slotUndoSelChanged(int))); + disconnect(lbRedo, SIGNAL(sigSelected(int)), this, SLOT(slotRedoSelChanged(int))); + + kWrite->undoTypeList(undoList); + + lbUndo->clear(); + + for (it = undoList.begin() ; it != undoList.end() ; it++) { + lbUndo->insertItem(i18n(kWrite->undoTypeName(*it))); + } + + kWrite->redoTypeList(undoList); + + lbRedo->clear(); + for (it = undoList.begin() ; it != undoList.end() ; it++) { + lbRedo->insertItem(i18n(kWrite->undoTypeName(*it))); + } + + connect(lbUndo, SIGNAL(sigSelected(int)), this, SLOT(slotUndoSelChanged(int))); + connect(lbRedo, SIGNAL(sigSelected(int)), this, SLOT(slotRedoSelChanged(int))); + + slotUndoSelChanged(lbUndo->selCount()); + slotRedoSelChanged(lbRedo->selCount()); +} + +void UndoHistory::slotUndo() +{ + int selCount = lbUndo->selCount(); + emit undo(selCount); + lbRedo->setSelCount(selCount); +} +void UndoHistory::slotRedo() +{ + int selCount = lbRedo->selCount(); + emit redo(selCount); + lbUndo->setSelCount(selCount); +} + +void UndoHistory::slotUndoSelChanged(int cnt) +{ + btnUndo->setEnabled(cnt > 0); +} + +void UndoHistory::slotRedoSelChanged(int cnt) +{ + btnRedo->setEnabled(cnt > 0); +} + +///////////////////////////////////////////////////////////////////// +// UndoListBox implementation +// +UndoListBox::UndoListBox(QWidget *parent, const char *name, WFlags f) + : QListBox(parent, name, f) +{ + _selCount = 0; + setSelectionMode(Extended); + connect(this, SIGNAL(highlighted(int)), this, SLOT(_slotSelectionChanged())); + connect(this, SIGNAL(selectionChanged()), this, SLOT(_slotSelectionChanged())); +} + +UndoListBox::~UndoListBox() +{} + +void UndoListBox::insertItem (const QString &text, int index) +{ + bool sig = false; + + if (count() == 0) + sig = true; + else if (index > -1) + sig = (isSelected(index)); + + QListBox::insertItem(text, index); + + if (sig) + _slotSelectionChanged(); +} + +void UndoListBox::removeItem (int index) +{ + bool sig; + + if (count() == 1) + sig = true; + else if (index == -1) + sig = (isSelected(count() - 1)); + else + sig = (isSelected(index)); + + QListBox::removeItem(index); + + if (sig) + _slotSelectionChanged(); +} + +void UndoListBox::clear() +{ + bool sig = (count() > 0); + + QListBox::clear(); + + if (sig) + _slotSelectionChanged(); +} + +int UndoListBox::selCount() +{ + return _selCount; +} + +void UndoListBox::setSelCount(int count) +{ + if (count == _selCount) + return; + + if (count < 1 || count > (int)this->count()) + return; + + setCurrentItem(count - 1); +} + +// make sure the first item is selected, and that there are no holes +void UndoListBox::_slotSelectionChanged() +{ + int count = this->count(); + + if (! count) { + if (_selCount != 0) { + _selCount = 0; + emit sigSelected(_selCount); + } + return; + } + + if (currentItem() < 0) + setCurrentItem(0); + + int i; + int currItem = currentItem(); + int max = (currItem+1 > _selCount ? currItem+1 : _selCount); + + for (i = 0 ; i < max ; i++) { + if (i > currItem) { + if (isSelected(i)) { + setSelected(i, false); + } + } else { + if (! isSelected(i)) { + setSelected(i, true); + } + } + } + + if (_selCount != currItem + 1) { + _selCount = currItem + 1; + emit sigSelected(_selCount); + } +} diff --git a/noncore/apps/tinykate/libkate/view/kateundohistory.h b/noncore/apps/tinykate/libkate/view/kateundohistory.h new file mode 100644 index 0000000..eb91af9 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/view/kateundohistory.h @@ -0,0 +1,114 @@ +/* + Copyright (C) 1999 Glen Parker <glenebob@nwlink.com> + 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 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. + + -------------------------------------------------------------------- + + This implements a dialog used to display and control undo/redo history. + It uses a specialized QListBox subclass to provide a selection mechanism + that will: + 1) always have the first item selected, and + 2) maintain a contiguous multiple selection +*/ + +#ifndef __undohistory_h_ +#define __undohistory_h_ + +#include <qdialog.h> +#include <qlistbox.h> + +#include "kateview.h" + +class UndoListBox; + +// the dialog class that provides the interface to the user +class UndoHistory : public QDialog +{ + Q_OBJECT + + public: + /** + Constructed just like a regular QDialog + */ + UndoHistory(KateView*, QWidget *parent=0, const char *name=0, bool modal=FALSE, WFlags f=0); + virtual ~UndoHistory(); + + public slots: + /** + This should be called whenever a change occurs in the undo/redo list. + Causes the dialog to update its interface. + */ + void newUndo(); + + signals: + /** + Emitted when the user hits the Undo button. Specifies the number of + operations to undo. + */ + void undo(int); + /** + Emitted when the user hits the Redo button. Specifies the number of + undone operations to redo. + */ + void redo(int); + + protected: + KateView *kWrite; + + UndoListBox *lbUndo, + *lbRedo; + QPushButton *btnUndo, + *btnRedo; + + protected slots: + void slotUndo(); + void slotRedo(); + void slotUndoSelChanged(int); + void slotRedoSelChanged(int); + +}; + +// listbox class used to provide contiguous, 0-based selection +// this is used internally +class UndoListBox : public QListBox +{ + Q_OBJECT + + public: + UndoListBox(QWidget * parent=0, const char * name=0, WFlags f=0); + virtual ~UndoListBox(); + + int selCount(); + void setSelCount(int count); + + void insertItem (const QString &text, int index = -1); + void removeItem (int index); + void clear(); + + protected: + int _selCount; + + signals: + void sigSelected(int); + + protected slots: + void _slotSelectionChanged(); + +}; + +#endif diff --git a/noncore/apps/tinykate/libkate/view/kateview.cpp b/noncore/apps/tinykate/libkate/view/kateview.cpp new file mode 100644 index 0000000..8f3a25e --- a/dev/null +++ b/noncore/apps/tinykate/libkate/view/kateview.cpp @@ -0,0 +1,2923 @@ +/*************************************************************************** + kateview.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 "kateview.h" + +#include "../document/katedocument.h" +#include "../document/katecmd.h" +#include "../document/katehighlight.h" +#include "kateviewdialog.h" +#include "../document/katedialogs.h" + +#include <qfocusdata.h> +#include <kdebug.h> +#include <kapplication.h> +#include <qscrollbar.h> +#include <qiodevice.h> +#include <qpopupmenu.h> +#include <kpopupmenu.h> +#include <qkeycode.h> +#include <qintdict.h> +#include <kconfig.h> +#include <qfont.h> +#include <qpainter.h> +#include <qpixmap.h> +#include <qfileinfo.h> +#include <qfile.h> +#include <qevent.h> +#include <qdir.h> +#include <qvbox.h> +#include <qprintdialog.h> +#include <qpaintdevicemetrics.h> +#include <qiodevice.h> +#include <qbuffer.h> +#include <qfocusdata.h> +#include <klocale.h> +#include <kglobal.h> +#include <kdebug.h> +#include <kmessagebox.h> +#include <qregexp.h> +#include <kdialogbase.h> +#include <klineeditdlg.h> +#include <qapplication.h> +#include <kfiledialog.h> +#include <kiconloader.h> +#include "../document/katetextline.h" +#include "kateviewdialog.h" +#include "kateundohistory.h" +#include <qlayout.h> + +KateViewInternal::KateViewInternal(KateView *view, KateDocument *doc) : QWidget(view) +{ + waitForPreHighlight=-1; + myView = view; + myDoc = doc; + + iconBorderWidth = 16; + iconBorderHeight = 800; + + QWidget::setCursor(ibeamCursor); + setBackgroundMode(NoBackground); + + setFocusPolicy(StrongFocus); + + xScroll = new QScrollBar(QScrollBar::Horizontal,myView); + yScroll = new QScrollBar(QScrollBar::Vertical,myView); + connect(xScroll,SIGNAL(valueChanged(int)),SLOT(changeXPos(int))); + connect(yScroll,SIGNAL(valueChanged(int)),SLOT(changeYPos(int))); + connect(yScroll,SIGNAL(valueChanged(int)),myView,SIGNAL(scrollValueChanged(int))); + connect( doc, SIGNAL (preHighlightChanged(long)),this,SLOT(slotPreHighlightUpdate(long))); + + xPos = 0; + yPos = 0; + + scrollTimer = 0; + + cursor.x = 0; + cursor.y = 0; + cursorOn = false; + cursorTimer = 0; + cXPos = 0; + cOldXPos = 0; + + startLine = 0; + endLine = -1; + + exposeCursor = false; + updateState = 0; + numLines = 0; + lineRanges = 0L; + newXPos = -1; + newYPos = -1; + + drawBuffer = new QPixmap (); + drawBuffer->setOptimization (QPixmap::BestOptim); + + bm.sXPos = 0; + bm.eXPos = -1; + +} + + +KateViewInternal::~KateViewInternal() +{ + delete [] lineRanges; + delete drawBuffer; +} + + +void KateViewInternal::slotPreHighlightUpdate(long line) +{ + //kdDebug()<<QString("slotPreHighlightUpdate - Wait for: %1, line: %2").arg(waitForPreHighlight).arg(line)<<endl; + if (waitForPreHighlight!=-1) + { + if (line>=waitForPreHighlight) + { + waitForPreHighlight=-1; + repaint(); + } + } +} + +void KateViewInternal::doCursorCommand(VConfig &c, int cmdNum) { + + switch (cmdNum) { + case KateView::cmLeft: + cursorLeft(c); + break; + case KateView::cmRight: + cursorRight(c); + break; + case KateView::cmWordLeft: + wordLeft(c); + break; + case KateView::cmWordRight: + wordRight(c); + break; + case KateView::cmHome: + home(c); + break; + case KateView::cmEnd: + end(c); + break; + case KateView::cmUp: + cursorUp(c); + break; + case KateView::cmDown: + cursorDown(c); + break; + case KateView::cmScrollUp: + scrollUp(c); + break; + case KateView::cmScrollDown: + scrollDown(c); + break; + case KateView::cmTopOfView: + topOfView(c); + break; + case KateView::cmBottomOfView: + bottomOfView(c); + break; + case KateView::cmPageUp: + pageUp(c); + break; + case KateView::cmPageDown: + pageDown(c); + break; + case KateView::cmTop: + top_home(c); + break; + case KateView::cmBottom: + bottom_end(c); + break; + } +} + +void KateViewInternal::doEditCommand(VConfig &c, int cmdNum) { + + switch (cmdNum) { + case KateView::cmCopy: + myDoc->copy(c.flags); + return; + case KateView::cmSelectAll: + myDoc->selectAll(); + return; + case KateView::cmDeselectAll: + myDoc->deselectAll(); + return; + case KateView::cmInvertSelection: + myDoc->invertSelection(); + return; + } + if (myView->isReadOnly()) return; + switch (cmdNum) { + case KateView::cmReturn: + if (c.flags & KateView::cfDelOnInput) myDoc->delMarkedText(c); + myDoc->newLine(c); + //emit returnPressed(); + //e->ignore(); + return; + case KateView::cmDelete: + if ((c.flags & KateView::cfDelOnInput) && myDoc->hasMarkedText()) + myDoc->delMarkedText(c); + else myDoc->del(c); + return; + case KateView::cmBackspace: + if ((c.flags & KateView::cfDelOnInput) && myDoc->hasMarkedText()) + myDoc->delMarkedText(c); + else myDoc->backspace(c); + return; + case KateView::cmKillLine: + myDoc->killLine(c); + return; + case KateView::cmCut: + myDoc->cut(c); + return; + case KateView::cmPaste: + if (c.flags & KateView::cfDelOnInput) myDoc->delMarkedText(c); + myDoc->paste(c); + return; + case KateView::cmUndo: + myDoc->undo(c); + return; + case KateView::cmRedo: + myDoc->redo(c); + return; + case KateView::cmIndent: + myDoc->indent(c); + return; + case KateView::cmUnindent: + myDoc->unIndent(c); + return; + case KateView::cmCleanIndent: + myDoc->cleanIndent(c); + return; + case KateView::cmComment: + myDoc->comment(c); + return; + case KateView::cmUncomment: + myDoc->unComment(c); + return; + } +} + +void KateViewInternal::cursorLeft(VConfig &c) { + + cursor.x--; + if (c.flags & KateView::cfWrapCursor && cursor.x < 0 && cursor.y > 0) { + cursor.y--; + cursor.x = myDoc->textLength(cursor.y); + } + cOldXPos = cXPos = myDoc->textWidth(cursor); + changeState(c); +} + +void KateViewInternal::cursorRight(VConfig &c) { + + if (c.flags & KateView::cfWrapCursor) { + if (cursor.x >= myDoc->textLength(cursor.y)) { + if (cursor.y == myDoc->lastLine()) return; + cursor.y++; + cursor.x = -1; + } + } + cursor.x++; + cOldXPos = cXPos = myDoc->textWidth(cursor); + changeState(c); +} + +void KateViewInternal::wordLeft(VConfig &c) { + Highlight *highlight; + + highlight = myDoc->highlight(); + TextLine::Ptr textLine = myDoc->getTextLine(cursor.y); + + if (cursor.x > 0) { + do { + cursor.x--; + } while (cursor.x > 0 && !highlight->isInWord(textLine->getChar(cursor.x))); + while (cursor.x > 0 && highlight->isInWord(textLine->getChar(cursor.x -1))) + cursor.x--; + } else { + if (cursor.y > 0) { + cursor.y--; + textLine = myDoc->getTextLine(cursor.y); + cursor.x = textLine->length(); + } + } + + cOldXPos = cXPos = myDoc->textWidth(cursor); + changeState(c); +} + +void KateViewInternal::wordRight(VConfig &c) { + Highlight *highlight; + int len; + + highlight = myDoc->highlight(); + TextLine::Ptr textLine = myDoc->getTextLine(cursor.y); + len = textLine->length(); + + if (cursor.x < len) { + do { + cursor.x++; + } while (cursor.x < len && highlight->isInWord(textLine->getChar(cursor.x))); + while (cursor.x < len && !highlight->isInWord(textLine->getChar(cursor.x))) + cursor.x++; + } else { + if (cursor.y < myDoc->lastLine()) { + cursor.y++; + textLine = myDoc->getTextLine(cursor.y); + cursor.x = 0; + } + } + + cOldXPos = cXPos = myDoc->textWidth(cursor); + changeState(c); +} + +void KateViewInternal::home(VConfig &c) { + int lc; + + lc = (c.flags & KateView::cfSmartHome) ? myDoc->getTextLine(cursor.y)->firstChar() : 0; + if (lc <= 0 || cursor.x == lc) { + cursor.x = 0; + cOldXPos = cXPos = 0; + } else { + cursor.x = lc; + cOldXPos = cXPos = myDoc->textWidth(cursor); + } + + changeState(c); +} + +void KateViewInternal::end(VConfig &c) { + cursor.x = myDoc->textLength(cursor.y); + cOldXPos = cXPos = myDoc->textWidth(cursor); + changeState(c); +} + + +void KateViewInternal::cursorUp(VConfig &c) { + + cursor.y--; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor,cursor,cOldXPos); + changeState(c); +} + + +void KateViewInternal::cursorDown(VConfig &c) { + int x; + + if (cursor.y == myDoc->lastLine()) { + x = myDoc->textLength(cursor.y); + if (cursor.x >= x) return; + cursor.x = x; + cXPos = myDoc->textWidth(cursor); + } else { + cursor.y++; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor, cursor, cOldXPos); + } + changeState(c); +} + +void KateViewInternal::scrollUp(VConfig &c) { + + if (! yPos) return; + + newYPos = yPos - myDoc->fontHeight; + if (cursor.y == (yPos + height())/myDoc->fontHeight -1) { + cursor.y--; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor,cursor,cOldXPos); + + changeState(c); + } +} + +void KateViewInternal::scrollDown(VConfig &c) { + + if (endLine >= myDoc->lastLine()) return; + + newYPos = yPos + myDoc->fontHeight; + if (cursor.y == (yPos + myDoc->fontHeight -1)/myDoc->fontHeight) { + cursor.y++; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor,cursor,cOldXPos); + changeState(c); + } +} + +void KateViewInternal::topOfView(VConfig &c) { + + cursor.y = (yPos + myDoc->fontHeight -1)/myDoc->fontHeight; + cursor.x = 0; + cOldXPos = cXPos = 0; + changeState(c); +} + +void KateViewInternal::bottomOfView(VConfig &c) { + + cursor.y = (yPos + height())/myDoc->fontHeight -1; + if (cursor.y < 0) cursor.y = 0; + if (cursor.y > myDoc->lastLine()) cursor.y = myDoc->lastLine(); + cursor.x = 0; + cOldXPos = cXPos = 0; + changeState(c); +} + +void KateViewInternal::pageUp(VConfig &c) { + int lines = (endLine - startLine - 1); + + if (lines <= 0) lines = 1; + + if (!(c.flags & KateView::cfPageUDMovesCursor) && yPos > 0) { + newYPos = yPos - lines * myDoc->fontHeight; + if (newYPos < 0) newYPos = 0; + } + cursor.y -= lines; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor, cursor, cOldXPos); + changeState(c); +// cursorPageUp(c); +} + +void KateViewInternal::pageDown(VConfig &c) { + + int lines = (endLine - startLine - 1); + + if (!(c.flags & KateView::cfPageUDMovesCursor) && endLine < myDoc->lastLine()) { + if (lines < myDoc->lastLine() - endLine) + newYPos = yPos + lines * myDoc->fontHeight; + else + newYPos = yPos + (myDoc->lastLine() - endLine) * myDoc->fontHeight; + } + cursor.y += lines; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor,cursor,cOldXPos); + changeState(c); +// cursorPageDown(c); +} + +// go to the top, same X position +void KateViewInternal::top(VConfig &c) { + +// cursor.x = 0; + cursor.y = 0; + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor,cursor,cOldXPos); +// cOldXPos = cXPos = 0; + changeState(c); +} + +// go to the bottom, same X position +void KateViewInternal::bottom(VConfig &c) { + +// cursor.x = 0; + cursor.y = myDoc->lastLine(); + cXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor,cursor,cOldXPos); +// cOldXPos = cXPos = 0; + changeState(c); +} + +// go to the top left corner +void KateViewInternal::top_home(VConfig &c) +{ + cursor.y = 0; + cursor.x = 0; + cOldXPos = cXPos = 0; + changeState(c); +} + +// go to the bottom right corner +void KateViewInternal::bottom_end(VConfig &c) { + + cursor.y = myDoc->lastLine(); + cursor.x = myDoc->textLength(cursor.y); + cOldXPos = cXPos = myDoc->textWidth(cursor); + changeState(c); +} + + +void KateViewInternal::changeXPos(int p) { + int dx; + + dx = xPos - p; + xPos = p; + if (QABS(dx) < width()) scroll(dx, 0); else update(); +} + +void KateViewInternal::changeYPos(int p) { + int dy; + + dy = yPos - p; + yPos = p; + clearDirtyCache(height()); + + if (QABS(dy) < height()) + { + scroll(0, dy); + leftBorder->scroll(0, dy); + } + else + update(); +} + + +void KateViewInternal::getVConfig(VConfig &c) { + + c.view = myView; + c.cursor = cursor; + c.cXPos = cXPos; + c.flags = myView->configFlags; +} + +void KateViewInternal::changeState(VConfig &c) { + /* + * we need to be sure to kill the selection on an attempted cursor + * movement even if the cursor doesn't physically move, + * but we need to be careful not to do some other things in this case, + * like we don't want to expose the cursor + */ + +// if (cursor.x == c.cursor.x && cursor.y == c.cursor.y) return; + bool nullMove = (cursor.x == c.cursor.x && cursor.y == c.cursor.y); + +// if (cursor.y != c.cursor.y || c.flags & KateView::cfMark) myDoc->recordReset(); + + if (! nullMove) { + + exposeCursor = true; + + // mark old position of cursor as dirty + if (cursorOn) { + tagLines(c.cursor.y, c.cursor.y, c.cXPos -2, c.cXPos +3); + cursorOn = false; + } + + // mark old bracket mark position as dirty + if (bm.sXPos < bm.eXPos) { + tagLines(bm.cursor.y, bm.cursor.y, bm.sXPos, bm.eXPos); + } + // make new bracket mark + myDoc->newBracketMark(cursor, bm); + + // remove trailing spaces when leaving a line + if (c.flags & KateView::cfRemoveSpaces && cursor.y != c.cursor.y) { + TextLine::Ptr textLine = myDoc->getTextLine(c.cursor.y); + int newLen = textLine->lastChar(); + if (newLen != textLine->length()) { + textLine->truncate(newLen); + // if some spaces are removed, tag the line as dirty + myDoc->tagLines(c.cursor.y, c.cursor.y); + } + } + } + + if (c.flags & KateView::cfMark) { + if (! nullMove) + myDoc->selectTo(c, cursor, cXPos); + } else { + if (!(c.flags & KateView::cfPersistent)) + myDoc->deselectAll(); + } +} + +void KateViewInternal::insLine(int line) { + + if (line <= cursor.y) { + cursor.y++; + } + if (line < startLine) { + startLine++; + endLine++; + yPos += myDoc->fontHeight; + } else if (line <= endLine) { + tagAll(); + } +} + +void KateViewInternal::delLine(int line) { + + if (line <= cursor.y && cursor.y > 0) { + cursor.y--; + } + if (line < startLine) { + startLine--; + endLine--; + yPos -= myDoc->fontHeight; + } else if (line <= endLine) { + tagAll(); + } +} + +void KateViewInternal::updateCursor() { + cOldXPos = cXPos = myDoc->textWidth(cursor); +} + + +void KateViewInternal::updateCursor(PointStruc &newCursor) { + updateCursor(newCursor, myView->config()); +} + +void KateViewInternal::updateCursor(PointStruc &newCursor, int flags) { + + if (!(flags & KateView::cfPersistent)) myDoc->deselectAll(); + + exposeCursor = true; + if (cursorOn) { + tagLines(cursor.y, cursor.y, cXPos -2, cXPos +3); + cursorOn = false; + } + + if (bm.sXPos < bm.eXPos) { + tagLines(bm.cursor.y, bm.cursor.y, bm.sXPos, bm.eXPos); + } + myDoc->newBracketMark(newCursor, bm); + + cursor = newCursor; + cOldXPos = cXPos = myDoc->textWidth(cursor); +} + +// init the line dirty cache +void KateViewInternal::clearDirtyCache(int height) { + int lines, z; + + // calc start and end line of visible part + startLine = yPos/myDoc->fontHeight; + endLine = (yPos + height -1)/myDoc->fontHeight; + + updateState = 0; + + lines = endLine - startLine +1; + if (lines > numLines) { // resize the dirty cache + numLines = lines*2; + delete [] lineRanges; + lineRanges = new LineRange[numLines]; + } + + for (z = 0; z < lines; z++) { // clear all lines + lineRanges[z].start = 0xffffff; + lineRanges[z].end = -2; + } + newXPos = newYPos = -1; +} + +void KateViewInternal::tagLines(int start, int end, int x1, int x2) { + LineRange *r; + int z; + + start -= startLine; + if (start < 0) start = 0; + end -= startLine; + if (end > endLine - startLine) end = endLine - startLine; + + if (x1 <= 0) x1 = -2; + if (x1 < xPos-2) x1 = xPos-2; + if (x2 > width() + xPos-2) x2 = width() + xPos-2; + if (x1 >= x2) return; + + r = &lineRanges[start]; + for (z = start; z <= end; z++) { + if (x1 < r->start) r->start = x1; + if (x2 > r->end) r->end = x2; + r++; + updateState |= 1; + } +} + +void KateViewInternal::tagAll() { + updateState = 3; +} + +void KateViewInternal::setPos(int x, int y) { + newXPos = x; + newYPos = y; +} + +void KateViewInternal::center() { + newXPos = 0; + newYPos = cursor.y*myDoc->fontHeight - height()/2; + if (newYPos < 0) newYPos = 0; +} + +void KateViewInternal::updateView(int flags) { + int fontHeight; + int oldXPos, oldYPos; + int w, h; + int z; + bool b; + int xMax, yMax; + int cYPos; + int cXPosMin, cXPosMax, cYPosMin, cYPosMax; + int dx, dy; + int pageScroll; + int scrollbarWidth = style().scrollBarExtent().width(); + +//debug("upView %d %d %d %d %d", exposeCursor, updateState, flags, newXPos, newYPos); + if (exposeCursor || flags & KateView::ufDocGeometry) { + emit myView->newCurPos(); + } else { + if (updateState == 0 && newXPos < 0 && newYPos < 0) return; + } + + if (cursorTimer) { + killTimer(cursorTimer); + cursorTimer = startTimer(KApplication::cursorFlashTime() / 2); + cursorOn = true; + } + + oldXPos = xPos; + oldYPos = yPos; +/* if (flags & ufPos) { + xPos = newXPos; + yPos = newYPos; + exposeCursor = true; + }*/ + if (newXPos >= 0) xPos = newXPos; + if (newYPos >= 0) yPos = newYPos; + + fontHeight = myDoc->fontHeight; + cYPos = cursor.y*fontHeight; + + z = 0; + do { + w = myView->width() - 4; + h = myView->height() - 4; + + xMax = myDoc->textWidth() - w; + b = (xPos > 0 || xMax > 0); + if (b) h -= scrollbarWidth; + yMax = myDoc->textHeight() - h; + if (yPos > 0 || yMax > 0) { + w -= scrollbarWidth; + xMax += scrollbarWidth; + if (!b && xMax > 0) { + h -= scrollbarWidth; + yMax += scrollbarWidth; + } + } + + if (!exposeCursor) break; +// if (flags & KateView::ufNoScroll) break; +/* + if (flags & KateView::ufCenter) { + cXPosMin = xPos + w/3; + cXPosMax = xPos + (w*2)/3; + cYPosMin = yPos + h/3; + cYPosMax = yPos + ((h - fontHeight)*2)/3; + } else {*/ + cXPosMin = xPos + 4; + cXPosMax = xPos + w - 8; + cYPosMin = yPos; + cYPosMax = yPos + (h - fontHeight); +// } + + if (cXPos < cXPosMin) { + xPos -= cXPosMin - cXPos; + } + if (xPos < 0) xPos = 0; + if (cXPos > cXPosMax) { + xPos += cXPos - cXPosMax; + } + if (cYPos < cYPosMin) { + yPos -= cYPosMin - cYPos; + } + if (yPos < 0) yPos = 0; + if (cYPos > cYPosMax) { + yPos += cYPos - cYPosMax; + } + + z++; + } while (z < 2); + + if (xMax < xPos) xMax = xPos; + if (yMax < yPos) yMax = yPos; + + if (xMax > 0) { + pageScroll = w - (w % fontHeight) - fontHeight; + if (pageScroll <= 0) + pageScroll = fontHeight; + + xScroll->blockSignals(true); + xScroll->setGeometry(2,h + 2,w,scrollbarWidth); + xScroll->setRange(0,xMax); + xScroll->setValue(xPos); + xScroll->setSteps(fontHeight,pageScroll); + xScroll->blockSignals(false); + xScroll->show(); + } else xScroll->hide(); + + if (yMax > 0) { + pageScroll = h - (h % fontHeight) - fontHeight; + if (pageScroll <= 0) + pageScroll = fontHeight; + + yScroll->blockSignals(true); + yScroll->setGeometry(w + 2,2,scrollbarWidth,h); + yScroll->setRange(0,yMax); + yScroll->setValue(yPos); + yScroll->setSteps(fontHeight,pageScroll); + yScroll->blockSignals(false); + yScroll->show(); + } else yScroll->hide(); + + if (w != width() || h != height()) { + clearDirtyCache(h); + resize(w,h); + } else { + dx = oldXPos - xPos; + dy = oldYPos - yPos; + + b = updateState == 3; + if (flags & KateView::ufUpdateOnScroll) { + b |= dx || dy; + } else { + b |= QABS(dx)*3 > w*2 || QABS(dy)*3 > h*2; + } + + if (b) { + clearDirtyCache(h); + update(); + } else { + if (dy) + leftBorder->scroll(0, dy); + if (updateState > 0) paintTextLines(oldXPos, oldYPos); + clearDirtyCache(h); + + if (dx || dy) { + scroll(dx,dy); +// kapp->syncX(); +// scroll2(dx - dx/2,dy - dy/2); +// } else { + } + if (cursorOn) paintCursor(); + if (bm.eXPos > bm.sXPos) paintBracketMark(); + } + } + exposeCursor = false; +// updateState = 0; +} + + +void KateViewInternal::paintTextLines(int xPos, int yPos) { +// int xStart, xEnd; + int line;//, z; + int h; + LineRange *r; + + if (!drawBuffer) return; + if (drawBuffer->isNull()) return; + + QPainter paint; + paint.begin(drawBuffer); + + h = myDoc->fontHeight; + r = lineRanges; + for (line = startLine; line <= endLine; line++) { + if (r->start < r->end) { +//debug("painttextline %d %d %d", line, r->start, r->end); + myDoc->paintTextLine(paint, line, r->start, r->end, myView->configFlags & KateView::cfShowTabs); + bitBlt(this, r->start - (xPos-2), line*h - yPos, drawBuffer, 0, 0, + r->end - r->start, h); + leftBorder->paintLine(line); + } + r++; + } + + paint.end(); +} + +void KateViewInternal::paintCursor() { + int h, y, x; + static int cx = 0, cy = 0, ch = 0; + + h = myDoc->fontHeight; + y = h*cursor.y - yPos; + x = cXPos - (xPos-2); + + if(myDoc->myFont != font()) setFont(myDoc->myFont); + if(cx != x || cy != y || ch != h){ + cx = x; + cy = y; + ch = h; + setMicroFocusHint(cx, cy, 0, ch - 2); + } + + QPainter paint; + if (cursorOn) { + paint.begin(this); + paint.setClipping(false); + paint.setPen(myDoc->cursorCol(cursor.x,cursor.y)); + + h += y - 1; + paint.drawLine(x, y, x, h); + + paint.end(); + } else { if (drawBuffer && !drawBuffer->isNull()) { + paint.begin(drawBuffer); + myDoc->paintTextLine(paint, cursor.y, cXPos - 2, cXPos + 3, myView->configFlags & KateView::cfShowTabs); + bitBlt(this,x - 2,y, drawBuffer, 0, 0, 5, h); + paint.end(); } + } + +} + +void KateViewInternal::paintBracketMark() { + int y; + + y = myDoc->fontHeight*(bm.cursor.y +1) - yPos -1; + + QPainter paint; + paint.begin(this); + paint.setPen(myDoc->cursorCol(bm.cursor.x, bm.cursor.y)); + + paint.drawLine(bm.sXPos - (xPos-2), y, bm.eXPos - (xPos-2) -1, y); + paint.end(); +} + +void KateViewInternal::placeCursor(int x, int y, int flags) { + VConfig c; + + getVConfig(c); + c.flags |= flags; + cursor.y = (yPos + y)/myDoc->fontHeight; + cXPos = cOldXPos = myDoc->textWidth(c.flags & KateView::cfWrapCursor, cursor,xPos-2 + x); + changeState(c); +} + +// given physical coordinates, report whether the text there is selected +bool KateViewInternal::isTargetSelected(int x, int y) { + + y = (yPos + y) / myDoc->fontHeight; + + TextLine::Ptr line = myDoc->getTextLine(y); + if (!line) + return false; + + x = myDoc->textPos(line, x); + + return line->isSelected(x); +} + +void KateViewInternal::focusInEvent(QFocusEvent *) { +// debug("got focus %d",cursorTimer); + + if (!cursorTimer) { + cursorTimer = startTimer(KApplication::cursorFlashTime() / 2); + cursorOn = true; + paintCursor(); + } +} + +void KateViewInternal::focusOutEvent(QFocusEvent *) { +// debug("lost focus %d", cursorTimer); + + if (cursorTimer) { + killTimer(cursorTimer); + cursorTimer = 0; + } + + if (cursorOn) { + cursorOn = false; + paintCursor(); + } +} + +void KateViewInternal::keyPressEvent(QKeyEvent *e) { + VConfig c; +// int ascii; + +/* if (e->state() & AltButton) { + e->ignore(); + return; + }*/ +// debug("ascii %i, key %i, state %i",e->ascii(), e->key(), e->state()); + + getVConfig(c); +// ascii = e->ascii(); + + if (!myView->isReadOnly()) { + if (c.flags & KateView::cfTabIndents && myDoc->hasMarkedText()) { + if (e->key() == Qt::Key_Tab) { + myDoc->indent(c); + myDoc->updateViews(); + return; + } + if (e->key() == Qt::Key_Backtab) { + myDoc->unIndent(c); + myDoc->updateViews(); + return; + } + } + if ( !(e->state() & ControlButton ) && myDoc->insertChars(c, e->text())) { + myDoc->updateViews(); + e->accept(); + return; + } + } + e->ignore(); +} + +void KateViewInternal::mousePressEvent(QMouseEvent *e) { + + if (e->button() == LeftButton) { + + int flags; + + flags = 0; + if (e->state() & ShiftButton) { + flags |= KateView::cfMark; + if (e->state() & ControlButton) flags |= KateView::cfMark | KateView::cfKeepSelection; + } + placeCursor(e->x(), e->y(), flags); + scrollX = 0; + scrollY = 0; + if (!scrollTimer) scrollTimer = startTimer(50); + myDoc->updateViews(); + } + if (e->button() == MidButton) { + placeCursor(e->x(), e->y()); + if (! myView->isReadOnly()) + myView->paste(); + } + if (myView->rmbMenu && e->button() == RightButton) { + myView->rmbMenu->popup(mapToGlobal(e->pos())); + } + myView->mousePressEvent(e); // this doesn't do anything, does it? + // it does :-), we need this for KDevelop, so please don't uncomment it again -Sandy +} + +void KateViewInternal::mouseDoubleClickEvent(QMouseEvent *e) { + + if (e->button() == LeftButton) { + VConfig c; + getVConfig(c); + myDoc->selectWord(c.cursor, c.flags); + myDoc->updateViews(); + } +} + +void KateViewInternal::mouseReleaseEvent(QMouseEvent *e) { + + if (e->button() == LeftButton) { + if (myView->config() & KateView::cfMouseAutoCopy) myView->copy(); + killTimer(scrollTimer); + scrollTimer = 0; + } +} + +void KateViewInternal::mouseMoveEvent(QMouseEvent *e) { + + if (e->state() & LeftButton) { + int flags; + int d; + int x = e->x(), + y = e->y(); + + mouseX = e->x(); + mouseY = e->y(); + scrollX = 0; + scrollY = 0; + d = myDoc->fontHeight; + if (mouseX < 0) { + mouseX = 0; + scrollX = -d; + } + if (mouseX > width()) { + mouseX = width(); + scrollX = d; + } + if (mouseY < 0) { + mouseY = 0; + scrollY = -d; + } + if (mouseY > height()) { + mouseY = height(); + scrollY = d; + } +//debug("modifiers %d", ((KGuiCmdApp *) kapp)->getModifiers()); + flags = KateView::cfMark; + if (e->state() & ControlButton) flags |= KateView::cfKeepSelection; + placeCursor(mouseX, mouseY, flags); + myDoc->updateViews(/*ufNoScroll*/); + } +} + + + +void KateViewInternal::wheelEvent( QWheelEvent *e ) +{ + if( yScroll->isVisible() == true ) + { + QApplication::sendEvent( yScroll, e ); + } +} + + + +void KateViewInternal::paintEvent(QPaintEvent *e) { + int xStart, xEnd; + int h; + int line, y, yEnd; + + QRect updateR = e->rect(); + + if (!drawBuffer) return; + if (drawBuffer->isNull()) return; + + QPainter paint; + paint.begin(drawBuffer); + + xStart = xPos-2 + updateR.x(); + xEnd = xStart + updateR.width(); + + h = myDoc->fontHeight; + line = (yPos + updateR.y()) / h; + y = line*h - yPos; + yEnd = updateR.y() + updateR.height(); + waitForPreHighlight=myDoc->needPreHighlight(waitForPreHighlight=line+((long)(yEnd-y)/h)+5); + + while (y < yEnd) + { + TextLine *textLine; + int ctxNum = 0; + myDoc->paintTextLine(paint, line, xStart, xEnd, myView->configFlags & KateView::cfShowTabs); + bitBlt(this, updateR.x(), y, drawBuffer, 0, 0, updateR.width(), h); + leftBorder->paintLine(line); + line++; + y += h; + } + paint.end(); + + if (cursorOn) paintCursor(); + if (bm.eXPos > bm.sXPos) paintBracketMark(); +} + +void KateViewInternal::resizeEvent(QResizeEvent *) +{ + drawBuffer->resize (width(), myDoc->fontHeight); + leftBorder->resize(iconBorderWidth, height()); +} + +void KateViewInternal::timerEvent(QTimerEvent *e) { + if (e->timerId() == cursorTimer) { + cursorOn = !cursorOn; + paintCursor(); + } + if (e->timerId() == scrollTimer && (scrollX | scrollY)) { + xScroll->setValue(xPos + scrollX); + yScroll->setValue(yPos + scrollY); + + placeCursor(mouseX, mouseY, KateView::cfMark); + myDoc->updateViews(/*ufNoScroll*/); + } +} + +uint KateView::uniqueID = 0; + +KateView::KateView(KateDocument *doc, QWidget *parent, const char * name) : Kate::View (doc, parent, name) +{ + + myViewID = uniqueID; + uniqueID++; + + active = false; + myIconBorder = false; + + myDoc = doc; + myViewInternal = new KateViewInternal (this,doc); + myViewInternal->move(2, 2); + myViewInternal->leftBorder = new KateIconBorder(this, myViewInternal); + myViewInternal->leftBorder->setGeometry(2, 2, myViewInternal->iconBorderWidth, myViewInternal->iconBorderHeight); + myViewInternal->leftBorder->hide(); + + doc->addView( this ); + + + // some defaults + configFlags = KateView::cfAutoIndent | KateView::cfBackspaceIndents + | KateView::cfTabIndents | KateView::cfKeepIndentProfile + | KateView::cfRemoveSpaces + | KateView::cfDelOnInput | KateView::cfMouseAutoCopy | KateView::cfWrapCursor + | KateView::cfGroupUndo | KateView::cfShowTabs | KateView::cfSmartHome; + + searchFlags = 0; + replacePrompt = 0L; + rmbMenu = 0L; + + + setFocusProxy( myViewInternal ); + myViewInternal->setFocus(); + resize(parent->width() -4, parent->height() -4); + + + myViewInternal->installEventFilter( this ); + + //setupActions(); + + connect( this, SIGNAL( newStatus() ), this, SLOT( slotUpdate() ) ); + connect( this, SIGNAL( newUndo() ), this, SLOT( slotNewUndo() ) ); + connect( doc, SIGNAL( fileNameChanged() ), this, SLOT( slotFileStatusChanged() ) ); + connect( doc, SIGNAL( highlightChanged() ), this, SLOT( slotHighlightChanged() ) ); + + readConfig(); +// setHighlight->setCurrentItem(getHl()); + slotUpdate(); +} + +KateView::~KateView() +{ + + if (myDoc && !myDoc->m_bSingleViewMode) + myDoc->removeView( this ); + + delete myViewInternal; + +} + +#if 0 +void KateView::setupActions() +{ +#if 0 + KStdAction::close( this, SLOT(flush()), actionCollection(), "file_close" ); + + KStdAction::save(this, SLOT(save()), actionCollection()); + + // setup edit menu + editUndo = KStdAction::undo(this, SLOT(undo()), actionCollection()); + editRedo = KStdAction::redo(this, SLOT(redo()), actionCollection()); + editUndoHist = new KAction(i18n("Undo/Redo &History..."), 0, this, SLOT(undoHistory()), + actionCollection(), "edit_undoHistory"); + KStdAction::cut(this, SLOT(cut()), actionCollection()); + KStdAction::copy(this, SLOT(copy()), actionCollection()); + KStdAction::paste(this, SLOT(paste()), actionCollection()); + + if ( myDoc->hasBrowserExtension() ) + { + KStdAction::saveAs(this, SLOT(saveAs()), myDoc->actionCollection()); + KStdAction::find(this, SLOT(find()), myDoc->actionCollection(), "find"); + KStdAction::findNext(this, SLOT(findAgain()), myDoc->actionCollection(), "find_again"); + KStdAction::findPrev(this, SLOT(findPrev()), myDoc->actionCollection(), "find_prev"); + KStdAction::gotoLine(this, SLOT(gotoLine()), myDoc->actionCollection(), "goto_line" ); + new KAction(i18n("&Configure Editor..."), 0, this, SLOT(configDialog()),myDoc->actionCollection(), "set_confdlg"); + setHighlight = new KSelectAction(i18n("&Highlight Mode"), 0, myDoc->actionCollection(), "set_highlight"); + KStdAction::selectAll(this, SLOT(selectAll()), myDoc->actionCollection(), "select_all"); + new KAction(i18n("&Deselect All"), 0, this, SLOT(deselectAll()), + myDoc->actionCollection(), "unselect_all"); + new KAction(i18n("Invert &Selection"), 0, this, SLOT(invertSelection()), + myDoc->actionCollection(), "invert_select"); + + new KAction(i18n("Increase Font Sizes"), "viewmag+", 0, this, SLOT(slotIncFontSizes()), + myDoc->actionCollection(), "incFontSizes"); + new KAction(i18n("Decrease Font Sizes"), "viewmag-", 0, this, SLOT(slotDecFontSizes()), + myDoc->actionCollection(), "decFontSizes"); + } + else + { + KStdAction::saveAs(this, SLOT(saveAs()), actionCollection()); + KStdAction::find(this, SLOT(find()), actionCollection()); + KStdAction::findNext(this, SLOT(findAgain()), actionCollection()); + KStdAction::findPrev(this, SLOT(findPrev()), actionCollection(), "edit_find_prev"); + KStdAction::gotoLine(this, SLOT(gotoLine()), actionCollection()); + new KAction(i18n("&Configure Editor..."), 0, this, SLOT(configDialog()),actionCollection(), "set_confdlg"); + setHighlight = new KSelectAction(i18n("&Highlight Mode"), 0, actionCollection(), "set_highlight"); + KStdAction::selectAll(this, SLOT(selectAll()), actionCollection()); + new KAction(i18n("&Deselect All"), 0, this, SLOT(deselectAll()), + actionCollection(), "edit_deselectAll"); + new KAction(i18n("Invert &Selection"), 0, this, SLOT(invertSelection()), + actionCollection(), "edit_invertSelection"); + + new KAction(i18n("Increase Font Sizes"), "viewmag+", 0, this, SLOT(slotIncFontSizes()), + actionCollection(), "incFontSizes"); + new KAction(i18n("Decrease Font Sizes"), "viewmag-", 0, this, SLOT(slotDecFontSizes()), + actionCollection(), "decFontSizes"); + } + + new KAction(i18n("Apply Word Wrap"), 0, myDoc, SLOT(applyWordWrap()), actionCollection(), "edit_apply_wordwrap"); + + KStdAction::replace(this, SLOT(replace()), actionCollection()); + + new KAction(i18n("Editing Co&mmand"), Qt::CTRL+Qt::Key_M, this, SLOT(slotEditCommand()), + actionCollection(), "edit_cmd"); + + // setup bookmark menu + bookmarkToggle = new KAction(i18n("Toggle &Bookmark"), Qt::CTRL+Qt::Key_B, this, SLOT(toggleBookmark()), actionCollection(), "edit_bookmarkToggle"); + bookmarkClear = new KAction(i18n("Clear Bookmarks"), 0, this, SLOT(clearBookmarks()), actionCollection(), "edit_bookmarksClear"); + + // connect settings menu aboutToshow + bookmarkMenu = new KActionMenu(i18n("&Bookmarks"), actionCollection(), "bookmarks"); + connect(bookmarkMenu->popupMenu(), SIGNAL(aboutToShow()), this, SLOT(bookmarkMenuAboutToShow())); + + new KToggleAction(i18n("Show &IconBorder"), Key_F6, this, SLOT(toggleIconBorder()), actionCollection(), "view_border"); + + // setup Tools menu + KStdAction::spelling(this, SLOT(spellcheck()), actionCollection()); + new KAction(i18n("&Indent"), "indent", Qt::CTRL+Qt::Key_I, this, SLOT(indent()), + actionCollection(), "tools_indent"); + new KAction(i18n("&Unindent"), "unindent", Qt::CTRL+Qt::Key_U, this, SLOT(unIndent()), + actionCollection(), "tools_unindent"); + new KAction(i18n("&Clean Indentation"), 0, this, SLOT(cleanIndent()), + actionCollection(), "tools_cleanIndent"); + new KAction(i18n("C&omment"), CTRL+Qt::Key_NumberSign, this, SLOT(comment()), + actionCollection(), "tools_comment"); + new KAction(i18n("Unco&mment"), CTRL+SHIFT+Qt::Key_NumberSign, this, SLOT(uncomment()), + actionCollection(), "tools_uncomment"); + + setVerticalSelection = new KToggleAction(i18n("&Vertical Selection"), Key_F4, this, SLOT(toggleVertical()), + actionCollection(), "set_verticalSelect"); + + connect(setHighlight, SIGNAL(activated(int)), this, SLOT(setHl(int))); + QStringList list; + for (int z = 0; z < HlManager::self()->highlights(); z++) + list.append(HlManager::self()->hlName(z)); + setHighlight->setItems(list); + + setEndOfLine = new KSelectAction(i18n("&End Of Line"), 0, actionCollection(), "set_eol"); + connect(setEndOfLine, SIGNAL(activated(int)), this, SLOT(setEol(int))); + list.clear(); + list.append("&Unix"); + list.append("&Windows/Dos"); + list.append("&Macintosh"); + setEndOfLine->setItems(list); +#endif +} +#endif + +void KateView::slotUpdate() +{ + int cfg = config(); + +#warning fixme setVerticalSelection->setChecked(cfg & KateView::cfVerticalSelect); + + slotNewUndo(); +} +void KateView::slotFileStatusChanged() +{ + int eol = getEol(); + eol = eol>=1 ? eol : 0; + +#warning fixme setEndOfLine->setCurrentItem(eol); +} +void KateView::slotNewUndo() +{ +#if 0 + int state = undoState(); + + editUndoHist->setEnabled(state & 1 || state & 2); + + QString t = i18n("Und&o"); // it would be nicer to fetch the original string + if (state & 1) { + editUndo->setEnabled(true); + t += ' '; + t += i18n(undoTypeName(nextUndoType())); + } else { + editUndo->setEnabled(false); + } + editUndo->setText(t); + + t = i18n("Re&do"); // it would be nicer to fetch the original string + if (state & 2) { + editRedo->setEnabled(true); + t += ' '; + t += i18n(undoTypeName(nextRedoType())); + } else { + editRedo->setEnabled(false); + } + editRedo->setText(t); +#endif +} + +void KateView::slotHighlightChanged() +{ +// setHighlight->setCurrentItem(getHl()); +} + + +void KateView::keyPressEvent( QKeyEvent *ev ) +{ + switch ( ev->key() ) + { + case Key_Left: + if ( ev->state() & ShiftButton ) + { + if ( ev->state() & ControlButton ) + shiftWordLeft(); + else + shiftCursorLeft(); + } + else if ( ev->state() & ControlButton ) + wordLeft(); + else + cursorLeft(); + break; + case Key_Right: + if ( ev->state() & ShiftButton ) + { + if ( ev->state() & ControlButton ) + shiftWordRight(); + else + shiftCursorRight(); + } + else if ( ev->state() & ControlButton ) + wordRight(); + else + cursorRight(); + break; + case Key_Home: + if ( ev->state() & ShiftButton ) + { + if ( ev->state() & ControlButton ) + shiftTop(); + else + shiftHome(); + } + else if ( ev->state() & ControlButton ) + top(); + else + home(); + break; + case Key_End: + if ( ev->state() & ShiftButton ) + { + if ( ev->state() & ControlButton ) + shiftBottom(); + else + shiftEnd(); + } + else if ( ev->state() & ControlButton ) + bottom(); + else + end(); + break; + case Key_Up: + if ( ev->state() & ShiftButton ) + shiftUp(); + else if ( ev->state() & ControlButton ) + scrollUp(); + else + up(); + break; + case Key_Down: + if ( ev->state() & ShiftButton ) + shiftDown(); + else if ( ev->state() & ControlButton ) + scrollDown(); + else + down(); + break; + case Key_PageUp: + if ( ev->state() & ShiftButton ) + shiftPageUp(); + else if ( ev->state() & ControlButton ) + topOfView(); + else + pageUp(); + break; + case Key_PageDown: + if ( ev->state() & ShiftButton ) + shiftPageDown(); + else if ( ev->state() & ControlButton ) + bottomOfView(); + else + pageDown(); + break; + case Key_Return: + case Key_Enter: + keyReturn(); + break; + case Key_Delete: + if ( ev->state() & ControlButton ) + { + VConfig c; + shiftWordRight(); + myViewInternal->getVConfig(c); + myDoc->delMarkedText(c); + myViewInternal->update(); + } + else keyDelete(); + break; + case Key_Backspace: + if ( ev->state() & ControlButton ) + { + VConfig c; + shiftWordLeft(); + myViewInternal->getVConfig(c); + myDoc->delMarkedText(c); + myViewInternal->update(); + } + else backspace(); + break; + case Key_Insert: + toggleInsert(); + break; + case Key_K: + if ( ev->state() & ControlButton ) + { + killLine(); + break; + } + default: + KTextEditor::View::keyPressEvent( ev ); + return; + break; + } + ev->accept(); +} + + +void KateView::setCursorPosition( int line, int col, bool /*mark*/ ) +{ + setCursorPositionInternal( line, col ); +} + +void KateView::getCursorPosition( int *line, int *col ) +{ + if ( line ) + *line = currentLine(); + + if ( col ) + *col = currentColumn(); +} + + +int KateView::currentLine() { + return myViewInternal->cursor.y; +} + +int KateView::currentColumn() { + return myDoc->currentColumn(myViewInternal->cursor); +} + +int KateView::currentCharNum() { + return myViewInternal->cursor.x; +} + +void KateView::setCursorPositionInternal(int line, int col) { + PointStruc cursor; + + cursor.x = col; + cursor.y = line; + myViewInternal->updateCursor(cursor); + myViewInternal->center(); +// myViewInternal->updateView(ufPos, 0, line*myDoc->fontHeight - height()/2); +// myDoc->updateViews(myViewInternal); //uptade all other views except this one + myDoc->updateViews(); +} + +int KateView::config() { + int flags; + + flags = configFlags; + if (myDoc->singleSelection()) flags |= KateView::cfSingleSelection; + return flags; +} + +void KateView::setConfig(int flags) { + bool updateView; + + // cfSingleSelection is a doc-property + myDoc->setSingleSelection(flags & KateView::cfSingleSelection); + flags &= ~KateView::cfSingleSelection; + + if (flags != configFlags) { + // update the view if visibility of tabs has changed + updateView = (flags ^ configFlags) & KateView::cfShowTabs; + configFlags = flags; + emit newStatus(); + if (updateView) myViewInternal->update(); + } +} + +int KateView::tabWidth() { + return myDoc->tabChars; +} + +void KateView::setTabWidth(int w) { + myDoc->setTabWidth(w); + myDoc->updateViews(); +} + +void KateView::setEncoding (QString e) { + myDoc->setEncoding (e); + myDoc->updateViews(); +} + +int KateView::undoSteps() { + return myDoc->undoSteps; +} + +void KateView::setUndoSteps(int s) { + myDoc->setUndoSteps(s); +} + +bool KateView::isReadOnly() { + return myDoc->readOnly; +} + +bool KateView::isModified() { + return myDoc->modified; +} + +void KateView::setReadOnly(bool m) { + myDoc->setReadOnly(m); +} + +void KateView::setModified(bool m) { + myDoc->setModified(m); +} + +bool KateView::isLastView() { + return myDoc->isLastView(1); +} + +KateDocument *KateView::doc() { + return myDoc; +} + +int KateView::undoState() { + if (isReadOnly()) + return 0; + else + return myDoc->undoState; +} + +int KateView::nextUndoType() { + return myDoc->nextUndoType(); +} + +int KateView::nextRedoType() { + return myDoc->nextRedoType(); +} + +void KateView::undoTypeList(QValueList<int> &lst) +{ + myDoc->undoTypeList(lst); +} + +void KateView::redoTypeList(QValueList<int> &lst) +{ + myDoc->redoTypeList(lst); +} + +const char * KateView::undoTypeName(int type) { + return KateActionGroup::typeName(type); +} + +QColor* KateView::getColors() +{ + return myDoc->colors; +} + +void KateView::applyColors() +{ + myDoc->tagAll(); + myDoc->updateViews(); +} + +bool KateView::isOverwriteMode() const +{ + return ( configFlags & KateView::cfOvr ); +} + +void KateView::setOverwriteMode( bool b ) +{ + if ( isOverwriteMode() && !b ) + setConfig( configFlags ^ KateView::cfOvr ); + else + setConfig( configFlags | KateView::cfOvr ); +} + +void KateView::toggleInsert() { + setConfig(configFlags ^ KateView::cfOvr); +} + +void KateView::toggleVertical() +{ + setConfig(configFlags ^ KateView::cfVerticalSelect); +} + + +int KateView::numLines() { + return myDoc->numLines(); +} + +QString KateView::text() { + return myDoc->text(); +} + +QString KateView::currentTextLine() { + TextLine::Ptr textLine = myDoc->getTextLine(myViewInternal->cursor.y); + return QString(textLine->getText(), textLine->length()); +} + +QString KateView::textLine(int num) { + TextLine::Ptr textLine = myDoc->getTextLine(num); + return QString(textLine->getText(), textLine->length()); +} + +QString KateView::currentWord() { + return myDoc->getWord(myViewInternal->cursor); +} + +QString KateView::word(int x, int y) { + PointStruc cursor; + cursor.y = (myViewInternal->yPos + y)/myDoc->fontHeight; + if (cursor.y < 0 || cursor.y > myDoc->lastLine()) return QString(); + cursor.x = myDoc->textPos(myDoc->getTextLine(cursor.y), myViewInternal->xPos-2 + x); + return myDoc->getWord(cursor); +} + +void KateView::setText(const QString &s) { + myDoc->setText(s); + myDoc->updateViews(); +} + +void KateView::insertText(const QString &s, bool /*mark*/) { + VConfig c; + myViewInternal->getVConfig(c); + myDoc->insert(c, s); + myDoc->updateViews(); +} + +bool KateView::hasMarkedText() { + return myDoc->hasMarkedText(); +} + +QString KateView::markedText() { + return myDoc->markedText(configFlags); +} + +bool KateView::canDiscard() { + int query; + + if (isModified()) { + query = KMessageBox::warningYesNoCancel(this, + i18n("The current Document has been modified.\nWould you like to save it?")); + switch (query) { + case KMessageBox::Yes: //yes + if (save() == CANCEL) return false; + if (isModified()) { + query = KMessageBox::warningContinueCancel(this, + i18n("Could not save the document.\nDiscard it and continue?"), + QString::null, i18n("&Discard")); + if (query == KMessageBox::Cancel) return false; + } + break; + case KMessageBox::Cancel: //cancel + return false; + } + } + return true; +} + +void KateView::flush() +{ + if (canDiscard()) myDoc->flush(); +} + +KateView::fileResult KateView::save() { + int query = KMessageBox::Yes; + if (isModified()) { + return saveAs(); + } + return OK; +} + +KateView::fileResult KateView::saveAs() { + return OK; +} + +void KateView::doCursorCommand(int cmdNum) { + VConfig c; + myViewInternal->getVConfig(c); + if (cmdNum & selectFlag) c.flags |= KateView::cfMark; + if (cmdNum & multiSelectFlag) c.flags |= KateView::cfMark | KateView::cfKeepSelection; + cmdNum &= ~(selectFlag | multiSelectFlag); + myViewInternal->doCursorCommand(c, cmdNum); + myDoc->updateViews(); +} + +void KateView::doEditCommand(int cmdNum) { + VConfig c; + myViewInternal->getVConfig(c); + myViewInternal->doEditCommand(c, cmdNum); + myDoc->updateViews(); +} + +void KateView::undoMultiple(int count) { + if (isReadOnly()) + return; + + VConfig c; + myViewInternal->getVConfig(c); + myDoc->undo(c, count); + myDoc->updateViews(); +} + +void KateView::redoMultiple(int count) { + if (isReadOnly()) + return; + + VConfig c; + myViewInternal->getVConfig(c); + myDoc->redo(c, count); + myDoc->updateViews(); +} + +void KateView::undoHistory() +{ + UndoHistory *undoH; + + undoH = new UndoHistory(this, this, "UndoHistory", true); + + undoH->setCaption(i18n("Undo/Redo History")); + + connect(this,SIGNAL(newUndo()),undoH,SLOT(newUndo())); + connect(undoH,SIGNAL(undo(int)),this,SLOT(undoMultiple(int))); + connect(undoH,SIGNAL(redo(int)),this,SLOT(redoMultiple(int))); + + undoH->exec(); + + delete undoH; +} + +static void kwview_addToStrList(QStringList &list, const QString &str) { + if (list.count() > 0) { + if (list.first() == str) return; + QStringList::Iterator it; + it = list.find(str); + if (*it != 0L) list.remove(it); + if (list.count() >= 16) list.remove(list.fromLast()); + } + list.prepend(str); +} + +void KateView::find() { + SearchDialog *searchDialog; + + if (!myDoc->hasMarkedText()) searchFlags &= ~KateView::sfSelected; + + searchDialog = new SearchDialog(this, myDoc->searchForList, myDoc->replaceWithList, + searchFlags & ~KateView::sfReplace); + + // If the user has marked some text we use that otherwise + // use the word under the cursor. + QString str; + if (myDoc->hasMarkedText()) + str = markedText(); + + if (str.isEmpty()) + str = currentWord(); + + if (!str.isEmpty()) + { + str.replace(QRegExp("^\n"), ""); + int pos=str.find("\n"); + if (pos>-1) + str=str.left(pos); + searchDialog->setSearchText( str ); + } + + myViewInternal->focusOutEvent(0L);// QT bug ? + if (searchDialog->exec() == QDialog::Accepted) { + kwview_addToStrList(myDoc->searchForList, searchDialog->getSearchFor()); + searchFlags = searchDialog->getFlags() | (searchFlags & KateView::sfPrompt); + initSearch(s, searchFlags); + findAgain(s); + } + delete searchDialog; +} + +void KateView::replace() { + SearchDialog *searchDialog; + + if (isReadOnly()) return; + + if (!myDoc->hasMarkedText()) searchFlags &= ~KateView::sfSelected; + searchDialog = new SearchDialog(this, myDoc->searchForList, myDoc->replaceWithList, + searchFlags | KateView::sfReplace); + + // If the user has marked some text we use that otherwise + // use the word under the cursor. + QString str; + if (myDoc->hasMarkedText()) + str = markedText(); + + if (str.isEmpty()) + str = currentWord(); + + if (!str.isEmpty()) + { + str.replace(QRegExp("^\n"), ""); + int pos=str.find("\n"); + if (pos>-1) + str=str.left(pos); + searchDialog->setSearchText( str ); + } + + myViewInternal->focusOutEvent(0L);// QT bug ? + if (searchDialog->exec() == QDialog::Accepted) { +// myDoc->recordReset(); + kwview_addToStrList(myDoc->searchForList, searchDialog->getSearchFor()); + kwview_addToStrList(myDoc->replaceWithList, searchDialog->getReplaceWith()); + searchFlags = searchDialog->getFlags(); + initSearch(s, searchFlags); + replaceAgain(); + } + delete searchDialog; +} + +void KateView::gotoLine() { + GotoLineDialog *dlg; + PointStruc cursor; + + dlg = new GotoLineDialog(this, myViewInternal->cursor.y + 1, myDoc->numLines()); +// dlg = new GotoLineDialog(myViewInternal->cursor.y + 1, this); + + if (dlg->exec() == QDialog::Accepted) { +// myDoc->recordReset(); + cursor.x = 0; + cursor.y = dlg->getLine() - 1; + myDoc->needPreHighlight(cursor.y); + myViewInternal->updateCursor(cursor); + myViewInternal->center(); + myViewInternal->updateView(KateView::ufUpdateOnScroll); + myDoc->updateViews(this); //uptade all other views except this one + } + delete dlg; +} + + +void KateView::initSearch(SConfig &s, int flags) { + + s.flags = flags; + s.setPattern(myDoc->searchForList.first()); + + if (!(s.flags & KateView::sfFromBeginning)) { + // If we are continuing a backward search, make sure we do not get stuck + // at an existing match. + s.cursor = myViewInternal->cursor; + TextLine::Ptr textLine = myDoc->getTextLine(s.cursor.y); + QString const txt(textLine->getText(),textLine->length()); + const QString searchFor= myDoc->searchForList.first(); + int pos = s.cursor.x-searchFor.length()-1; + if ( pos < 0 ) pos = 0; + pos= txt.find(searchFor, pos, s.flags & KateView::sfCaseSensitive); + if ( s.flags & KateView::sfBackward ) + { + if ( pos <= s.cursor.x ) s.cursor.x= pos-1; + } + else + if ( pos == s.cursor.x ) s.cursor.x++; + } else { + if (!(s.flags & KateView::sfBackward)) { + s.cursor.x = 0; + s.cursor.y = 0; + } else { + s.cursor.x = -1; + s.cursor.y = myDoc->lastLine(); + } + s.flags |= KateView::sfFinished; + } + if (!(s.flags & KateView::sfBackward)) { + if (!(s.cursor.x || s.cursor.y)) + s.flags |= KateView::sfFinished; + } + s.startCursor = s.cursor; +} + +void KateView::continueSearch(SConfig &s) { + + if (!(s.flags & KateView::sfBackward)) { + s.cursor.x = 0; + s.cursor.y = 0; + } else { + s.cursor.x = -1; + s.cursor.y = myDoc->lastLine(); + } + s.flags |= KateView::sfFinished; + s.flags &= ~KateView::sfAgain; +} + +void KateView::findAgain(SConfig &s) { + int query; + PointStruc cursor; + QString str; + + QString searchFor = myDoc->searchForList.first(); + + if( searchFor.isEmpty() ) { + find(); + return; + } + + do { + query = KMessageBox::Cancel; + if (myDoc->doSearch(s,searchFor)) { + cursor = s.cursor; + if (!(s.flags & KateView::sfBackward)) + s.cursor.x += s.matchedLength; + myViewInternal->updateCursor(s.cursor); //does deselectAll() + exposeFound(cursor,s.matchedLength,(s.flags & KateView::sfAgain) ? 0 : KateView::ufUpdateOnScroll,false); + } else { + if (!(s.flags & KateView::sfFinished)) { + // ask for continue + if (!(s.flags & KateView::sfBackward)) { + // forward search + str = i18n("End of document reached.\n" + "Continue from the beginning?"); + query = KMessageBox::warningContinueCancel(this, + str, i18n("Find"), i18n("Continue")); + } else { + // backward search + str = i18n("Beginning of document reached.\n" + "Continue from the end?"); + query = KMessageBox::warningContinueCancel(this, + str, i18n("Find"), i18n("Continue")); + } + continueSearch(s); + } else { + // wrapped + KMessageBox::sorry(this, + i18n("Search string '%1' not found!").arg(searchFor), + i18n("Find")); + } + } + } while (query == KMessageBox::Continue); +} + +void KateView::replaceAgain() { + if (isReadOnly()) + return; + + replaces = 0; + if (s.flags & KateView::sfPrompt) { + doReplaceAction(-1); + } else { + doReplaceAction(KateView::srAll); + } +} + +void KateView::doReplaceAction(int result, bool found) { + int rlen; + PointStruc cursor; + bool started; + + QString searchFor = myDoc->searchForList.first(); + QString replaceWith = myDoc->replaceWithList.first(); + rlen = replaceWith.length(); + + switch (result) { + case KateView::srYes: //yes + myDoc->recordStart(this, s.cursor, configFlags, + KateActionGroup::ugReplace, true); + myDoc->recordReplace(s.cursor, s.matchedLength, replaceWith); + replaces++; + if (s.cursor.y == s.startCursor.y && s.cursor.x < s.startCursor.x) + s.startCursor.x += rlen - s.matchedLength; + if (!(s.flags & KateView::sfBackward)) s.cursor.x += rlen; + myDoc->recordEnd(this, s.cursor, configFlags | KateView::cfPersistent); + break; + case KateView::srNo: //no + if (!(s.flags & KateView::sfBackward)) s.cursor.x += s.matchedLength; + break; + case KateView::srAll: //replace all + deleteReplacePrompt(); + do { + started = false; + while (found || myDoc->doSearch(s,searchFor)) { + if (!started) { + found = false; + myDoc->recordStart(this, s.cursor, configFlags, + KateActionGroup::ugReplace); + started = true; + } + myDoc->recordReplace(s.cursor, s.matchedLength, replaceWith); + replaces++; + if (s.cursor.y == s.startCursor.y && s.cursor.x < s.startCursor.x) + s.startCursor.x += rlen - s.matchedLength; + if (!(s.flags & KateView::sfBackward)) s.cursor.x += rlen; + } + if (started) myDoc->recordEnd(this, s.cursor, + configFlags | KateView::cfPersistent); + } while (!askReplaceEnd()); + return; + case KateView::srCancel: //cancel + deleteReplacePrompt(); + return; + default: + replacePrompt = 0L; + } + + do { + if (myDoc->doSearch(s,searchFor)) { + //text found: highlight it, show replace prompt if needed and exit + cursor = s.cursor; + if (!(s.flags & KateView::sfBackward)) cursor.x += s.matchedLength; + myViewInternal->updateCursor(cursor); //does deselectAll() + exposeFound(s.cursor,s.matchedLength,(s.flags & KateView::sfAgain) ? 0 : KateView::ufUpdateOnScroll,true); + if (replacePrompt == 0L) { + replacePrompt = new ReplacePrompt(this); + myDoc->setPseudoModal(replacePrompt);//disable(); + connect(replacePrompt,SIGNAL(clicked()),this,SLOT(replaceSlot())); + replacePrompt->show(); //this is not modal + } + return; //exit if text found + } + //nothing found: repeat until user cancels "repeat from beginning" dialog + } while (!askReplaceEnd()); + deleteReplacePrompt(); +} + +void KateView::exposeFound(PointStruc &cursor, int slen, int flags, bool replace) { + int x1, x2, y1, y2, xPos, yPos; + + VConfig c; + myViewInternal->getVConfig(c); + myDoc->selectLength(cursor,slen,c.flags); + + TextLine::Ptr textLine = myDoc->getTextLine(cursor.y); + x1 = myDoc->textWidth(textLine,cursor.x) -10; + x2 = myDoc->textWidth(textLine,cursor.x + slen) +20; + y1 = myDoc->fontHeight*cursor.y -10; + y2 = y1 + myDoc->fontHeight +30; + + xPos = myViewInternal->xPos; + yPos = myViewInternal->yPos; + + if (x1 < 0) x1 = 0; + if (replace) y2 += 90; + + if (x1 < xPos || x2 > xPos + myViewInternal->width()) { + xPos = x2 - myViewInternal->width(); + } + if (y1 < yPos || y2 > yPos + myViewInternal->height()) { + xPos = x2 - myViewInternal->width(); + yPos = myDoc->fontHeight*cursor.y - height()/3; + } + myViewInternal->setPos(xPos, yPos); + myViewInternal->updateView(flags);// | ufPos,xPos,yPos); + myDoc->updateViews(this); +} + +void KateView::deleteReplacePrompt() { + myDoc->setPseudoModal(0L); +} + +bool KateView::askReplaceEnd() { + QString str; + int query; + + myDoc->updateViews(); + if (s.flags & KateView::sfFinished) { + // replace finished + str = i18n("%1 replacement(s) made").arg(replaces); + KMessageBox::information(this, str, i18n("Replace")); + return true; + } + + // ask for continue + if (!(s.flags & KateView::sfBackward)) { + // forward search + str = i18n("%1 replacement(s) made.\n" + "End of document reached.\n" + "Continue from the beginning?").arg(replaces); + query = KMessageBox::questionYesNo(this, str, i18n("Replace"), + i18n("Continue"), i18n("Stop")); + } else { + // backward search + str = i18n("%1 replacement(s) made.\n" + "Beginning of document reached.\n" + "Continue from the end?").arg(replaces); + query = KMessageBox::questionYesNo(this, str, i18n("Replace"), + i18n("Continue"), i18n("Stop")); + } + replaces = 0; + continueSearch(s); + return (query == KMessageBox::No); +} + +void KateView::replaceSlot() { + doReplaceAction(replacePrompt->result(),true); +} + +void KateView::installPopup(QPopupMenu *rmb_Menu) +{ + rmbMenu = rmb_Menu; +} + +void KateView::readConfig() +{ + KConfig *config = KGlobal::config(); + config->setGroup("Kate View"); + + searchFlags = config->readNumEntry("SearchFlags", KateView::sfPrompt); + configFlags = config->readNumEntry("ConfigFlags", configFlags) & ~KateView::cfMark; + + config->sync(); +} + +void KateView::writeConfig() +{ + KConfig *config = KGlobal::config(); + config->setGroup("Kate View"); + + config->writeEntry("SearchFlags",searchFlags); + config->writeEntry("ConfigFlags",configFlags); + + config->sync(); +} + +void KateView::readSessionConfig(KConfig *config) +{ + PointStruc cursor; + + myViewInternal->xPos = config->readNumEntry("XPos"); + myViewInternal->yPos = config->readNumEntry("YPos"); + cursor.x = config->readNumEntry("CursorX"); + cursor.y = config->readNumEntry("CursorY"); + myViewInternal->updateCursor(cursor); + myIconBorder = config->readBoolEntry("IconBorder on"); + setIconBorder(myIconBorder); +} + +void KateView::writeSessionConfig(KConfig *config) +{ + config->writeEntry("XPos",myViewInternal->xPos); + config->writeEntry("YPos",myViewInternal->yPos); + config->writeEntry("CursorX",myViewInternal->cursor.x); + config->writeEntry("CursorY",myViewInternal->cursor.y); + config->writeEntry("IconBorder on", myIconBorder); +} + +void KateView::configDialog() +{ + +#warning fixme + +#if 1 + KDialogBase *kd = new KDialogBase(KDialogBase::IconList, + i18n("Configure Editor"), + KDialogBase::Ok | KDialogBase::Cancel | + KDialogBase::Help , + KDialogBase::Ok, this, "tabdialog"); + + // color options + QFrame *page=kd->addPage(i18n("Colors")); + (new QVBoxLayout(page))->setAutoAdd(true); + ColorConfig *colorConfig = new ColorConfig(page); + QColor* colors = getColors(); + colorConfig->setColors(colors); + + page = kd->addPage(i18n("Fonts")); + (new QVBoxLayout(page))->setAutoAdd(true); + + FontConfig *fontConfig = new FontConfig(page); + fontConfig->setFont (myDoc->getFont()); + + // indent options + page=kd->addPage(i18n("Indent")); + (new QVBoxLayout(page))->setAutoAdd(true); + + IndentConfigTab *indentConfig = new IndentConfigTab(page, this); + + // select options + page=kd->addPage(i18n("Select")); + (new QVBoxLayout(page))->setAutoAdd(true); + + SelectConfigTab *selectConfig = new SelectConfigTab(page, this); + + // edit options + page=kd->addPage(i18n("Edit")); + (new QVBoxLayout(page))->setAutoAdd(true); + + EditConfigTab *editConfig = new EditConfigTab(page, this); + + + + HighlightDialogPage *hlPage; + HlManager *hlManager; + HlDataList hlDataList; + ItemStyleList defaultStyleList; + + hlManager = HlManager::self(); + + defaultStyleList.setAutoDelete(true); + hlManager->getDefaults(defaultStyleList); + + hlDataList.setAutoDelete(true); + //this gets the data from the KConfig object + hlManager->getHlDataList(hlDataList); + + page=kd->addPage(i18n("Highlighting")); + (new QVBoxLayout(page))->setAutoAdd(true); + + hlPage = new HighlightDialogPage(hlManager, &defaultStyleList, &hlDataList, 0, page); + + if (kd->exec()) { + // color options + colorConfig->getColors(colors); + myDoc->setFont (fontConfig->getFont()); + + applyColors(); + // indent options + indentConfig->getData(this); + // select options + selectConfig->getData(this); + // edit options + editConfig->getData(this); + // spell checker + hlManager->setHlDataList(hlDataList); + hlManager->setDefaults(defaultStyleList); + hlPage->saveData(); + } + + delete kd; + +#endif +} + +int KateView::getHl() { + return myDoc->highlightNum(); +} + +void KateView::setDontChangeHlOnSave() +{ + myDoc->setDontChangeHlOnSave(); +} + +void KateView::setHl(int n) { + myDoc->setHighlight(n); + myDoc->setDontChangeHlOnSave(); + myDoc->updateViews(); +} + +int KateView::getEol() { + return myDoc->eolMode; +} + +void KateView::setEol(int eol) { + if (isReadOnly()) + return; + + myDoc->eolMode = eol; + myDoc->setModified(true); +} + + + +void KateView::paintEvent(QPaintEvent *e) { + int x, y; + + QRect updateR = e->rect(); // update rectangle +// debug("Update rect = ( %i, %i, %i, %i )", +// updateR.x(),updateR.y(), updateR.width(), updateR.height() ); + + int ux1 = updateR.x(); + int uy1 = updateR.y(); + int ux2 = ux1 + updateR.width(); + int uy2 = uy1 + updateR.height(); + + QPainter paint; + paint.begin(this); + + QColorGroup g = colorGroup(); + x = width(); + y = height(); + + paint.setPen(g.dark()); + if (uy1 <= 0) paint.drawLine(0,0,x-2,0); + if (ux1 <= 0) paint.drawLine(0,1,0,y-2); + + paint.setPen(black); + if (uy1 <= 1) paint.drawLine(1,1,x-3,1); + if (ux1 <= 1) paint.drawLine(1,2,1,y-3); + + paint.setPen(g.midlight()); + if (uy2 >= y-1) paint.drawLine(1,y-2,x-3,y-2); + if (ux2 >= x-1) paint.drawLine(x-2,1,x-2,y-2); + + paint.setPen(g.light()); + if (uy2 >= y) paint.drawLine(0,y-1,x-2,y-1); + if (ux2 >= x) paint.drawLine(x-1,0,x-1,y-1); + + x -= 2 + 16; + y -= 2 + 16; + if (ux2 > x && uy2 > y) { + paint.fillRect(x,y,16,16,g.background()); + } + paint.end(); +} + +void KateView::resizeEvent(QResizeEvent *) { + +// debug("Resize %d, %d",e->size().width(),e->size().height()); + +//myViewInternal->resize(width() -20, height() -20); + myViewInternal->tagAll(); + myViewInternal->updateView(0/*ufNoScroll*/); +} + + +// Applies a new pattern to the search context. +void SConfig::setPattern(QString &newPattern) { + bool regExp = (flags & KateView::sfRegularExpression); + + m_pattern = newPattern; + if (regExp) { + m_regExp.setCaseSensitive(flags & KateView::sfCaseSensitive); + m_regExp.setPattern(m_pattern); + } +} + +// Applies the search context to the given string, and returns whether a match was found. If one is, +// the length of the string matched is also returned. +int SConfig::search(QString &text, int index) { + bool regExp = (flags & KateView::sfRegularExpression); + bool caseSensitive = (flags & KateView::sfCaseSensitive); + + if (flags & KateView::sfBackward) { + if (regExp) { + index = text.findRev(m_regExp, index); + } + else { + index = text.findRev(m_pattern, index, caseSensitive); + } + } + else { + if (regExp) { + index = text.find(m_regExp, index); + } + else { + index = text.find(m_pattern, index, caseSensitive); + } + } + + // Work out the matched length. + if (index != -1) + { + if (regExp) { + m_regExp.match(text, index, &matchedLength, false); + } + else { + matchedLength = m_pattern.length(); + } + } + return index; +} + +void KateView::setActive (bool b) +{ + active = b; +} + +bool KateView::isActive () +{ + return active; +} + +void KateView::setFocus () +{ + QWidget::setFocus (); + + emit gotFocus (this); +} + +bool KateView::eventFilter (QObject *object, QEvent *event) +{ + + if ( (event->type() == QEvent::FocusIn) ) + emit gotFocus (this); + + if ( (event->type() == QEvent::KeyPress) ) + { + QKeyEvent * ke=(QKeyEvent *)event; + + if ((ke->key()==Qt::Key_Tab) || (ke->key()==Qt::Key_BackTab)) + { + myViewInternal->keyPressEvent(ke); + return true; + } + } + return QWidget::eventFilter (object, event); +} + +void KateView::findAgain (bool back) +{ + bool b= (searchFlags & sfBackward) > 0; + initSearch(s, (searchFlags & ((b==back)?~sfBackward:~0) & ~sfFromBeginning) // clear flag for forward searching + | sfPrompt | sfAgain | ((b!=back)?sfBackward:0) ); + if (s.flags & sfReplace) + replaceAgain(); + else + KateView::findAgain(s); +} + +void KateView::slotEditCommand () +{ +#warning fixme +/* + bool ok; + QString cmd = KLineEditDlg::getText("Editing Command", "", &ok, this); + + if (ok) + myDoc->cmd()->execCmd (cmd, this);*/ +} + +void KateView::setIconBorder (bool enable) +{ + myIconBorder = enable; + + if (myIconBorder) + { + myViewInternal->move(myViewInternal->iconBorderWidth+2, 2); + myViewInternal->leftBorder->show(); + } + else + { + myViewInternal->leftBorder->hide(); + myViewInternal->move(2, 2); + } +} + +void KateView::toggleIconBorder () +{ + setIconBorder (!myIconBorder); +} + +void KateView::gotoMark (Kate::Mark *mark) +{ + PointStruc cursor; + + cursor.x = 0; + cursor.y = mark->line; + myDoc->needPreHighlight(cursor.y); + myViewInternal->updateCursor(cursor); + myViewInternal->center(); + myViewInternal->updateView(KateView::ufUpdateOnScroll); + myDoc->updateViews(this); +} + +void KateView::toggleBookmark () +{ + TextLine::Ptr line = myDoc->getTextLine (currentLine()); + + if (line->mark()&KateDocument::Bookmark) + line->delMark(KateDocument::Bookmark); + else + line->addMark(KateDocument::Bookmark); + + myDoc->tagLines (currentLine(), currentLine()); + myDoc->updateViews(); +} + +void KateView::clearBookmarks() +{ + QList<Kate::Mark> list = myDoc->marks(); + for (int i=0; (uint) i < list.count(); i++) + { + if (list.at(i)->type&KateDocument::Bookmark) + { + myDoc->getTextLine(list.at(i)->line)->delMark(KateDocument::Bookmark); + myDoc->tagLines(list.at(i)->line, list.at(i)->line); + } + } + + myDoc->updateViews(); +} + +void KateView::bookmarkMenuAboutToShow() +{ +#warning fixme +#if 0 + bookmarkMenu->popupMenu()->clear (); + bookmarkToggle->plug (bookmarkMenu->popupMenu()); + bookmarkClear->plug (bookmarkMenu->popupMenu()); + bookmarkMenu->popupMenu()->insertSeparator (); + + list = myDoc->marks(); + for (int i=0; (uint) i < list.count(); i++) + { + if (list.at(i)->type&KateDocument::Bookmark) + { + QString bText = textLine(list.at(i)->line); + bText.truncate(32); + bText.append ("..."); + bookmarkMenu->popupMenu()->insertItem ( QString("%1 - \"%2\"").arg(list.at(i)->line).arg(bText), this, SLOT (gotoBookmark(int)), 0, i ); + } + } +#endif +} + +void KateView::gotoBookmark (int n) +{ + gotoMark (list.at(n)); +} + +int KateView::getHlCount () +{ + return HlManager::self()->highlights(); +} + +QString KateView::getHlName (int z) +{ + return HlManager::self()->hlName(z); +} + +QString KateView::getHlSection (int z) +{ + return HlManager::self()->hlSection (z); +} + +void KateView::slotIncFontSizes () +{ + QFont font = myDoc->getFont(); + font.setPointSize (font.pointSize()+2); + myDoc->setFont (font); +} + +void KateView::slotDecFontSizes () +{ + QFont font = myDoc->getFont(); + font.setPointSize (font.pointSize()-2); + myDoc->setFont (font); +} + +const char*bookmark_xpm[]={ +"12 16 4 1", +"b c #808080", +"a c #000080", +"# c #0000ff", +". c None", +"............", +"............", +"........###.", +".......#...a", +"......#.##.a", +".....#.#..aa", +"....#.#...a.", +"...#.#.a.a..", +"..#.#.a.a...", +".#.#.a.a....", +"#.#.a.a.....", +"#.#a.a...bbb", +"#...a..bbb..", +".aaa.bbb....", +"............", +"............"}; + +const char* breakpoint_xpm[]={ +"11 16 6 1", +"c c #c6c6c6", +". c None", +"# c #000000", +"d c #840000", +"a c #ffffff", +"b c #ff0000", +"...........", +"...........", +"...#####...", +"..#aaaaa#..", +".#abbbbbb#.", +"#abbbbbbbb#", +"#abcacacbd#", +"#abbbbbbbb#", +"#abcacacbd#", +"#abbbbbbbb#", +".#bbbbbbb#.", +"..#bdbdb#..", +"...#####...", +"...........", +"...........", +"..........."}; + +const char*breakpoint_bl_xpm[]={ +"11 16 7 1", +"a c #c0c0ff", +"# c #000000", +"c c #0000c0", +"e c #0000ff", +"b c #dcdcdc", +"d c #ffffff", +". c None", +"...........", +"...........", +"...#####...", +"..#ababa#..", +".#bcccccc#.", +"#acccccccc#", +"#bcadadace#", +"#acccccccc#", +"#bcadadace#", +"#acccccccc#", +".#ccccccc#.", +"..#cecec#..", +"...#####...", +"...........", +"...........", +"..........."}; + +const char*breakpoint_gr_xpm[]={ +"11 16 6 1", +"c c #c6c6c6", +"d c #2c2c2c", +"# c #000000", +". c None", +"a c #ffffff", +"b c #555555", +"...........", +"...........", +"...#####...", +"..#aaaaa#..", +".#abbbbbb#.", +"#abbbbbbbb#", +"#abcacacbd#", +"#abbbbbbbb#", +"#abcacacbd#", +"#abbbbbbbb#", +".#bbbbbbb#.", +"..#bdbdb#..", +"...#####...", +"...........", +"...........", +"..........."}; + +const char*ddd_xpm[]={ +"11 16 4 1", +"a c #00ff00", +"b c #000000", +". c None", +"# c #00c000", +"...........", +"...........", +"...........", +"#a.........", +"#aaa.......", +"#aaaaa.....", +"#aaaaaaa...", +"#aaaaaaaaa.", +"#aaaaaaa#b.", +"#aaaaa#b...", +"#aaa#b.....", +"#a#b.......", +"#b.........", +"...........", +"...........", +"..........."}; + + + +KateIconBorder::KateIconBorder(KateView *view, KateViewInternal *internalView) + : QWidget(view), myView(view), myInternalView(internalView) +{ + lmbSetsBreakpoints = true; +} + +KateIconBorder::~KateIconBorder() +{ +} + +void KateIconBorder::paintLine(int i) +{ + if (!myView->myIconBorder) return; + + QPainter p(this); + + int fontHeight = myView->doc()->fontHeight; + int y = i*fontHeight - myInternalView->yPos; + p.fillRect(0, y, myInternalView->iconBorderWidth-2, fontHeight, colorGroup().background()); + p.setPen(white); + p.drawLine(myInternalView->iconBorderWidth-2, y, myInternalView->iconBorderWidth-2, y + fontHeight); + p.setPen(QColor(colorGroup().background()).dark()); + p.drawLine(myInternalView->iconBorderWidth-1, y, myInternalView->iconBorderWidth-1, y + fontHeight); + + TextLine *line = myView->doc()->getTextLine(i); + if (!line) + return; + + if (line->mark()&KateDocument::Bookmark) + p.drawPixmap(2, y, QPixmap(bookmark_xpm)); /* + if (line && (line->breakpointId() != -1)) { + if (!line->breakpointEnabled()) + p.drawPixmap(2, y, QPixmap(breakpoint_gr_xpm)); + else if (line->breakpointPending()) + p.drawPixmap(2, y, QPixmap(breakpoint_bl_xpm)); + else + p.drawPixmap(2, y, QPixmap(breakpoint_xpm)); + } + if (line->isExecutionPoint()) + p.drawPixmap(2, y, QPixmap(ddd_xpm)); */ +} + + +void KateIconBorder::paintEvent(QPaintEvent* e) +{ + if (!myView->myIconBorder) return; + + int lineStart = 0; + int lineEnd = 0; + + QRect updateR = e->rect(); + + KateDocument *doc = myView->doc(); + int h = doc->fontHeight; + int yPos = myInternalView->yPos; + if (h) { + lineStart = (yPos + updateR.y()) / h; + lineEnd = QMAX((yPos + updateR.y() + updateR.height()) / h, (int)doc->numLines()); + } + + for(int i = lineStart; i <= lineEnd; ++i) + paintLine(i); +} + + +void KateIconBorder::mousePressEvent(QMouseEvent* e) +{ + myInternalView->placeCursor( 0, e->y(), 0 ); + + KateDocument *doc = myView->doc(); + int cursorOnLine = (e->y() + myInternalView->yPos) / doc->fontHeight; + TextLine *line = doc->getTextLine(cursorOnLine); + + switch (e->button()) { + case LeftButton: + if (!line) + break; + else + { + if (line->mark()&KateDocument::Bookmark) + line->delMark (KateDocument::Bookmark); + else + line->addMark (KateDocument::Bookmark); + + doc->tagLines(cursorOnLine, cursorOnLine); + doc->updateViews(); + } + break; + /* case RightButton: + { + if (!line) + break; + KPopupMenu popup; + popup.setCheckable(true); + popup.insertTitle(i18n("Breakpoints/Bookmarks")); + int idToggleBookmark = popup.insertItem(i18n("Toggle bookmark")); + popup.insertSeparator(); + int idToggleBreakpoint = popup.insertItem(i18n("Toggle breakpoint")); + int idEditBreakpoint = popup.insertItem(i18n("Edit breakpoint")); + int idEnableBreakpoint = popup.insertItem(i18n("Disable breakpoint")); + popup.insertSeparator(); + popup.insertSeparator(); + int idLmbSetsBreakpoints = popup.insertItem(i18n("LMB sets breakpoints")); + int idLmbSetsBookmarks = popup.insertItem(i18n("LMB sets bookmarks")); + + popup.setItemChecked(idLmbSetsBreakpoints, lmbSetsBreakpoints); + popup.setItemChecked(idLmbSetsBookmarks, !lmbSetsBreakpoints); + + if (line->breakpointId() == -1) { + popup.setItemEnabled(idEditBreakpoint, false); + popup.setItemEnabled(idEnableBreakpoint, false); + popup.changeItem(idEnableBreakpoint, i18n("Enable breakpoint")); + } + int res = popup.exec(mapToGlobal(e->pos())); + if (res == idToggleBookmark) { + line->toggleBookmark(); + doc->tagLines(cursorOnLine, cursorOnLine); + doc->updateViews(); + } else if (res == idToggleBreakpoint) + emit myView->toggledBreakpoint(cursorOnLine); + else if (res == idEditBreakpoint) + emit myView->editedBreakpoint(cursorOnLine); + else if (res == idEnableBreakpoint) + emit myView->toggledBreakpointEnabled(cursorOnLine+1); + else if (res == idLmbSetsBreakpoints || res == idLmbSetsBookmarks) + lmbSetsBreakpoints = !lmbSetsBreakpoints; + break; + } + case MidButton: + line->toggleBookmark(); + doc->tagLines(cursorOnLine, cursorOnLine); + doc->updateViews(); + break; */ + default: + break; + } +} + + + diff --git a/noncore/apps/tinykate/libkate/view/kateview.h b/noncore/apps/tinykate/libkate/view/kateview.h new file mode 100644 index 0000000..2e78a3a --- a/dev/null +++ b/noncore/apps/tinykate/libkate/view/kateview.h @@ -0,0 +1,865 @@ +/*************************************************************************** + kateview.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_view_h +#define kate_view_h + +#include "../interfaces/view.h" +#include "../interfaces/document.h" + +#include <qlist.h> +#include <qstring.h> +#include <qdialog.h> + + +class KateDocument; +class Highlight; + +/* +//dialog results +const int srYes = QDialog::Accepted; +const int srNo = 10; +const int srAll = 11; +const int srCancel = QDialog::Rejected; +*/ +// --- config flags --- +// indent + +enum Select_flags { + selectFlag = 0x100000, + multiSelectFlag = 0x200000 +}; +//state commands +enum State_commands { + cmToggleInsert = 1, + cmToggleVertical = 2 +}; + +class KateViewInternal; +class KateView; + +struct PointStruc { + int x; + int y; +}; + +struct VConfig { + KateView *view; + PointStruc cursor; + int cXPos; + int flags; +}; + +struct SConfig { + PointStruc cursor; + PointStruc startCursor; + int flags; + + // Set the pattern to be used for searching. + void setPattern(QString &newPattern); + + // Search the given string. + int search(QString &text, int index); + + // The length of the last match found using pattern or regExp. + int matchedLength; + +private: + QString m_pattern; + + // The regular expression corresponding to pattern. Only guaranteed valid if + // flags has sfRegularExpression set. + QRegExp m_regExp; +}; + +struct LineRange { + int start; + int end; +}; + +struct BracketMark { + PointStruc cursor; + int sXPos; + int eXPos; +}; + + +class KateIconBorder : public QWidget +{ +public: + KateIconBorder(KateView *view, class KateViewInternal *internalView); + ~KateIconBorder(); + + void paintLine(int i); + +protected: + void paintEvent(QPaintEvent* e); + void mousePressEvent(QMouseEvent* e); + +private: + + KateView *myView; + class KateViewInternal *myInternalView; + bool lmbSetsBreakpoints; +}; + +class KateViewInternal : public QWidget { + Q_OBJECT + friend class KateDocument; + friend class KateView; + friend class KateIconBorder; + + private: + long waitForPreHighlight; + int iconBorderWidth; + int iconBorderHeight; + + protected slots: + void slotPreHighlightUpdate(long line); + + public: + KateViewInternal(KateView *view, KateDocument *doc); + ~KateViewInternal(); + + virtual void doCursorCommand(VConfig &, int cmdNum); + virtual void doEditCommand(VConfig &, int cmdNum); + + void cursorLeft(VConfig &); + void cursorRight(VConfig &); + void wordLeft(VConfig &); + void wordRight(VConfig &); + void home(VConfig &); + void end(VConfig &); + void cursorUp(VConfig &); + void cursorDown(VConfig &); + void scrollUp(VConfig &); + void scrollDown(VConfig &); + void topOfView(VConfig &); + void bottomOfView(VConfig &); + void pageUp(VConfig &); + void pageDown(VConfig &); + void cursorPageUp(VConfig &); + void cursorPageDown(VConfig &); + void top(VConfig &); + void bottom(VConfig &); + void top_home(VConfig &c); + void bottom_end(VConfig &c); + + protected slots: + void changeXPos(int); + void changeYPos(int); + + protected: + void getVConfig(VConfig &); + void changeState(VConfig &); + void insLine(int line); + void delLine(int line); + void updateCursor(); + void updateCursor(PointStruc &newCursor); + void updateCursor(PointStruc &newCursor, int flags); + void clearDirtyCache(int height); + void tagLines(int start, int end, int x1, int x2); + void tagAll(); + void setPos(int x, int y); + void center(); + + void updateView(int flags); + + void paintTextLines(int xPos, int yPos); + void paintCursor(); + void paintBracketMark(); + + void placeCursor(int x, int y, int flags = 0); + bool isTargetSelected(int x, int y); + +// void doDrag(); + + virtual void focusInEvent(QFocusEvent *); + virtual void focusOutEvent(QFocusEvent *); + virtual void keyPressEvent(QKeyEvent *e); + virtual void mousePressEvent(QMouseEvent *); + virtual void mouseDoubleClickEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void wheelEvent( QWheelEvent *e ); + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); + virtual void timerEvent(QTimerEvent *); + + + KateView *myView; + KateDocument *myDoc; + QScrollBar *xScroll; + QScrollBar *yScroll; + KateIconBorder *leftBorder; + + int xPos; + int yPos; + + int mouseX; + int mouseY; + int scrollX; + int scrollY; + int scrollTimer; + + PointStruc cursor; + bool cursorOn; + int cursorTimer; + int cXPos; + int cOldXPos; + + int startLine; + int endLine; + + bool exposeCursor; + int updateState; + int numLines; + LineRange *lineRanges; + int newXPos; + int newYPos; + + QPixmap *drawBuffer; + + BracketMark bm; + +}; + +/** + The KateView text editor widget. It has many options, document/view + architecture and syntax highlight. + @author Jochen Wilhelmy +*/ + +class KateView : public Kate::View +{ + Q_OBJECT + friend class KateViewInternal; + friend class KateDocument; + friend class KateIconBorder; + + public: + KateView(KateDocument *doc=0L, QWidget *parent = 0L, const char * name = 0); + ~KateView(); + + virtual void setCursorPosition( int line, int col, bool mark = false ); + virtual void getCursorPosition( int *line, int *col ); + + virtual bool isOverwriteMode() const; + virtual void setOverwriteMode( bool b ); + +//status and config functions + /** + Returns the current line number, that is the line the cursor is on. + For the first line it returns 0. Signal newCurPos() is emitted on + cursor position changes. + */ + int currentLine(); + /** + Returns the current column number. It handles tab's correctly. + For the first column it returns 0. + */ + int currentColumn(); + /** + Returns the number of the character, that the cursor is on (cursor x) + */ + int currentCharNum(); + /** + Sets the current cursor position + */ + void setCursorPositionInternal(int line, int col); + /** + Returns the config flags. See the cfXXX constants in the .h file. + */ + int config();// {return configFlags;} + /** + Sets the config flags + */ + void setConfig(int); + + int tabWidth(); + void setTabWidth(int); + void setEncoding (QString e); + int undoSteps(); + void setUndoSteps(int); + + // bool isOverwriteMode(); + /** + Returns true if the document is in read only mode. + */ + bool isReadOnly(); + /** + Returns true if the document has been modified. + */ + bool isModified(); + /** + Sets the read-only flag of the document + */ + void setReadOnly(bool); + /** + Sets the modification status of the document + */ + void setModified(bool m = true); + /** + Returns true if this editor is the only owner of its document + */ + bool isLastView(); + /** + Returns the document object + */ + KateDocument *doc(); + + /* + Bit 0 : undo possible, Bit 1 : redo possible. + Used to enable/disable undo/redo menu items and toolbar buttons + */ + int undoState(); + /** + Returns the type of the next undo group. + */ + int nextUndoType(); + /** + Returns the type of the next redo group. + */ + int nextRedoType(); + /** + Returns a list of all available undo types, in undo order. + */ + void undoTypeList(QValueList<int> &lst); + /** + Returns a list of all available redo types, in redo order. + */ + void redoTypeList(QValueList<int> &lst); + /** + Returns a short text description of the given undo type, + which is obtained with nextUndoType(), nextRedoType(), undoTypeList(), and redoTypeList(), + suitable for display in a menu entry. It is not translated; + use i18n() before displaying this string. + */ + const char * undoTypeName(int undoType); + + QColor* getColors(); + void applyColors(); + + + public slots: + void slotUpdate(); + void slotFileStatusChanged(); + void slotNewUndo(); + void slotHighlightChanged(); + + public slots: + /** + Toggles Insert mode + */ + void toggleInsert(); + /** + Toggles "Vertical Selections" option + */ + void toggleVertical(); + signals: + /** + The cursor position has changed. Get the values with currentLine() + and currentColumn() + */ + void newCurPos(); + /** + Modified flag or config flags have changed + */ + void newStatus(); + /** + The undo/redo enable status has changed + */ + void newUndo(); + /** + The marked text state has changed. This can be used to enable/disable + cut and copy + */ + void newMarkStatus(); + + // emitted when saving a remote URL with KIO::NetAccess. In that case we have to disable the UI. + void enableUI( bool enable ); + + protected: + virtual void keyPressEvent( QKeyEvent *ev ); + + int configFlags; + + /* + * Check if the given URL already exists. Currently used by both save() and saveAs() + * + * Asks the user for permission and returns the message box result and defaults to + * KMessageBox::Yes in case of doubt + */ + +//text access + public: + /** + Gets the number of text lines; + */ + int numLines(); + /** + Gets the complete document content as string + */ + QString text(); + /** + Gets the text line where the cursor is on + */ + QString currentTextLine(); + /** + Gets a text line + */ + QString textLine(int num); + /** + Gets the word where the cursor is on + */ + QString currentWord(); + /** + Gets the word at position x, y. Can be used to find + the word under the mouse cursor + */ + QString word(int x, int y); + /** + Discard old text without warning and set new text + */ + void setText(const QString &); + /** + Insert text at the current cursor position. If length is a positive + number, it restricts the number of inserted characters + */ + virtual void insertText(const QString &, bool mark = false); + /** + Queries if there is marked text + */ + bool hasMarkedText(); + /** + Gets the marked text as string + */ + QString markedText(); + + public: + enum fileResult { OK, CANCEL, RETRY, ERROR }; + + /** + Returns true if the current document can be + discarded. If the document is modified, the user is asked if he wants + to save it. On "cancel" the function returns false. + */ + bool canDiscard(); + + public slots: + /** + Flushes the document of the text widget. The user is given + a chance to save the current document if the current document has + been modified. + */ + void flush (); + /** + Saves the file if necessary under the current file name. If the current file + name is Untitled, as it is after a call to newFile(), this routing will + call saveAs(). + */ + fileResult save(); + /** + Allows the user to save the file under a new name. This starts the + automatic highlight selection. + */ + fileResult saveAs(); + /** + Moves the marked text into the clipboard + */ + void cut() {doEditCommand(KateView::cmCut);} + /** + Copies the marked text into the clipboard + */ + void copy() {doEditCommand(KateView::cmCopy);} + /** + Inserts text from the clipboard at the actual cursor position + */ + void paste() {doEditCommand(KateView::cmPaste);} + /** + Undoes the last operation. The number of undo steps is configurable + */ + void undo() {doEditCommand(KateView::cmUndo);} + /** + Repeats an operation which has been undone before. + */ + void redo() {doEditCommand(KateView::cmRedo);} + /** + Undoes <count> operations. + Called by slot undo(). + */ + void undoMultiple(int count); + /** + Repeats <count> operation which have been undone before. + Called by slot redo(). + */ + void redoMultiple(int count); + /** + Displays the undo history dialog + */ + void undoHistory(); + /** + Moves the current line or the selection one position to the right + */ + void indent() {doEditCommand(KateView::cmIndent);}; + /** + Moves the current line or the selection one position to the left + */ + void unIndent() {doEditCommand(KateView::cmUnindent);}; + /** + Optimizes the selected indentation, replacing tabs and spaces as needed + */ + void cleanIndent() {doEditCommand(KateView::cmCleanIndent);}; + /** + Selects all text + */ + void selectAll() {doEditCommand(KateView::cmSelectAll);} + /** + Deselects all text + */ + void deselectAll() {doEditCommand(KateView::cmDeselectAll);} + /** + Inverts the current selection + */ + void invertSelection() {doEditCommand(KateView::cmInvertSelection);} + /** + comments out current line + */ + void comment() {doEditCommand(KateView::cmComment);}; + /** + removes comment signs in the current line + */ + void uncomment() {doEditCommand(KateView::cmUncomment);}; + + void keyReturn() {doEditCommand(KateView::cmReturn);}; + void keyDelete() {doEditCommand(KateView::cmDelete);}; + void backspace() {doEditCommand(KateView::cmBackspace);}; + void killLine() {doEditCommand(KateView::cmKillLine);}; + +// cursor commands... + + void cursorLeft() {doCursorCommand(KateView::cmLeft);}; + void shiftCursorLeft() {doCursorCommand(KateView::cmLeft | selectFlag);}; + void cursorRight() {doCursorCommand(KateView::cmRight);} + void shiftCursorRight() {doCursorCommand(KateView::cmRight | selectFlag);} + void wordLeft() {doCursorCommand(KateView::cmWordLeft);}; + void shiftWordLeft() {doCursorCommand(KateView::cmWordLeft | selectFlag);}; + void wordRight() {doCursorCommand(KateView::cmWordRight);}; + void shiftWordRight() {doCursorCommand(KateView::cmWordRight | selectFlag);}; + void home() {doCursorCommand(KateView::cmHome);}; + void shiftHome() {doCursorCommand(KateView::cmHome | selectFlag);}; + void end() {doCursorCommand(KateView::cmEnd);}; + void shiftEnd() {doCursorCommand(KateView::cmEnd | selectFlag);}; + void up() {doCursorCommand(KateView::cmUp);}; + void shiftUp() {doCursorCommand(KateView::cmUp | selectFlag);}; + void down() {doCursorCommand(KateView::cmDown);}; + void shiftDown() {doCursorCommand(KateView::cmDown | selectFlag);}; + void scrollUp() {doCursorCommand(KateView::cmScrollUp);}; + void scrollDown() {doCursorCommand(KateView::cmScrollDown);}; + void topOfView() {doCursorCommand(KateView::cmTopOfView);}; + void bottomOfView() {doCursorCommand(KateView::cmBottomOfView);}; + void pageUp() {doCursorCommand(KateView::cmPageUp);}; + void shiftPageUp() {doCursorCommand(KateView::cmPageUp | selectFlag);}; + void pageDown() {doCursorCommand(KateView::cmPageDown);}; + void shiftPageDown() {doCursorCommand(KateView::cmPageDown | selectFlag);}; + void top() {doCursorCommand(KateView::cmTop);}; + void shiftTop() {doCursorCommand(KateView::cmTop | selectFlag);}; + void bottom() {doCursorCommand(KateView::cmBottom);}; + void shiftBottom() {doCursorCommand(KateView::cmBottom | selectFlag);}; + +//search/replace functions + public slots: + /** + Presents a search dialog to the user + */ + void find(); + /** + Presents a replace dialog to the user + */ + void replace(); + + /** + Presents a "Goto Line" dialog to the user + */ + void gotoLine(); + protected: + void initSearch(SConfig &, int flags); + void continueSearch(SConfig &); + void findAgain(SConfig &); + void replaceAgain(); + void doReplaceAction(int result, bool found = false); + void exposeFound(PointStruc &cursor, int slen, int flags, bool replace); + void deleteReplacePrompt(); + bool askReplaceEnd(); + protected slots: + void replaceSlot(); + protected: + int searchFlags; + int replaces; + SConfig s; + QDialog *replacePrompt; + +//right mouse button popup menu & bookmark menu + public: + /** + Install a Popup Menu. The Popup Menu will be activated on + a right mouse button press event. + */ + void installPopup(QPopupMenu *rmb_Menu); + + protected: + QPopupMenu *rmbMenu; + + signals: + void bookAddChanged(bool enabled); + void bookClearChanged(bool enabled); + +//config file / session management functions + public: + /** + Reads config entries + */ + void readConfig(); + /** + Writes config entries i + */ + void writeConfig(); + /** + Reads session config out of the KConfig object. This also includes + the actual cursor position and the bookmarks. + */ + void readSessionConfig(KConfig *); + /** + Writes session config into the KConfig object + */ + void writeSessionConfig(KConfig *); + + + public: + void setDontChangeHlOnSave(); + + + // syntax highlight + public slots: + /** + Presents the setup dialog to the user + */ + void configDialog (); + /** + Gets the highlight number + */ + int getHl(); + /** + Sets the highlight number n + */ + void setHl(int n); + /** + Get the end of line mode (Unix, Macintosh or Dos) + */ + int getEol(); + /** + Set the end of line mode (Unix, Macintosh or Dos) + */ + void setEol(int); + +//internal + protected: + virtual void paintEvent(QPaintEvent *); + virtual void resizeEvent(QResizeEvent *); + + void doCursorCommand(int cmdNum); + void doEditCommand(int cmdNum); + + KateViewInternal *myViewInternal; + KateDocument *myDoc; + + + // some kwriteview stuff + protected: + void insLine(int line) { myViewInternal->insLine(line); }; + void delLine(int line) { myViewInternal->delLine(line); }; + void updateCursor() { myViewInternal->updateCursor(); }; + void updateCursor(PointStruc &newCursor) { myViewInternal->updateCursor(newCursor); }; + void updateCursor(PointStruc &newCursor, int flags) { myViewInternal->updateCursor(newCursor, flags); }; + + void clearDirtyCache(int height) { myViewInternal->clearDirtyCache(height); }; + void tagLines(int start, int end, int x1, int x2) { myViewInternal->tagLines(start, end, x1, x2); }; + void tagAll() { myViewInternal->tagAll(); }; + void setPos(int x, int y) { myViewInternal->setPos(x, y); }; + void center() { myViewInternal->center(); }; + + void updateView(int flags) { myViewInternal->updateView(flags); }; + + + + public: + enum Config_flags { + cfAutoIndent= 0x1, + cfBackspaceIndents= 0x2, + cfWordWrap= 0x4, + cfReplaceTabs= 0x8, + cfRemoveSpaces = 0x10, + cfWrapCursor= 0x20, + cfAutoBrackets= 0x40, + cfPersistent= 0x80, + cfKeepSelection= 0x100, + cfVerticalSelect= 0x200, + cfDelOnInput= 0x400, + cfXorSelect= 0x800, + cfOvr= 0x1000, + cfMark= 0x2000, + cfGroupUndo= 0x4000, + cfKeepIndentProfile= 0x8000, + cfKeepExtraSpaces= 0x10000, + cfMouseAutoCopy= 0x20000, + cfSingleSelection= 0x40000, + cfTabIndents= 0x80000, + cfPageUDMovesCursor= 0x100000, + cfShowTabs= 0x200000, + cfSpaceIndent= 0x400000, + cfSmartHome = 0x800000}; + + enum Dialog_results { + srYes=QDialog::Accepted, + srNo=10, + srAll, + srCancel=QDialog::Rejected}; + +//search flags + enum Search_flags { + sfCaseSensitive=1, + sfWholeWords=2, + sfFromBeginning=4, + sfBackward=8, + sfSelected=16, + sfPrompt=32, + sfReplace=64, + sfAgain=128, + sfWrapped=256, + sfFinished=512, + sfRegularExpression=1024}; + +//update flags + enum Update_flags { + ufDocGeometry=1, + ufUpdateOnScroll=2, + ufPos=4}; + +//load flags + enum Load_flags { + lfInsert=1, + lfNewFile=2, + lfNoAutoHl=4}; + +//cursor movement commands + enum Cursor_commands + { cmLeft,cmRight,cmWordLeft,cmWordRight, + cmHome,cmEnd,cmUp,cmDown, + cmScrollUp,cmScrollDown,cmTopOfView,cmBottomOfView, + cmPageUp,cmPageDown,cmCursorPageUp,cmCursorPageDown, + cmTop,cmBottom}; +//edit commands + enum Edit_commands { + cmReturn=1,cmDelete,cmBackspace,cmKillLine,cmUndo, + cmRedo,cmCut,cmCopy,cmPaste,cmIndent,cmUnindent,cmCleanIndent, + cmSelectAll,cmDeselectAll,cmInvertSelection,cmComment, + cmUncomment}; +//find commands + enum Find_commands { cmFind=1,cmReplace,cmFindAgain,cmGotoLine}; + + public: + void setActive (bool b); + bool isActive (); + + private: + bool active; + bool myIconBorder; + QList<Kate::Mark> list; + + public slots: + virtual void setFocus (); + void findAgain(bool back=false); + void findAgain () { findAgain(false); }; + void findPrev () { findAgain(true); }; + + protected: + bool eventFilter(QObject* o, QEvent* e); + + signals: + void gotFocus (KateView *); + + public slots: + void slotEditCommand (); + void setIconBorder (bool enable); + void toggleIconBorder (); + void gotoMark (Kate::Mark *mark); + void toggleBookmark (); + void clearBookmarks (); + + public: + bool iconBorder() { return myIconBorder; } ; + + private slots: + void bookmarkMenuAboutToShow(); + void gotoBookmark (int n); + + public: + Kate::Document *getDoc () + { return (Kate::Document*) myDoc; }; + + public slots: + int getHlCount (); + QString getHlName (int); + QString getHlSection (int); + + void slotIncFontSizes (); + void slotDecFontSizes (); + + protected: + uint myViewID; + static uint uniqueID; +}; + +#endif + + + + + + diff --git a/noncore/apps/tinykate/libkate/view/kateviewdialog.cpp b/noncore/apps/tinykate/libkate/view/kateviewdialog.cpp new file mode 100644 index 0000000..a311042 --- a/dev/null +++ b/noncore/apps/tinykate/libkate/view/kateviewdialog.cpp @@ -0,0 +1,556 @@ +/*************************************************************************** + kateviewdialog.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. * + * * + ***************************************************************************/ +// Dialogs + +#include <stdio.h> +#include <stdlib.h> + +#include <qgrid.h> +#include <qlabel.h> +#include <qlayout.h> +#include <qlistbox.h> +#include <qspinbox.h> +#include <qcombobox.h> +#include <qgroupbox.h> +#include <qlineedit.h> +#include <qcheckbox.h> +#include <qcollection.h> +#include <qpushbutton.h> +#include <qobjectlist.h> +#include <qradiobutton.h> +#include <qwhatsthis.h> +#include <qstringlist.h> +#include <klocale.h> +#include <kcolorbtn.h> +#include <qcombobox.h> +#include <kglobal.h> +#include <qvbox.h> +#include <qspinbox.h> +#include <kfontdialog.h> + +#include "../document/katedocument.h" +#include "kateviewdialog.h" + +SearchDialog::SearchDialog( QWidget *parent, QStringList &searchFor, QStringList &replaceWith, int flags ) + : KDialogBase( parent, 0L, true, i18n( "Find Text" ), Ok | Cancel, Ok ) + , m_replace( 0L ) +{ + QWidget *page = new QWidget( this ); + setMainWidget( page ); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + + m_search = new QComboBox( true, page ); + m_search->insertStringList( searchFor ); + m_search->setMinimumWidth( m_search->sizeHint().width() ); + m_search->lineEdit()->selectAll(); + QLabel *label = new QLabel( m_search, i18n( "&Text To Find:" ), page ); + m_optRegExp = new QCheckBox( i18n( "Regular Expression" ), page ); + topLayout->addWidget( label ); + topLayout->addWidget( m_search ); + topLayout->addWidget( m_optRegExp ); + + if( flags & KateView::sfReplace ) + { + // make it a replace dialog + setCaption( i18n( "Replace Text" ) ); + m_replace = new QComboBox( true, page ); + m_replace->insertStringList( replaceWith ); + m_replace->setMinimumWidth( m_search->sizeHint().width() ); + label = new QLabel( m_replace, i18n( "&Replace With:" ), page ); + //m_optPlaceholders = new QCheckBox( i18n( "&Use Placeholders" ), page ); + topLayout->addWidget( label ); + topLayout->addWidget( m_replace ); + //topLayout->addWidget( m_optPlaceholders ); + } + + QGroupBox *group = new QGroupBox( i18n( "Options" ), page ); + topLayout->addWidget( group, 10 ); + + QGridLayout *gbox = new QGridLayout( group, 5, 2, spacingHint() ); + gbox->addRowSpacing( 0, fontMetrics().lineSpacing() ); + gbox->setRowStretch( 4, 10 ); + + m_opt1 = new QCheckBox( i18n( "C&ase Sensitive" ), group ); + gbox->addWidget( m_opt1, 1, 0 ); + + m_opt2 = new QCheckBox(i18n("&Whole Words Only" ), group ); + gbox->addWidget( m_opt2, 2, 0 ); + + m_opt3 = new QCheckBox(i18n("&From Beginning" ), group ); + gbox->addWidget( m_opt3, 3, 0 ); + + m_opt4 = new QCheckBox(i18n("Find &Backwards" ), group ); + gbox->addWidget( m_opt4, 1, 1 ); + + m_opt5 = new QCheckBox(i18n("&Selected Text" ), group ); + gbox->addWidget( m_opt5, 2, 1 ); + + m_opt1->setChecked( flags & KateView::sfCaseSensitive ); + m_opt2->setChecked( flags & KateView::sfWholeWords ); + m_opt3->setChecked( flags & KateView::sfFromBeginning ); + m_optRegExp->setChecked( flags & KateView::sfRegularExpression ); + m_opt4->setChecked( flags & KateView::sfBackward ); + m_opt5->setChecked( flags & KateView::sfSelected ); + + if( m_replace ) + { + m_opt6 = new QCheckBox( i18n( "&Prompt On Replace" ), group ); + m_opt6->setChecked( flags & KateView::sfPrompt ); + gbox->addWidget( m_opt6, 3, 1 ); + } + + m_search->setFocus(); +} + +QString SearchDialog::getSearchFor() +{ + return m_search->currentText(); +} + +QString SearchDialog::getReplaceWith() +{ + return m_replace->currentText(); +} + +int SearchDialog::getFlags() +{ + int flags = 0; + + if( m_opt1->isChecked() ) flags |= KateView::sfCaseSensitive; + if( m_opt2->isChecked() ) flags |= KateView::sfWholeWords; + if( m_opt3->isChecked() ) flags |= KateView::sfFromBeginning; + if( m_opt4->isChecked() ) flags |= KateView::sfBackward; + if( m_opt5->isChecked() ) flags |= KateView::sfSelected; + if( m_optRegExp->isChecked() ) flags |= KateView::sfRegularExpression; + if( m_replace ) + { + if( m_opt6->isChecked() ) + flags |= KateView::sfPrompt; + + flags |= KateView::sfReplace; + } + + return flags; +} + +void SearchDialog::slotOk() +{ + if ( !m_search->currentText().isEmpty() ) + { + if ( !m_optRegExp->isChecked() ) + { + accept(); + } + else + { + // Check for a valid regular expression. + + QRegExp regExp( m_search->currentText() ); + + if ( regExp.isValid() ) + accept(); + } + } +} + +void SearchDialog::setSearchText( const QString &searchstr ) + { + m_search->insertItem( searchstr, 0 ); + m_search->setCurrentItem( 0 ); + m_search->lineEdit()->selectAll(); + } + +// this dialog is not modal +ReplacePrompt::ReplacePrompt( QWidget *parent ) + : KDialogBase(parent, 0L, false, i18n( "Replace Text" ), + User3 | User2 | User1 | Close, User3, true, + i18n("&All"), i18n("&No"), i18n("&Yes")) { + + QWidget *page = new QWidget(this); + setMainWidget(page); + + QBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + QLabel *label = new QLabel(i18n("Replace this occurence?"),page); + topLayout->addWidget(label ); +} + +void ReplacePrompt::slotUser1( void ) { // All + done(KateView::srAll); +} + +void ReplacePrompt::slotUser2( void ) { // No + done(KateView::srNo); +} + +void ReplacePrompt::slotUser3( void ) { // Yes + accept(); +} + +void ReplacePrompt::done(int r) { + setResult(r); + emit clicked(); +} + +void ReplacePrompt::closeEvent(QCloseEvent *) { + reject(); +} + +GotoLineDialog::GotoLineDialog(QWidget *parent, int line, int max) + : KDialogBase(parent, 0L, true, i18n("Goto Line"), Ok | Cancel, Ok) { + + QWidget *page = new QWidget(this); + setMainWidget(page); + + QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() ); + e1 = new QSpinBox(page); + e1->setMinValue(1); + e1->setMaxValue(max); + e1->setValue((int)line); + + QLabel *label = new QLabel( e1,i18n("&Goto Line:"), page ); + topLayout->addWidget(label); + topLayout->addWidget(e1); + topLayout->addSpacing(spacingHint()); // A little bit extra space + topLayout->addStretch(10); + e1->setFocus(); +} + +int GotoLineDialog::getLine() { + return e1->value(); +} + +const int IndentConfigTab::flags[] = {KateView::cfAutoIndent, KateView::cfSpaceIndent, + KateView::cfBackspaceIndents,KateView::cfTabIndents, KateView::cfKeepIndentProfile, KateView::cfKeepExtraSpaces}; + +IndentConfigTab::IndentConfigTab(QWidget *parent, KateView *view) + : QWidget(parent, 0L) +{ + QVBoxLayout *layout = new QVBoxLayout(this, 0, KDialog::spacingHint() ); + int configFlags = view->config(); + + opt[0] = new QCheckBox(i18n("&Auto Indent"), this); + layout->addWidget(opt[0], 0, AlignLeft); + opt[0]->setChecked(configFlags & flags[0]); + + opt[1] = new QCheckBox(i18n("Indent With &Spaces"), this); + layout->addWidget(opt[1], 0, AlignLeft); + opt[1]->setChecked(configFlags & flags[1]); + + opt[2] = new QCheckBox(i18n("&Backspace Key Indents"), this); + layout->addWidget(opt[2], 0, AlignLeft); + opt[2]->setChecked(configFlags & flags[2]); + + opt[3] = new QCheckBox(i18n("&Tab Key Indents"), this); + layout->addWidget(opt[3], 0, AlignLeft); + opt[3]->setChecked(configFlags & flags[3]); + + opt[4] = new QCheckBox(i18n("Keep Indent &Profile"), this); + layout->addWidget(opt[4], 0, AlignLeft); +// opt[4]->setChecked(configFlags & flags[4]); + opt[4]->setChecked(true); + opt[4]->hide(); + + opt[5] = new QCheckBox(i18n("&Keep Extra Spaces"), this); + layout->addWidget(opt[5], 0, AlignLeft); + opt[5]->setChecked(configFlags & flags[5]); + + layout->addStretch(); + + // What is this? help + QWhatsThis::add(opt[0], i18n("When <b>Auto indent</b> is on, KateView will indent new lines to equal the indent on the previous line.<p>If the previous line is blank, the nearest line above with text is used")); + QWhatsThis::add(opt[1], i18n("Check this if you want to indent with spaces rather than tabs.<br>A Tab will be converted to <u>Tab-width</u> as set in the <b>edit</b> options")); + QWhatsThis::add(opt[2], i18n("This allows the <b>backspace</b> key to be used to indent.")); + QWhatsThis::add(opt[3], i18n("This allows the <b>tab</b> key to be used to indent.")); + QWhatsThis::add(opt[4], i18n("This retains current indentation settings for future documents.")); + QWhatsThis::add(opt[5], i18n("Indentations of more than the selected number of spaces will not be shortened.")); +} + +void IndentConfigTab::getData(KateView *view) { + int configFlags, z; + + configFlags = view->config(); + for (z = 0; z < numFlags; z++) { + configFlags &= ~flags[z]; + if (opt[z]->isChecked()) configFlags |= flags[z]; + } + view->setConfig(configFlags); +} + +const int SelectConfigTab::flags[] = {KateView::cfPersistent, KateView::cfDelOnInput, + KateView::cfMouseAutoCopy, KateView::cfSingleSelection, KateView::cfVerticalSelect, KateView::cfXorSelect}; + +SelectConfigTab::SelectConfigTab(QWidget *parent, KateView *view) + : QWidget(parent, 0L) +{ + QVBoxLayout *layout = new QVBoxLayout(this, 0, KDialog::spacingHint() ); + int configFlags = view->config(); + + opt[0] = new QCheckBox(i18n("&Persistent Selections"), this); + layout->addWidget(opt[0], 0, AlignLeft); + opt[0]->setChecked(configFlags & flags[0]); + + opt[1] = new QCheckBox(i18n("&Overwrite Selections"), this); + layout->addWidget(opt[1], 0, AlignLeft); + opt[1]->setChecked(configFlags & flags[1]); + + opt[2] = new QCheckBox(i18n("Mouse &Autocopy"), this); + layout->addWidget(opt[2], 0, AlignLeft); + opt[2]->setChecked(configFlags & flags[2]); + + opt[3] = new QCheckBox(i18n("&X11-like Single Selection"), this); + layout->addWidget(opt[3], 0, AlignLeft); + opt[3]->setChecked(configFlags & flags[3]); + + opt[4] = new QCheckBox(i18n("&Vertical Selections"), this); + layout->addWidget(opt[4], 0, AlignLeft); + opt[4]->setChecked(configFlags & flags[4]); + + opt[5] = new QCheckBox(i18n("&Toggle Old"), this); + layout->addWidget(opt[5], 0, AlignLeft); + opt[5]->setChecked(configFlags & flags[5]); + + layout->addStretch(); + + // What is this? help + QWhatsThis::add(opt[0], i18n("Enabling this prevents key input or cursor movement by way of the arrow keys from causing the elimination of text selection.<p><b>Note:</b> If the Overwrite Selections option is activated then any typed character input or paste operation will replace the selected text.")); + QWhatsThis::add(opt[1], i18n("When this is on, any keyed character input or paste operation will replace the selected text.")); + QWhatsThis::add(opt[2], i18n("When this is on, any text selected with the mouse will be automatically copied to the clipboard.")); + QWhatsThis::add(opt[3], i18n("Not implemented yet.")); + QWhatsThis::add(opt[4], i18n("Enabling this allows you to make vertical selections.")); + QWhatsThis::add(opt[5], i18n("Not yet implemented.")); +} + +void SelectConfigTab::getData(KateView *view) { + int configFlags, z; + + configFlags = view->config(); + for (z = 0; z < numFlags; z++) { + configFlags &= ~flags[z]; // clear flag + if (opt[z]->isChecked()) configFlags |= flags[z]; // set flag if checked + } + view->setConfig(configFlags); +} + +const int EditConfigTab::flags[] = {KateView::cfWordWrap, KateView::cfReplaceTabs, KateView::cfRemoveSpaces, + KateView::cfAutoBrackets, KateView::cfGroupUndo, KateView::cfShowTabs, KateView::cfSmartHome, + KateView::cfPageUDMovesCursor, KateView::cfWrapCursor}; + +EditConfigTab::EditConfigTab(QWidget *parent, KateView *view) + : QWidget(parent, 0L) { + + QHBoxLayout *mainLayout; + QVBoxLayout *cbLayout, *leLayout; + int configFlags; + + mainLayout = new QHBoxLayout(this, 0, KDialog::spacingHint() ); + + // checkboxes + cbLayout = new QVBoxLayout( mainLayout ); + configFlags = view->config(); + + opt[0] = new QCheckBox(i18n("&Word wrap"), this); + cbLayout->addWidget(opt[0], 0, AlignLeft); + opt[0]->setChecked(view->doc()->wordWrap()); + + opt[1] = new QCheckBox(i18n("Replace &tabs with spaces"), this); + cbLayout->addWidget(opt[1], 0, AlignLeft); + opt[1]->setChecked(configFlags & flags[1]); + + opt[2] = new QCheckBox(i18n("&Remove trailing spaces"), this); + cbLayout->addWidget(opt[2], 0, AlignLeft); + opt[2]->setChecked(configFlags & flags[2]); + + opt[3] = new QCheckBox(i18n("&Auto brackets"), this); + cbLayout->addWidget(opt[3], 0, AlignLeft); + opt[3]->setChecked(configFlags & flags[3]); + + opt[4] = new QCheckBox(i18n("Group &undos"), this); + cbLayout->addWidget(opt[4], 0, AlignLeft); + opt[4]->setChecked(configFlags & flags[4]); + + opt[5] = new QCheckBox(i18n("&Show tabs"), this); + cbLayout->addWidget(opt[5], 0, AlignLeft); + opt[5]->setChecked(configFlags & flags[5]); + + opt[6] = new QCheckBox(i18n("Smart &home"), this); + cbLayout->addWidget(opt[6], 0, AlignLeft); + opt[6]->setChecked(configFlags & flags[6]); + + opt[7] = new QCheckBox(i18n("&Page up/down moves cursor"), this); + cbLayout->addWidget(opt[7], 0, AlignLeft); + opt[7]->setChecked(configFlags & flags[7]); + + opt[8] = new QCheckBox(i18n("Wrap &cursor"), this); + cbLayout->addWidget(opt[8], 0, AlignLeft); + opt[8]->setChecked(configFlags & flags[8]); + + cbLayout->addStretch(); + + // edit lines + leLayout = new QVBoxLayout(); + mainLayout->addLayout(leLayout,10); + + e1 = new QSpinBox(this); + e1->setMinValue(20); + e1->setMaxValue( 200); + e1->setValue((int)(view->doc()->wordWrapAt())); +#warning fixme e1->setLabel(i18n("Wrap Words At:")); + + e2 = new QSpinBox(this); + e2->setMinValue(1); + e2->setMaxValue(16); + e2->setValue((int)view->tabWidth()); + +#warning fixme e2->setLabel(i18n("Tab/Indent Width:")); + + e3 = new QSpinBox(this); + e3->setMinValue(5); + e3->setMaxValue( 30000); +#warning fixme e3->setLabel(i18n("Undo steps:")); + e3->setValue((int)view->undoSteps()); + + leLayout->addWidget(e1, 0, AlignLeft); + leLayout->addWidget(e2, 0, AlignLeft); + leLayout->addWidget(e3, 0, AlignLeft); + + + QVBox *box = new QVBox (this); + leLayout->addWidget (box, 0, AlignLeft); + + new QLabel (i18n("Encoding:"), box); + + encoding = new QComboBox(box); +#warning fixme +#if 0 + encoding->insertStringList (KGlobal::charsets()->availableEncodingNames()); + encoding->setCurrentItem (KGlobal::charsets()->availableEncodingNames().findIndex(view->doc()->encoding())); +#endif + leLayout->addStretch(); + + // What is this? help + QWhatsThis::add(opt[0], i18n("Word wrap is a feature that causes the editor to automatically start a new line of text and move (wrap) the cursor to the beginning of that new line. KateView will automatically start a new line of text when the current line reaches the length specified by the Wrap Words At: option.<p><b>NOTE:<b> Word Wrap will not change existing lines or wrap them for easy reading as in some applications.")); + QWhatsThis::add(e1, i18n("If the Word Wrap option is selected this entry determines the length (in characters) at which the editor will automatically start a new line.")); + QWhatsThis::add(opt[1], i18n("KateView will replace any tabs with the number of spaces indicated in the Tab Width: entry.")); + QWhatsThis::add(e2, i18n("If the Replace Tabs By Spaces option is selected this entry determines the number of spaces with which the editor will automatically replace tabs.")); + QWhatsThis::add(opt[2], i18n("KateView will automatically eliminate extra spaces at the ends of lines of text.")); + QWhatsThis::add(opt[3], i18n("When the user types a left bracket ([,(, or {) KateView automatically enters the right bracket (}, ), or ]) to the right of the cursor.")); + QWhatsThis::add(opt[4], i18n("Checking this will cause sequences of similar actions to be undone at once.")); + QWhatsThis::add(opt[5], i18n("The editor will display a symbol to indicate the presence of a tab in the text.")); + QWhatsThis::add(opt[6], i18n("Not yet implemented.")); + QWhatsThis::add(opt[7], i18n("If this is selected, the insertion cursor will be moved to the first/last line when pressing the page up/down buttons.<p>If not selected, it will remain at it's relative position in the visible text.")); + QWhatsThis::add(e3, i18n("Sets the number of undo/redo steps to record. More steps uses more memory.")); + QWhatsThis::add(opt[8], i18n("When on, moving the insertion cursor using the <b>Left</b> and <b>Right</b> keys will go on to previous/next line at beginning/end of the line, similar to most editors.<p>When off, the insertion cursor cannot be moved left of the line start, but it can be moved off the line end, which can be very handy for programmers.")); +} + +void EditConfigTab::getData(KateView *view) +{ + int configFlags, z; + + configFlags = view->config(); + for (z = 1; z < numFlags; z++) { + configFlags &= ~flags[z]; + if (opt[z]->isChecked()) configFlags |= flags[z]; + } + view->setConfig(configFlags); + + view->setEncoding (encoding->currentText()); + view->doc()->setWordWrapAt(e1->value()); + view->doc()->setWordWrap (opt[0]->isChecked()); + view->setTabWidth(e2->value()); + view->setUndoSteps(e3->value()); +} + +ColorConfig::ColorConfig( QWidget *parent, char *name ) + : QWidget( parent, name ) +{ + QGridLayout *glay = new QGridLayout( this, 6, 2, 0, KDialog::spacingHint()); + glay->setColStretch(1,1); + glay->setRowStretch(5,1); + + QLabel *label; + + label = new QLabel( i18n("Background:"), this); + label->setAlignment( AlignRight|AlignVCenter ); + m_back = new KColorButton( this ); + glay->addWidget( label, 0, 0 ); + glay->addWidget( m_back, 0, 1 ); + + label = new QLabel( i18n("Selected:"), this); + label->setAlignment( AlignRight|AlignVCenter ); + m_selected = new KColorButton( this ); + glay->addWidget( label, 2, 0 ); + glay->addWidget( m_selected, 2, 1 ); + + // QWhatsThis help + QWhatsThis::add(m_back, i18n("Sets the background color of the editing area")); + QWhatsThis::add(m_selected, i18n("Sets the background color of the selection. To set the text color for selected text, use the "<b>Configure Highlighting</b>" dialog.")); +} + + +ColorConfig::~ColorConfig() +{ +} + +void ColorConfig::setColors(QColor *colors) +{ + m_back->setColor( colors[0] ); + m_selected->setColor( colors[1] ); +} + +void ColorConfig::getColors(QColor *colors) +{ + colors[0] = m_back->color(); + colors[1] = m_selected->color(); +} + +FontConfig::FontConfig( QWidget *parent, char *name ) + : QWidget( parent, name ) +{ + // sizemanagment + QGridLayout *grid = new QGridLayout( this, 1, 1 ); +#if 0 + m_fontchooser = new KFontChooser ( this ); + m_fontchooser->enableColumn(KFontChooser::StyleList, false); + grid->addWidget( m_fontchooser, 0, 0); + + connect (m_fontchooser, SIGNAL (fontSelected( const QFont & )), this, SLOT (slotFontSelected( const QFont & ))); +#endif +} + +FontConfig::~FontConfig() +{ +} + +void FontConfig::setFont ( const QFont &font ) +{ +#if 0 + m_fontchooser->setFont (font); + myFont = font; +#endif +} + +void FontConfig::slotFontSelected( const QFont &font ) +{ + myFont = font; +} + + + + diff --git a/noncore/apps/tinykate/libkate/view/kateviewdialog.h b/noncore/apps/tinykate/libkate/view/kateviewdialog.h new file mode 100644 index 0000000..60f30bd --- a/dev/null +++ b/noncore/apps/tinykate/libkate/view/kateviewdialog.h @@ -0,0 +1,194 @@ +/*************************************************************************** + kateviewdialog.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. * + * * + ***************************************************************************/ +// Dialogs + +#ifndef _KWDIALOG_H_ +#define _KWDIALOG_H_ + + +class QCheckBox; +class QLineEdit; +class QPushButton; +class QRadioButton; +class QSpinBox; +class KColorButton; +class QComboBox; + +#include <kdialogbase.h> +#include "kateview.h" + +class SearchDialog : public KDialogBase +{ + Q_OBJECT + + public: + SearchDialog( QWidget *parent, QStringList &searchFor, QStringList &replaceWith, int flags ); + QString getSearchFor(); + QString getReplaceWith(); + int getFlags(); + void setSearchText( const QString &searchstr ); + + protected slots: + void slotOk(); + + protected: + QComboBox *m_search; + QComboBox *m_replace; + QCheckBox *m_opt1; + QCheckBox *m_opt2; + QCheckBox *m_opt3; + QCheckBox *m_optRegExp; + QCheckBox *m_opt4; + QCheckBox *m_opt5; + QCheckBox *m_opt6; +}; + +class ReplacePrompt : public KDialogBase +{ + Q_OBJECT + + public: + + ReplacePrompt(QWidget *parent); + + signals: + + void clicked(); + + protected slots: + + void slotUser1( void ); // All + void slotUser2( void ); // No + void slotUser3( void ); // Yes + virtual void done(int); + + protected: + + void closeEvent(QCloseEvent *); +}; + +class GotoLineDialog : public KDialogBase +{ + Q_OBJECT + + public: + + GotoLineDialog(QWidget *parent, int line, int max); + int getLine(); + + protected: + + QSpinBox *e1; + QPushButton *btnOK; +}; + +class IndentConfigTab : public QWidget +{ + Q_OBJECT + + public: + + IndentConfigTab(QWidget *parent, KateView *); + void getData(KateView *); + + protected: + + static const int numFlags = 6; + static const int flags[numFlags]; + QCheckBox *opt[numFlags]; +}; + +class SelectConfigTab : public QWidget +{ + Q_OBJECT + + public: + + SelectConfigTab(QWidget *parent, KateView *); + void getData(KateView *); + + protected: + + static const int numFlags = 6; + static const int flags[numFlags]; + QCheckBox *opt[numFlags]; +}; + +class EditConfigTab : public QWidget +{ + Q_OBJECT + + public: + + EditConfigTab(QWidget *parent, KateView *); + void getData(KateView *); + + protected: + + static const int numFlags = 9; + static const int flags[numFlags]; + QCheckBox *opt[numFlags]; + QComboBox *encoding; + + + QSpinBox *e1; + QSpinBox *e2; + QSpinBox *e3; +}; + +class ColorConfig : public QWidget +{ + Q_OBJECT + +public: + + ColorConfig( QWidget *parent = 0, char *name = 0 ); + ~ColorConfig(); + + void setColors( QColor * ); + void getColors( QColor * ); + +private: + + KColorButton *m_back; + KColorButton *m_selected; +}; + +class FontConfig : public QWidget +{ + Q_OBJECT + +public: + + FontConfig( QWidget *parent = 0, char *name = 0 ); + ~FontConfig(); + + void setFont ( const QFont &font ); + QFont getFont ( ) { return myFont; }; + + private: +// class KFontChooser *m_fontchooser; + QFont myFont; + + private slots: + void slotFontSelected( const QFont &font ); +}; + + +#endif //_KWDIALOG_H_ diff --git a/noncore/apps/tinykate/main.cpp b/noncore/apps/tinykate/main.cpp new file mode 100644 index 0000000..e92df69 --- a/dev/null +++ b/noncore/apps/tinykate/main.cpp @@ -0,0 +1,29 @@ +/*************************************************************************** + main.cpp + ------------------- + begin : November 2002 + copyright : (C) 2002 by Joseph Wenninger <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. * + * ONLY VERSION 2 OF THE LICENSE IS APPLICABLE * + * * + ***************************************************************************/ +#include <qpe/qpeapplication.h> +#include <qmainwindow.h> +#include "tinykate.h" + + +int main( int argc, char ** argv ) +{ + QPEApplication a( argc, argv ); + + TinyKate *m = new TinyKate(); + a.setMainWidget( m ); + m->showMaximized(); + return a.exec(); +} diff --git a/noncore/apps/tinykate/pics/edit-redo.xpm b/noncore/apps/tinykate/pics/edit-redo.xpm new file mode 100644 index 0000000..7557ac5 --- a/dev/null +++ b/noncore/apps/tinykate/pics/edit-redo.xpm @@ -0,0 +1,90 @@ +/* XPM */ +static char * edit_redo_xpm[] = { +"18 17 70 1", +" c None", +". c #1E472E", +"+ c #234E33", +"@ c #1B4029", +"# c #1B422A", +"$ c #AFBEBA", +"% c #DBEADF", +"& c #C1CECC", +"* c #214A30", +"= c #224B31", +"- c #163321", +"; c #BFD0C8", +"> c #90BD9F", +", c #227D37", +"' c #C0D1C9", +") c #245135", +"! c #153220", +"~ c #BDCEC7", +"{ c #2F9645", +"] c #3BB057", +"^ c #43BA5C", +"/ c #224B30", +"( c #173A23", +"_ c #143120", +": c #38774E", +"< c #1E4335", +"[ c #0B281E", +"} c #143D29", +"| c #3FAF57", +"1 c #42B75B", +"2 c #7BA08A", +"3 c #0F2417", +"4 c #081914", +"5 c #050E0D", +"6 c #123926", +"7 c #36A34D", +"8 c #9DC6AA", +"9 c #88AB9C", +"0 c #C2DBCA", +"a c #040B06", +"b c #0A1F18", +"c c #0D3525", +"d c #2A8F3D", +"e c #CFE0D4", +"f c #0A1910", +"g c #0D2419", +"h c #030C0B", +"i c #041714", +"j c #259039", +"k c #3E9951", +"l c #B2D1BC", +"m c #03090A", +"n c #071112", +"o c #55AE72", +"p c #5AB975", +"q c #5AA77B", +"r c #468166", +"s c #000001", +"t c #10211F", +"u c #03080A", +"v c #010003", +"w c #020005", +"x c #000000", +"y c #14311F", +"z c #050B0C", +"A c #162D26", +"B c #050D0E", +"C c #142724", +"D c #090F10", +"E c #050A0C", +" ", +" ", +" ..+ ", +" @#$%&*= ", +" -;>,,,%'* ) ", +" !~,,{]^,,%/ )( ", +" _,:<[[}|1,%*)2( ", +"3,)4 567,890( ", +"a,b c7,de( ", +"fgh i,jkl( ", +" mn 4,opqr( ", +" stu vvvwvvxy ", +" zA5 ", +" BCD ", +" sEs ", +" ", +" "}; diff --git a/noncore/apps/tinykate/pics/edit-undo.xpm b/noncore/apps/tinykate/pics/edit-undo.xpm new file mode 100644 index 0000000..17a1f30 --- a/dev/null +++ b/noncore/apps/tinykate/pics/edit-undo.xpm @@ -0,0 +1,90 @@ +/* XPM */ +static char * edit_undo_xpm[] = { +"18 17 70 1", +" c None", +". c #234E33", +"+ c #1E472E", +"@ c #224B31", +"# c #214A30", +"$ c #C1CECC", +"% c #DBEADF", +"& c #AFBEBA", +"* c #1B422A", +"= c #1B4029", +"- c #245135", +"; c #C0D1C9", +"> c #227D37", +", c #90BD9F", +"' c #BFD0C8", +") c #163321", +"! c #173A23", +"~ c #224B30", +"{ c #43BA5C", +"] c #3BB057", +"^ c #2F9645", +"/ c #BDCEC7", +"( c #153220", +"_ c #7BA08A", +": c #42B75B", +"< c #3FAF57", +"[ c #143D29", +"} c #0B281E", +"| c #1E4335", +"1 c #38774E", +"2 c #143120", +"3 c #C2DBCA", +"4 c #88AB9C", +"5 c #9DC6AA", +"6 c #36A34D", +"7 c #123926", +"8 c #050E0D", +"9 c #081914", +"0 c #0F2417", +"a c #CFE0D4", +"b c #2A8F3D", +"c c #0D3525", +"d c #0A1F18", +"e c #040B06", +"f c #B2D1BC", +"g c #3E9951", +"h c #259039", +"i c #041714", +"j c #030C0B", +"k c #0D2419", +"l c #0A1910", +"m c #468166", +"n c #5AA77B", +"o c #5AB975", +"p c #55AE72", +"q c #071112", +"r c #03090A", +"s c #14311F", +"t c #000000", +"u c #010003", +"v c #020005", +"w c #03080A", +"x c #10211F", +"y c #000001", +"z c #162D26", +"A c #050B0C", +"B c #090F10", +"C c #142724", +"D c #050D0E", +"E c #050A0C", +" ", +" ", +" .++ ", +" @#$%&*= ", +"- #;%>>>,') ", +"!- ~%>>{]^>>/( ", +"!_-#%>:<[}}|1>2 ", +"!345>678 9->0 ", +"!ab>6c d>e ", +"!fgh>i jkl ", +"!mnop>9 qr ", +"stuuvuuu wxy ", +" 8zA ", +" BCD ", +" yEy ", +" ", +" "}; diff --git a/noncore/apps/tinykate/pics/file-new.xpm b/noncore/apps/tinykate/pics/file-new.xpm new file mode 100644 index 0000000..ec8dd63 --- a/dev/null +++ b/noncore/apps/tinykate/pics/file-new.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char * file_new_xpm[] = { +"16 16 5 1", +" c None", +". c #808080", +"+ c #FFFFFF", +"@ c #C0C0C0", +"# c #000000", +" .......... ", +" .++++++++@. ", +" .++++++++@+. ", +" .++++++++#### ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .++++++++++@# ", +" .@@@@@@@@@@@# ", +" ############# "}; diff --git a/noncore/apps/tinykate/pics/file-open.xpm b/noncore/apps/tinykate/pics/file-open.xpm new file mode 100644 index 0000000..8449d5b --- a/dev/null +++ b/noncore/apps/tinykate/pics/file-open.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * file_open_xpm[] = { +"16 16 6 1", +" c None", +". c #808080", +"+ c #FFFFFF", +"@ c #C0C0C0", +"# c #FFFF00", +"$ c #000000", +" ", +" ..... ", +" .+++++. ", +" .+@#@#@+...... ", +" .+#@#@#@+++++.$", +" .+@#@#@#@#@#@.$", +".............#.$", +".++++++++++.$@.$", +".+@#@#@#@#@#$..$", +" .+@#@#@#@#@.$.$", +" .+#@#@#@#@#@$.$", +" .+#@#@#@#@#.$$", +" ............$$", +" $$$$$$$$$$$$$", +" ", +" "}; diff --git a/noncore/apps/tinykate/pics/file-save.xpm b/noncore/apps/tinykate/pics/file-save.xpm new file mode 100644 index 0000000..039a174 --- a/dev/null +++ b/noncore/apps/tinykate/pics/file-save.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static const char * file_save_xpm[] = { +"16 16 5 1", +" c None", +". c #808080", +"+ c #FFFFFF", +"@ c #000000", +"# c #0000FF", +" ", +" ........ ", +" .++++++.@ ", +" .+....+.+@ #", +" .++++++.@@@ ##", +" .+....++++@ ##@", +" .+++++++++@##@ ", +" .+.......+##@ ", +" .++++++++##@ ", +" .+......@#@ ", +" .++++++@@@@ ", +" .+....@@@+@ ", +" .++++@++++@ ", +" .+++++++++@ ", +" @@@@@@@@@@@ ", +" "}; diff --git a/noncore/apps/tinykate/tinykate.cpp b/noncore/apps/tinykate/tinykate.cpp new file mode 100644 index 0000000..03c6e50 --- a/dev/null +++ b/noncore/apps/tinykate/tinykate.cpp @@ -0,0 +1,199 @@ +/*************************************************************************** + tinykate.cpp + Tiny KATE mainwindow + ------------------- + begin : November 2002 + copyright : (C) 2002 by Joseph Wenninger <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. * + * ONLY VERSION 2 OF THE LICENSE IS APPLICABLE * + * * + ***************************************************************************/ +#include <qwidget.h> +#include <qaction.h> +#include <qlayout.h> +#include <qpe/qpetoolbar.h> +#include <qpe/qpemenubar.h> +#include <qpe/resource.h> +#include <qpe/global.h> + +#include <opie/ofiledialog.h> + +#include "tinykate.h" +#include "pics/file-new.xpm" +#include "pics/file-open.xpm" +#include "pics/file-save.xpm" +#include "pics/edit-undo.xpm" +#include "pics/edit-redo.xpm" + +#include <katedocument.h> +#include <katehighlight.h> + +TinyKate::TinyKate( QWidget *parent, const char *name, WFlags f) : + QMainWindow( parent, name, f ) +{ + currentView=0; + setCaption(tr("TinyKATE")); + + setToolBarsMovable(FALSE); + + QPEToolBar *bar = new QPEToolBar( this ); + bar->setHorizontalStretchable( TRUE ); + QPEMenuBar *mb = new QPEMenuBar( bar ); + mb->setMargin( 0 ); + + tabwidget=new OTabWidget(this); + setCentralWidget(tabwidget); + connect(tabwidget,SIGNAL(currentChanged( QWidget *)),this,SLOT(slotCurrentChanged(QWidget *))); + +//FILE ACTIONS + QPopupMenu *popup = new QPopupMenu( this ); + + // Action for creating a new document + QAction *a = new QAction( tr( "New" ), QPixmap((const char**)file_new_xpm ), QString::null, 0, this, 0 ); + a->addTo( popup ); + connect(a, SIGNAL(activated()), this, SLOT(slotNew())); + + // Action for opening an exisiting document + a = new QAction( tr( "Open" ), QPixmap((const char**)file_open_xpm), QString::null, 0, this, 0 ); + a->addTo(popup); + connect(a, SIGNAL(activated()), this, SLOT(slotOpen())); + + + // Action for saving document + a = new QAction( tr( "Save" ), QPixmap((const char**)file_save_xpm), QString::null, 0, this, 0 ); + a->addTo(popup); + + // Action for saving document to a new name + a = new QAction( tr( "Save As" ), QPixmap((const char**)file_save_xpm), QString::null, 0, this, 0 ); + a->addTo(popup); + + // Action for closing the currently active document + a = new QAction( tr( "Close" ), QPixmap(), QString::null, 0, this, 0 ); + a->addTo(popup); + connect(a, SIGNAL(activated()), this, SLOT(slotClose())); + + + mb->insertItem(tr("File"),popup); + +//EDIT ACTIONS + + // Action for cutting text + editCut = new QAction( tr( "Cut" ), Resource::loadPixmap( "cut" ), QString::null, 0, this, 0 ); + editCut->addTo( bar ); + + // Action for Copying text + editCopy = new QAction( tr( "Copy" ), Resource::loadPixmap( "copy" ), QString::null, 0, this, 0 ); + editCopy->addTo( bar ); + + // Action for pasting text + editPaste = new QAction( tr( "Paste" ), Resource::loadPixmap( "paste" ), QString::null, 0, this, 0 ); + editPaste->addTo( bar ); + + + // Action for finding / replacing text + editFindReplace = new QAction( tr( "Find/Replace" ), Resource::loadPixmap("find"), QString::null, 0, this, 0 ); + editFindReplace->addTo( bar ); + + // Action for undo + editUndo = new QAction( tr( "Undo" ), QPixmap((const char**)edit_undo_xpm), QString::null, 0, this, 0 ); + editUndo->addTo( bar ); + + // Action for redo + editRedo = new QAction( tr( "Redo" ), QPixmap((const char**)edit_redo_xpm), QString::null, 0, this, 0 ); + editRedo->addTo( bar ); + +//VIEW ACITONS + popup = new QPopupMenu( this ); + + viewIncFontSizes = new QAction( tr( "Font +" ), QString::null, 0, this, 0 ); + viewIncFontSizes->addTo( popup ); + + viewDecFontSizes = new QAction( tr( "Font -" ), QString::null, 0, this, 0 ); + viewDecFontSizes->addTo( popup ); + + mb->insertItem(tr("View"),popup); + + + + popup = new QPopupMenu( this ); + mb->insertItem(tr("Utils"),popup); + +//Highlight management + hlmenu=new QPopupMenu(this); + HlManager *hlm=HlManager::self(); + for (int i=0;i<hlm->highlights();i++) + { + hlmenu->insertItem(hlm->hlName(i),i); + } + popup->insertItem(tr("Highlighting"),hlmenu); + + + utilSettings = new QAction( tr( "Settings" ), QString::null, 0, this, 0 ); + utilSettings->addTo( popup); + +} + + +void TinyKate::slotOpen( ) +{ + QString filename=OFileDialog::getOpenFileName(OFileSelector::EXTENDED_ALL); + if (!filename.isEmpty()) { + KateDocument *kd= new KateDocument(false, false, this,0,this); + KTextEditor::View *kv; + tabwidget->addTab(kv=kd->createView(tabwidget,"bLAH"),"BLAH","BLAH"); + qDebug(filename); + kd->open(filename); + } +} + +void TinyKate::slotCurrentChanged( QWidget * view) +{ + if (currentView) { + disconnect(editCopy,SIGNAL(activated()),currentView,SLOT(copy())); + disconnect(editCut,SIGNAL(activated()),currentView,SLOT(cut())); + disconnect(editPaste,SIGNAL(activated()),currentView,SLOT(paste())); + disconnect(editUndo,SIGNAL(activated()),currentView,SLOT(undo())); + disconnect(editRedo,SIGNAL(activated()),currentView,SLOT(redo())); + disconnect(viewIncFontSizes,SIGNAL(activated()), currentView,SLOT(slotIncFontSizes())); + disconnect(viewDecFontSizes,SIGNAL(activated()), currentView,SLOT(slotDecFontSizes())); + disconnect(hlmenu,SIGNAL(activated(int)), currentView,SLOT(setHl(int))); + disconnect(utilSettings,SIGNAL(activated()), currentView,SLOT(configDialog())); + } + + currentView=(KTextEditor::View*)view; + + connect(editCopy,SIGNAL(activated()),currentView,SLOT(copy())); + connect(editCut,SIGNAL(activated()),currentView,SLOT(cut())); + connect(editPaste,SIGNAL(activated()),currentView,SLOT(paste())); + connect(editUndo,SIGNAL(activated()),currentView,SLOT(undo())); + connect(editRedo,SIGNAL(activated()),currentView,SLOT(redo())); + connect(viewIncFontSizes,SIGNAL(activated()), currentView,SLOT(slotIncFontSizes())); + connect(viewDecFontSizes,SIGNAL(activated()), currentView,SLOT(slotDecFontSizes())); + connect(hlmenu,SIGNAL(activated(int)), currentView,SLOT(setHl(int))); + connect(utilSettings,SIGNAL(activated()), currentView,SLOT(configDialog())); + +} + +void TinyKate::slotNew( ) +{ + KateDocument *kd= new KateDocument(false, false, this,0,this); + KTextEditor::View *kv; + tabwidget->addTab(kv=kd->createView(tabwidget,"BLAH"),"BLAH",tr("Unnamed %1").arg(0)); + +} + +void TinyKate::slotClose( ) +{ + if (currentView==0) return; + KTextEditor::View *dv=currentView; + currentView=0; + tabwidget->removePage(dv); + delete dv->document(); +} + diff --git a/noncore/apps/tinykate/tinykate.desktop b/noncore/apps/tinykate/tinykate.desktop new file mode 100644 index 0000000..2230a6b --- a/dev/null +++ b/noncore/apps/tinykate/tinykate.desktop @@ -0,0 +1,6 @@ +[Desktop Entry] +Type=Application +Exec=tinykate +Icon=tinykate_icon.xpm +Name=TinyKATE +Comment=Opie Advanced Texteditor diff --git a/noncore/apps/tinykate/tinykate.h b/noncore/apps/tinykate/tinykate.h new file mode 100644 index 0000000..6dda05d --- a/dev/null +++ b/noncore/apps/tinykate/tinykate.h @@ -0,0 +1,62 @@ +/*************************************************************************** + tinykate.h + Tiny KATE mainwindow + ------------------- + begin : November 2002 + copyright : (C) 2002 by Joseph Wenninger <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. * + * ONLY VERSION 2 OF THE LICENSE IS APPLICABLE * + * * + ***************************************************************************/ + +#ifndef __TINYKATE_H__ +#define __TINYKATE_H__ + + +#include <qmainwindow.h> +#include <opie/otabwidget.h> +#include <ktexteditor.h> + +class QAction; +class QPopupMenu; + +class TinyKate : public QMainWindow +{ +Q_OBJECT +public: + TinyKate( QWidget *parent=0, const char *name=0, WFlags f = 0); + +public slots: + void slotOpen(); + +protected slots: + void slotNew(); + void slotClose(); + void slotCurrentChanged(QWidget *); + +private: + OTabWidget *tabwidget; + KTextEditor::View *currentView; + + QAction *editCopy; + QAction *editCut; + QAction *editPaste; + QAction *editUndo; + QAction *editRedo; + QAction *editFindReplace; + QAction *viewIncFontSizes; + QAction *viewDecFontSizes; + QAction *utilSettings; + + QPopupMenu *hlmenu; + +}; + + +#endif // __TINYKATE_H__ diff --git a/noncore/apps/tinykate/tinykate.pro b/noncore/apps/tinykate/tinykate.pro new file mode 100644 index 0000000..2079041 --- a/dev/null +++ b/noncore/apps/tinykate/tinykate.pro @@ -0,0 +1,16 @@ +TEMPLATE = app +CONFIG = qt warn_on release +DESTDIR = $(OPIEDIR)/bin +HEADERS = tinykate.h +SOURCES = tinykate.cpp main.cpp +INTERFACES = +INCLUDEPATH += $(OPIEDIR)/include $(OPIEDIR)/noncore/apps/tinykate/libkate/microkde \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/document \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/view \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/interfaces \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/ktexteditor \ + $(OPIEDIR)/noncore/apps/tinykate/libkate/qt3back + +DEPENDPATH += $(OPIEDIR)/include +LIBS += -lqpe -ltinykate -lopie +TARGET = tinykate diff --git a/noncore/apps/tinykate/tinykate_icon.xpm b/noncore/apps/tinykate/tinykate_icon.xpm new file mode 100644 index 0000000..e48e7c9 --- a/dev/null +++ b/noncore/apps/tinykate/tinykate_icon.xpm @@ -0,0 +1,20 @@ +/* XPM */ +static char *tinykate_xpm[] = { +"14 14 3 1", +" c None", +". c #000000", +"a c #FFFFFF", +" ", +" aaaaaaaaaaaa ", +" a..........a ", +" a..aaaaaa..a ", +" a.a.aaaa.a.a ", +" a.aa.aa.aa.a ", +" a.aaa..aaa.a ", +" a.aaa..aaa.a ", +" a.aa.aa.aa.a ", +" a.a.aaaa.a.a ", +" a..aaaaaa..a ", +" a..........a ", +" aaaaaaaaaaaa ", +" "}; diff --git a/pics/tinykate/tinykate.png b/pics/tinykate/tinykate.png Binary files differnew file mode 100644 index 0000000..6644160 --- a/dev/null +++ b/pics/tinykate/tinykate.png |