Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

katedocument.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           katedocument.cpp  -  description
00003                              -------------------
00004     begin                : Mon Jan 15 2001
00005     copyright            : (C) 2001 by Christoph "Crossfire" Cullmann
00006                            (C) 2002 by Joseph Wenninger
00007     email                : crossfire@babylon2k.de
00008                            jowenn@kde.org
00009 
00010 ***************************************************************************/
00011 
00012 /***************************************************************************
00013  *                                                                         *
00014  *   This program is free software; you can redistribute it and/or modify  *
00015  *   it under the terms of the GNU General Public License as published by  *
00016  *   the Free Software Foundation; either version 2 of the License, or     *
00017  *   (at your option) any later version.                                   *
00018  *                                                                         *
00019  ***************************************************************************/
00020 
00021 /*
00022    Copyright (C) 1998, 1999 Jochen Wilhelmy
00023                             digisnap@cs.tu-berlin.de
00024 
00025     This library is free software; you can redistribute it and/or
00026     modify it under the terms of the GNU Library General Public
00027     License as published by the Free Software Foundation; either
00028     version 2 of the License, or (at your option) any later version.
00029 
00030     This library is distributed in the hope that it will be useful,
00031     but WITHOUT ANY WARRANTY; without even the implied warranty of
00032     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00033     Library General Public License for more details.
00034 
00035     You should have received a copy of the GNU Library General Public License
00036     along with this library; see the file COPYING.LIB.  If not, write to
00037     the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00038     Boston, MA 02111-1307, USA.
00039 */
00040 
00041 #include "katedocument.h"
00042 #include "kmessagebox.h"
00043 #include "kglobal.h"
00044 
00045 //#include "kcharsets.h"
00046 #include "kdebug.h"
00047 //#include "kinstance.h"
00048 
00049 #include "kglobalsettings.h"
00050 //#include "kaction.h"
00051 //#include "kstdaction.h"
00052 
00053 #include "../view/kateview.h"
00054 #include "katebuffer.h"
00055 #include "katetextline.h"
00056 
00057 #include "katecmd.h"
00058 
00059 /* OPIE */
00060 #include <opie2/odebug.h>
00061 #include <qpe/config.h>
00062 
00063 /* QT */
00064 #include <qfileinfo.h>
00065 #include <qdatetime.h>
00066 #include <qstring.h>
00067 #include <qtimer.h>
00068 #include <qobject.h>
00069 #include <qapplication.h>
00070 #include <qclipboard.h>
00071 #include <qfont.h>
00072 #include <qpainter.h>
00073 #include <qfile.h>
00074 #include <qtextstream.h>
00075 #include <qtextcodec.h>
00076 
00077 /* STD */
00078 #include <sys/time.h>
00079 #include <unistd.h>
00080 #include <stdio.h>
00081 
00082 KateAction::KateAction(Action a, PointStruc &cursor, int len, const QString &text)
00083   : action(a), cursor(cursor), len(len), text(text) {
00084 }
00085 
00086 KateActionGroup::KateActionGroup(PointStruc &aStart, int type)
00087   : start(aStart), action(0L), undoType(type) {
00088 }
00089 
00090 KateActionGroup::~KateActionGroup() {
00091   KateAction *current, *next;
00092 
00093   current = action;
00094   while (current) {
00095     next = current->next;
00096     delete current;
00097     current = next;
00098   }
00099 }
00100 
00101 void KateActionGroup::insertAction(KateAction *a) {
00102   a->next = action;
00103   action = a;
00104 }
00105 
00106 const char * KateActionGroup::typeName(int type)
00107 {
00108   // return a short text description of the given undo group type suitable for a menu
00109   // not the lack of i18n's, the caller is expected to handle translation
00110   switch (type) {
00111   case ugPaste : return "Paste Text";
00112   case ugDelBlock : return "Selection Overwrite";
00113   case ugIndent : return "Indent";
00114   case ugUnindent : return "Unindent";
00115   case ugComment : return "Comment";
00116   case ugUncomment : return "Uncomment";
00117   case ugReplace : return "Text Replace";
00118   case ugSpell : return "Spell Check";
00119   case ugInsChar : return "Typing";
00120   case ugDelChar : return "Delete Text";
00121   case ugInsLine : return "New Line";
00122   case ugDelLine : return "Delete Line";
00123   }
00124   return "";
00125 }
00126 
00127 const int KateDocument::maxAttribs = 32;
00128 
00129 QStringList KateDocument::searchForList = QStringList();
00130 QStringList KateDocument::replaceWithList = QStringList();
00131 
00132 uint KateDocument::uniqueID = 0;
00133 
00134 QPtrDict<KateDocument::KateDocPrivate>* KateDocument::d_ptr = 0;
00135 
00136 
00137 KateDocument::KateDocument(bool bSingleViewMode, bool bBrowserView,
00138                                            QWidget *parentWidget, const char *widgetName,
00139                                            QObject *, const char *)
00140   : Kate::Document (),
00141     myFont(KGlobalSettings::generalFont()), myFontBold(KGlobalSettings::generalFont()), myFontItalic(KGlobalSettings::generalFont()), myFontBI(KGlobalSettings::generalFont()),
00142     myFontMetrics (myFont), myFontMetricsBold (myFontBold), myFontMetricsItalic (myFontItalic), myFontMetricsBI (myFontBI),
00143     hlManager(HlManager::self ())
00144 {
00145 
00146   d(this)->hlSetByUser = false;
00147   PreHighlightedTill=0;
00148   RequestPreHighlightTill=0;
00149 
00150   m_bSingleViewMode=bSingleViewMode;
00151   m_bBrowserView = bBrowserView;
00152 
00153   m_url = QString::null;
00154 
00155   // NOTE: QFont::CharSet doesn't provide all the charsets KDE supports
00156   // (esp. it doesn't distinguish between UTF-8 and iso10646-1)
00157 
00158   myEncoding = QString::fromLatin1(QTextCodec::codecForLocale()->name());
00159 
00160   maxLength = -1;
00161 
00162   setFont (KGlobalSettings::generalFont());
00163 
00164   myDocID = uniqueID;
00165   uniqueID++;
00166 
00167   myDocName = QString ("");
00168   fileInfo = new QFileInfo ();
00169 
00170   myCmd = new KateCmd (this);
00171 
00172   connect(this,SIGNAL(modifiedChanged()),this,SLOT(slotModChanged()));
00173 
00174   buffer = new KWBuffer;
00175   connect(buffer, SIGNAL(linesChanged(int)), this, SLOT(slotBufferChanged()));
00176 //  connect(buffer, SIGNAL(textChanged()), this, SIGNAL(textChanged()));
00177   connect(buffer, SIGNAL(needHighlight(long,long)),this,SLOT(slotBufferHighlight(long,long)));
00178 
00179   colors[0] = KGlobalSettings::baseColor();
00180   colors[1] = KGlobalSettings::highlightColor();
00181 
00182   m_attribs = new Attribute[maxAttribs];
00183 
00184   m_highlight = 0L;
00185   tabChars = 8;
00186 
00187   m_singleSelection = false;
00188 
00189   newDocGeometry = false;
00190   readOnly = false;
00191   newDoc = false;
00192 
00193   modified = false;
00194 
00195   undoList.setAutoDelete(true);
00196   undoState = 0;
00197   undoSteps = 50;
00198 
00199   pseudoModal = 0L;
00200   clear();
00201 
00202   setHighlight(0); //calls updateFontData()
00203   // if the user changes the highlight with the dialog, notify the doc
00204   connect(hlManager,SIGNAL(changed()),SLOT(hlChanged()));
00205 
00206   newDocGeometry = false;
00207 
00208   readConfig();
00209 
00210   setReadOnly(false);
00211 }
00212 
00213 void KateDocument::setDontChangeHlOnSave()
00214 {
00215   d(this)->hlSetByUser = true;
00216 }
00217 
00218 void KateDocument::setFont (QFont font)
00219 {
00220   kdDebug()<<"Kate:: setFont"<<endl;
00221   int oldwidth=myFontMetrics.width('W');  //Quick & Dirty Hack (by JoWenn) //Remove in KDE 3.0
00222   myFont = font;
00223   myFontBold = QFont (font);
00224   myFontBold.setBold (true);
00225 
00226   myFontItalic = QFont (font);
00227   myFontItalic.setItalic (true);
00228 
00229   myFontBI = QFont (font);
00230   myFontBI.setBold (true);
00231   myFontBI.setItalic (true);
00232 
00233   myFontMetrics = CachedFontMetrics (myFont);
00234   myFontMetricsBold = CachedFontMetrics (myFontBold);
00235   myFontMetricsItalic = CachedFontMetrics (myFontItalic);
00236   myFontMetricsBI = CachedFontMetrics (myFontBI);
00237   int newwidth=myFontMetrics.width('W'); //Quick & Dirty Hack (by JoWenn)  //Remove in KDE 3.0
00238   maxLength=maxLength*(float)newwidth/(float)oldwidth; //Quick & Dirty Hack (by JoWenn)  //Remove in KDE 3.0
00239 
00240   updateFontData();
00241   updateViews(); //Quick & Dirty Hack (by JoWenn) //Remove in KDE 3.0
00242 
00243 }
00244 
00245 long  KateDocument::needPreHighlight(long till)
00246 {
00247   int max=numLines()-1;
00248   if (till>max)
00249     {
00250       till=max;
00251     }
00252   if (PreHighlightedTill>=till) return -1;
00253 
00254   long tmp=RequestPreHighlightTill;
00255   if (RequestPreHighlightTill<till)
00256     {
00257       RequestPreHighlightTill=till;
00258       if (tmp<=PreHighlightedTill) QTimer::singleShot(10,this,SLOT(doPreHighlight()));
00259     }
00260   return RequestPreHighlightTill;
00261 }
00262 
00263 void KateDocument::doPreHighlight()
00264 {
00265   int from = PreHighlightedTill;
00266   int till = PreHighlightedTill+200;
00267   int max = numLines()-1;
00268   if (till > max)
00269     {
00270       till = max;
00271     }
00272   PreHighlightedTill = till;
00273   updateLines(from,till);
00274   emit preHighlightChanged(PreHighlightedTill);
00275   if (PreHighlightedTill<RequestPreHighlightTill)
00276     QTimer::singleShot(10,this,SLOT(doPreHighlight()));
00277 }
00278 
00279 KateDocument::~KateDocument()
00280 {
00281   m_highlight->release();
00282   writeConfig();
00283 
00284   if ( !m_bSingleViewMode )
00285   {
00286     m_views.setAutoDelete( true );
00287     m_views.clear();
00288     m_views.setAutoDelete( false );
00289   }
00290   delete_d(this);
00291 }
00292 
00293 void KateDocument::openURL(const QString &filename)
00294 {
00295 
00296   m_file=filename;
00297   fileInfo->setFile (m_file);
00298   setMTime();
00299 
00300   if (!fileInfo->exists() || !fileInfo->isReadable())
00301   {
00302     odebug << "File doesn't exit or couldn't be read" << oendl;
00303     return ;
00304   }
00305 
00306   buffer->clear();
00307 #warning fixme
00308 //  buffer->insertFile(0, m_file, KGlobal::charsets()->codecForName(myEncoding));
00309   odebug << "Telling buffer to open file" << oendl;
00310   buffer->insertFile(0, m_file, QTextCodec::codecForLocale());
00311 
00312   setMTime();
00313 
00314   if (myWordWrap)
00315     wrapText (myWordWrapAt);
00316 
00317   int hl = hlManager->wildcardFind( m_file );
00318 
00319   setHighlight(hl);
00320 
00321   updateLines();
00322   updateViews();
00323 
00324   emit fileNameChanged();
00325 
00326   return ;
00327 }
00328 
00329 bool KateDocument::saveFile()
00330 {
00331 
00332   QFile f( m_file );
00333   if ( !f.open( IO_WriteOnly ) )
00334     return false; // Error
00335 
00336   QTextStream stream(&f);
00337 
00338   stream.setEncoding(QTextStream::RawUnicode); // disable Unicode headers
00339 #warning fixme
00340 //  stream.setCodec(KGlobal::charsets()->codecForName(myEncoding));
00341   stream.setCodec(QTextCodec::codecForLocale()); // this line sets the mapper to the correct codec
00342 
00343   int maxLine = numLines();
00344   int line = 0;
00345   while(true)
00346   {
00347     stream << getTextLine(line)->getString();
00348     line++;
00349     if (line >= maxLine) break;
00350 
00351     if (eolMode == KateDocument::eolUnix) stream << "\n";
00352     else if (eolMode == KateDocument::eolDos) stream << "\r\n";
00353     else if (eolMode == KateDocument::eolMacintosh) stream << '\r';
00354   };
00355   f.close();
00356 
00357   fileInfo->setFile (m_file);
00358   setMTime();
00359 
00360   if (!(d(this)->hlSetByUser))
00361   {
00362   int hl = hlManager->wildcardFind( m_file );
00363 
00364   setHighlight(hl);
00365   }
00366   emit fileNameChanged ();
00367 
00368   return (f.status() == IO_Ok);
00369 }
00370 
00371 KTextEditor::View *KateDocument::createView( QWidget *parent, const char *name )
00372 {
00373   return new KateView( this, parent, name);
00374 }
00375 
00376 QString KateDocument::textLine( int line ) const
00377 {
00378   TextLine::Ptr l = getTextLine( line );
00379   if ( !l )
00380     return QString();
00381 
00382   return l->getString();
00383 }
00384 
00385 void KateDocument::replaceLine(const QString& s,int line)
00386 {
00387   remove_Line(line,false);
00388   insert_Line(s,line,true);
00389 }
00390 
00391 void KateDocument::insertLine( const QString &str, int l ) {
00392   insert_Line(str,l,true);
00393 }
00394 
00395 void KateDocument::insert_Line(const QString& s,int line, bool update)
00396 {
00397   kdDebug(13020)<<"KateDocument::insertLine "<<s<<QString(" %1").arg(line)<<endl;
00398   TextLine::Ptr TL=new TextLine();
00399   TL->append(s.unicode(),s.length());
00400   buffer->insertLine(line,TL);
00401   if (update)
00402   {
00403     newDocGeometry=true;
00404     updateLines(line);
00405     updateViews();
00406   }
00407 }
00408 
00409 void KateDocument::insertAt( const QString &s, int line, int col, bool  )
00410 {
00411   VConfig c;
00412   c.view = 0; // ### FIXME
00413   c.cursor.x = col;
00414   c.cursor.y = line;
00415   c.cXPos = 0; // ### FIXME
00416   c.flags = 0; // ### FIXME
00417   insert( c, s );
00418 }
00419 
00420 void KateDocument::removeLine( int line ) {
00421   remove_Line(line,true);
00422 }
00423 
00424 void KateDocument::remove_Line(int line,bool update)
00425 {
00426   kdDebug(13020)<<"KateDocument::removeLine "<<QString("%1").arg(line)<<endl;
00427   buffer->removeLine(line);
00428 //  newDocGeometry=true;
00429 //  if line==0)
00430   if (update)
00431   {
00432     updateLines(line);
00433     updateViews();
00434   }
00435 }
00436 
00437 int KateDocument::length() const
00438 {
00439   return text().length();
00440 }
00441 
00442 void KateDocument::setSelection( int , int , int , int )
00443 {
00444 }
00445 
00446 bool KateDocument::hasSelection() const
00447 {
00448   return (selectEnd >= selectStart);
00449 }
00450 
00451 QString KateDocument::selection() const
00452 {
00453   uint flags = 0;
00454   TextLine::Ptr textLine;
00455   int len, z, start, end, i;
00456 
00457   len = 1;
00458   if (!(flags & KateView::cfVerticalSelect)) {
00459     for (z = selectStart; z <= selectEnd; z++) {
00460       textLine = getTextLine(z);
00461       len += textLine->numSelected();
00462       if (textLine->isSelected()) len++;
00463     }
00464     QString s;
00465     len = 0;
00466     for (z = selectStart; z <= selectEnd; z++) {
00467       textLine = getTextLine(z);
00468       end = 0;
00469       do {
00470         start = textLine->findUnselected(end);
00471         end = textLine->findSelected(start);
00472         for (i = start; i < end; i++) {
00473           s[len] = textLine->getChar(i);
00474           len++;
00475         }
00476       } while (start < end);
00477       if (textLine->isSelected()) {
00478         s[len] = '\n';
00479         len++;
00480       }
00481     }
00482 //    s[len] = '\0';
00483     return s;
00484   } else {
00485     for (z = selectStart; z <= selectEnd; z++) {
00486       textLine = getTextLine(z);
00487       len += textLine->numSelected() + 1;
00488     }
00489     QString s;
00490     len = 0;
00491     for (z = selectStart; z <= selectEnd; z++) {
00492       textLine = getTextLine(z);
00493       end = 0;
00494       do {
00495         start = textLine->findUnselected(end);
00496         end = textLine->findSelected(start);
00497         for (i = start; i < end; i++) {
00498           s[len] = textLine->getChar(i);
00499           len++;
00500         }
00501       } while (start < end);
00502       s[len] = '\n';
00503       len++;
00504     }
00505 //    s[len] = '\0';       //  the final \0 is not counted in length()
00506     return s;
00507   }
00508 }
00509 
00510 int KateDocument::numLines() const
00511 {
00512   return buffer->count();
00513 }
00514 
00515 
00516 TextLine::Ptr KateDocument::getTextLine(int line) const
00517 {
00518   // This is a hack to get this stuff working.
00519   return buffer->line(line);
00520 }
00521 
00522 int KateDocument::textLength(int line) {
00523   TextLine::Ptr textLine = getTextLine(line);
00524   if (!textLine) return 0;
00525   return textLine->length();
00526 }
00527 
00528 void KateDocument::setTabWidth(int chars) {
00529   if (tabChars == chars) return;
00530   if (chars < 1) chars = 1;
00531   if (chars > 16) chars = 16;
00532   tabChars = chars;
00533   updateFontData();
00534 
00535   maxLength = -1;
00536   for (int i=0; i < buffer->count(); i++)
00537   {
00538     TextLine::Ptr textLine = buffer->line(i);
00539     int len = textWidth(textLine,textLine->length());
00540     if (len > maxLength) {
00541       maxLength = len;
00542       longestLine = textLine;
00543     }
00544   }
00545 }
00546 
00547 void KateDocument::setReadOnly(bool m) {
00548   KTextEditor::View *view;
00549 
00550   if (m != readOnly) {
00551     readOnly = m;
00552 //    if (readOnly) recordReset();
00553     for (view = m_views.first(); view != 0L; view = m_views.next() ) {
00554       emit static_cast<KateView *>( view )->newStatus();
00555     }
00556   }
00557 }
00558 
00559 bool KateDocument::isReadOnly() const {
00560   return readOnly;
00561 }
00562 
00563 void KateDocument::setNewDoc( bool m )
00564 {
00565 //  KTextEditor::View *view;
00566 
00567   if ( m != newDoc )
00568   {
00569     newDoc = m;
00571 //    for (view = m_views.first(); view != 0L; view = m_views.next() ) {
00572 //      emit static_cast<KateView *>( view )->newStatus();
00573 //    }
00574   }
00575 }
00576 
00577 bool KateDocument::isNewDoc() const {
00578   return newDoc;
00579 }
00580 
00581 void KateDocument::setModified(bool m) {
00582   KTextEditor::View *view;
00583 
00584   if (m != modified) {
00585     modified = m;
00586     for (view = m_views.first(); view != 0L; view = m_views.next() ) {
00587       emit static_cast<KateView *>( view )->newStatus();
00588     }
00589     emit modifiedChanged ();
00590   }
00591 }
00592 
00593 bool KateDocument::isModified() const {
00594   return modified;
00595 }
00596 
00597 void KateDocument::readConfig()
00598 {
00599   KateConfig *config = KGlobal::config();
00600   config->setGroup("Kate Document");
00601 
00602   myWordWrap = config->readBoolEntry("Word Wrap On", false);
00603   myWordWrapAt = config->readNumEntry("Word Wrap At", 80);
00604   if (myWordWrap)
00605     wrapText (myWordWrapAt);
00606 
00607   setTabWidth(config->readNumEntry("TabWidth", 8));
00608   setUndoSteps(config->readNumEntry("UndoSteps", 50));
00609   m_singleSelection = config->readBoolEntry("SingleSelection", false);
00610   myEncoding = config->readEntry("Encoding", QString::fromLatin1(QTextCodec::codecForLocale()->name()));
00611   setFont (config->readFontEntry("Font", myFont));
00612 
00613   colors[0] = config->readColorEntry("Color Background", colors[0]);
00614   colors[1] = config->readColorEntry("Color Selected", colors[1]);
00615 
00616 //  config->sync();
00617 }
00618 
00619 void KateDocument::writeConfig()
00620 {
00621   KateConfig *config = KGlobal::config();
00622   config->setGroup("Kate Document");
00623   config->writeEntry("Word Wrap On", myWordWrap);
00624   config->writeEntry("Word Wrap At", myWordWrapAt);
00625   config->writeEntry("TabWidth", tabChars);
00626   config->writeEntry("UndoSteps", undoSteps);
00627   config->writeEntry("SingleSelection", m_singleSelection);
00628   config->writeEntry("Encoding", myEncoding);
00629   config->writeEntry("Font", myFont);
00630   config->writeEntry("Color Background", colors[0]);
00631   config->writeEntry("Color Selected", colors[1]);
00632 //  config->sync();
00633 }
00634 
00635 void KateDocument::readSessionConfig(KateConfig *config)
00636 {
00637   m_url = config->readEntry("URL"); // ### doesn't this break the encoding? (Simon)
00638   setHighlight(hlManager->nameFind(config->readEntry("Highlight")));
00639   // anders: restore bookmarks if possible
00640   QValueList<int> l = config->readIntListEntry("Bookmarks");
00641   if ( l.count() ) {
00642     for (uint i=0; i < l.count(); i++) {
00643       if ( numLines() < l[i] ) break;
00644       getTextLine( l[i] )->addMark( Bookmark );
00645     }
00646   }
00647 }
00648 
00649 void KateDocument::writeSessionConfig(KateConfig *config)
00650 {
00651 #if 0
00652   config->writeEntry("URL", m_url); // ### encoding?? (Simon)
00653   config->writeEntry("Highlight", m_highlight->name());
00654   // anders: save bookmarks
00655   QList<Kate::Mark> l = marks();
00656   QValueList<int> ml;
00657   for (uint i=0; i < l.count(); i++) {
00658     if ( l.at(i)->type == 1) // only save bookmarks
00659      ml << l.at(i)->line;
00660   }
00661   if ( ml.count() )
00662     config->writeEntry("Bookmarks", ml);
00663 #endif
00664 }
00665 
00666 
00667 void KateDocument::setHighlight(int n) {
00668   Highlight *h;
00669 
00670 //  hlNumber = n;
00671 
00672   h = hlManager->getHl(n);
00673   if (h == m_highlight) {
00674     updateLines();
00675   } else {
00676     if (m_highlight != 0L) m_highlight->release();
00677     h->use();
00678     m_highlight = h;
00679     makeAttribs();
00680   }
00681   PreHighlightedTill=0;
00682   RequestPreHighlightTill=0;
00683   emit(highlightChanged());
00684 }
00685 
00686 void KateDocument::makeAttribs() {
00687   odebug << "KateDocument::makeAttribs()" << oendl;
00688   m_numAttribs = hlManager->makeAttribs(m_highlight, m_attribs, maxAttribs);
00689   updateFontData();
00690   updateLines();
00691 }
00692 
00693 void KateDocument::updateFontData() {
00694   int maxAscent, maxDescent;
00695   int tabWidth;
00696   KateView *view;
00697 
00698   maxAscent = myFontMetrics.ascent();
00699   maxDescent = myFontMetrics.descent();
00700   tabWidth = myFontMetrics.width(' ');
00701 
00702   fontHeight = maxAscent + maxDescent + 1;
00703   fontAscent = maxAscent;
00704   m_tabWidth = tabChars*tabWidth;
00705 
00706   for (view = views.first(); view != 0L; view = views.next() ) {
00707     view->myViewInternal->drawBuffer->resize(view->width(),fontHeight);
00708     view->tagAll();
00709     view->updateCursor();
00710   }
00711 }
00712 
00713 void KateDocument::hlChanged() { //slot
00714   makeAttribs();
00715   updateViews();
00716 }
00717 
00718 
00719 void KateDocument::addView(KTextEditor::View *view) {
00720   views.append( static_cast<KateView *>( view ) );
00721   KTextEditor::Document::addView( view );
00722   connect( static_cast<KateView *>( view ), SIGNAL( destroyed() ), this, SLOT( slotViewDestroyed() ) );
00723 }
00724 
00725 void KateDocument::removeView(KTextEditor::View *view) {
00726 //  if (undoView == view) recordReset();
00727   disconnect( static_cast<KateView *>( view ), SIGNAL( destroyed() ), this, SLOT( slotViewDestroyed() ) );
00728   views.removeRef( static_cast<KateView *>( view ) );
00729   KTextEditor::Document::removeView( view );
00730 }
00731 
00732 void KateDocument::slotViewDestroyed()
00733 {
00734   views.removeRef( static_cast<const KateView *>( sender() ) );
00735 }
00736 
00737 bool KateDocument::ownedView(KateView *view) {
00738   // do we own the given view?
00739   return (views.containsRef(view) > 0);
00740 }
00741 
00742 bool KateDocument::isLastView(int numViews) {
00743   return ((int) views.count() == numViews);
00744 }
00745 
00746 int KateDocument::textWidth(const TextLine::Ptr &textLine, int cursorX) {
00747   int x;
00748   int z;
00749   QChar ch;
00750   Attribute *a;
00751 
00752   x = 0;
00753   for (z = 0; z < cursorX; z++) {
00754     ch = textLine->getChar(z);
00755     a = &m_attribs[textLine->getAttr(z)];
00756 
00757     if (ch == '\t')
00758       x += m_tabWidth - (x % m_tabWidth);
00759     else if (a->bold && a->italic)
00760       x += myFontMetricsBI.width(ch);
00761     else if (a->bold)
00762       x += myFontMetricsBold.width(ch);
00763     else if (a->italic)
00764       x += myFontMetricsItalic.width(ch);
00765     else
00766       x += myFontMetrics.width(ch);
00767   }
00768   return x;
00769 }
00770 
00771 int KateDocument::textWidth(PointStruc &cursor) {
00772   if (cursor.x < 0)
00773      cursor.x = 0;
00774   if (cursor.y < 0)
00775      cursor.y = 0;
00776   if (cursor.y >= numLines())
00777      cursor.y = lastLine();
00778   return textWidth(getTextLine(cursor.y),cursor.x);
00779 }
00780 
00781 int KateDocument::textWidth(bool wrapCursor, PointStruc &cursor, int xPos) {
00782   int len;
00783   int x, oldX;
00784   int z;
00785   QChar ch;
00786   Attribute *a;
00787 
00788   if (cursor.y < 0) cursor.y = 0;
00789   if (cursor.y > lastLine()) cursor.y = lastLine();
00790   TextLine::Ptr textLine = getTextLine(cursor.y);
00791   len = textLine->length();
00792 
00793   x = oldX = z = 0;
00794   while (x < xPos && (!wrapCursor || z < len)) {
00795     oldX = x;
00796     ch = textLine->getChar(z);
00797     a = &m_attribs[textLine->getAttr(z)];
00798 
00799     if (ch == '\t')
00800       x += m_tabWidth - (x % m_tabWidth);
00801     else if (a->bold && a->italic)
00802       x += myFontMetricsBI.width(ch);
00803     else if (a->bold)
00804       x += myFontMetricsBold.width(ch);
00805     else if (a->italic)
00806       x += myFontMetricsItalic.width(ch);
00807     else
00808       x += myFontMetrics.width(ch);
00809 
00810     z++;
00811   }
00812   if (xPos - oldX < x - xPos && z > 0) {
00813     z--;
00814     x = oldX;
00815   }
00816   cursor.x = z;
00817   return x;
00818 }
00819 
00820 
00821 int KateDocument::textPos(const TextLine::Ptr &textLine, int xPos) {
00822   int x, oldX;
00823   int z;
00824   QChar ch;
00825   Attribute *a;
00826 
00827   x = oldX = z = 0;
00828   while (x < xPos) { // && z < len) {
00829     oldX = x;
00830     ch = textLine->getChar(z);
00831     a = &m_attribs[textLine->getAttr(z)];
00832 
00833     if (ch == '\t')
00834       x += m_tabWidth - (x % m_tabWidth);
00835     else if (a->bold && a->italic)
00836       x += myFontMetricsBI.width(ch);
00837     else if (a->bold)
00838       x += myFontMetricsBold.width(ch);
00839     else if (a->italic)
00840       x += myFontMetricsItalic.width(ch);
00841     else
00842       x += myFontMetrics.width(ch);
00843 
00844     z++;
00845   }
00846   if (xPos - oldX < x - xPos && z > 0) {
00847     z--;
00848    // newXPos = oldX;
00849   }// else newXPos = x;
00850   return z;
00851 }
00852 
00853 int KateDocument::textWidth() {
00854    return int(maxLength + 8);
00855 }
00856 
00857 int KateDocument::textHeight() {
00858   return numLines()*fontHeight;
00859 }
00860 
00861 void KateDocument::insert(VConfig &c, const QString &s) {
00862   int pos;
00863   QChar ch;
00864   QString buf;
00865 
00866   if (s.isEmpty()) return;
00867 
00868   recordStart(c, KateActionGroup::ugPaste);
00869 
00870   pos = 0;
00871   if (!(c.flags & KateView::cfVerticalSelect)) {
00872     do {
00873       ch = s[pos];
00874       if (ch.isPrint() || ch == '\t') {
00875         buf += ch; // append char to buffer
00876       } else if (ch == '\n') {
00877         recordAction(KateAction::newLine, c.cursor); // wrap contents behind cursor to new line
00878         recordInsert(c, buf); // append to old line
00879 //        c.cursor.x += buf.length();
00880         buf.truncate(0); // clear buffer
00881         c.cursor.y++;
00882         c.cursor.x = 0;
00883       }
00884       pos++;
00885     } while (pos < (int) s.length());
00886   } else {
00887     int xPos;
00888 
00889     xPos = textWidth(c.cursor);
00890     do {
00891       ch = s[pos];
00892       if (ch.isPrint() || ch == '\t') {
00893         buf += ch;
00894       } else if (ch == '\n') {
00895         recordInsert(c, buf);
00896         c.cursor.x += buf.length();
00897         buf.truncate(0);
00898         c.cursor.y++;
00899         if (c.cursor.y >= numLines())
00900           recordAction(KateAction::insLine, c.cursor);
00901         c.cursor.x = textPos(getTextLine(c.cursor.y), xPos);
00902       }
00903       pos++;
00904     } while (pos < (int) s.length());
00905   }
00906   recordInsert(c, buf);
00907   c.cursor.x += buf.length();
00908   recordEnd(c);
00909 }
00910 
00911 void KateDocument::insertFile(VConfig &c, QIODevice &dev)
00912 {
00913   recordStart(c, KateActionGroup::ugPaste);
00914 
00915   QString buf;
00916   QChar ch, last;
00917 
00918   QTextStream stream( &dev );
00919 
00920   while ( !stream.atEnd() ) {
00921     stream >> ch;
00922 
00923     if (ch.isPrint() || ch == '\t') {
00924         buf += ch;
00925     } else if (ch == '\n' || ch == '\r') {
00926         if (last != '\r' || ch != '\n') {
00927           recordAction(KateAction::newLine, c.cursor);
00928           recordInsert(c, buf);
00929           buf.truncate(0);
00930           c.cursor.y++;
00931           c.cursor.x = 0;
00932         }
00933         last = ch;
00934     }
00935   }
00936 
00937   recordInsert(c, buf);
00938   recordEnd(c);
00939 }
00940 
00941 int KateDocument::currentColumn(PointStruc &cursor) {
00942   return getTextLine(cursor.y)->cursorX(cursor.x,tabChars);
00943 }
00944 
00945 bool KateDocument::insertChars(VConfig &c, const QString &chars) {
00946   int z, pos, l;
00947   bool onlySpaces;
00948   QChar ch;
00949   QString buf;
00950 
00951   TextLine::Ptr textLine = getTextLine(c.cursor.y);
00952 
00953   pos = 0;
00954   onlySpaces = true;
00955   for (z = 0; z < (int) chars.length(); z++) {
00956     ch = chars[z];
00957     if (ch == '\t' && c.flags & KateView::cfReplaceTabs) {
00958       l = tabChars - (textLine->cursorX(c.cursor.x, tabChars) % tabChars);
00959       while (l > 0) {
00960         buf.insert(pos, ' ');
00961         pos++;
00962         l--;
00963       }
00964     } else if (ch.isPrint() || ch == '\t') {
00965       buf.insert(pos, ch);
00966       pos++;
00967       if (ch != ' ') onlySpaces = false;
00968       if (c.flags & KateView::cfAutoBrackets) {
00969         if (ch == '(') buf.insert(pos, ')');
00970         if (ch == '[') buf.insert(pos, ']');
00971         if (ch == '{') buf.insert(pos, '}');
00972       }
00973     }
00974   }
00975   //pos = cursor increment
00976 
00977   //return false if nothing has to be inserted
00978   if (buf.isEmpty()) return false;
00979 
00980   //auto deletion of the marked text occurs not very often and can therefore
00981   //  be recorded separately
00982   if (c.flags &KateView:: cfDelOnInput) delMarkedText(c);
00983 
00984   recordStart(c, KateActionGroup::ugInsChar);
00985   recordReplace(c/*.cursor*/, (c.flags & KateView::cfOvr) ? buf.length() : 0, buf);
00986   c.cursor.x += pos;
00987 
00988   if (myWordWrap && myWordWrapAt > 0) {
00989     int line;
00990     const QChar *s;
00991 //    int pos;
00992     PointStruc actionCursor;
00993 
00994     line = c.cursor.y;
00995     do {
00996       textLine = getTextLine(line);
00997       s = textLine->getText();
00998       l = textLine->length();
00999       for (z = myWordWrapAt; z < l; z++) if (!s[z].isSpace()) break; //search for text to wrap
01000       if (z >= l) break; // nothing more to wrap
01001       pos = myWordWrapAt;
01002       for (; z >= 0; z--) { //find wrap position
01003         if (s[z].isSpace()) {
01004           pos = z + 1;
01005           break;
01006         }
01007       }
01008       //pos = wrap position
01009 
01010       if (line == c.cursor.y && pos <= c.cursor.x) {
01011         //wrap cursor
01012         c.cursor.y++;
01013         c.cursor.x -= pos;
01014       }
01015 
01016       if (line == lastLine() || (getTextLine(line+1)->length() == 0) ) {
01017         //at end of doc: create new line
01018         actionCursor.x = pos;
01019         actionCursor.y = line;
01020         recordAction(KateAction::newLine,actionCursor);
01021       } else {
01022         //wrap
01023         actionCursor.y = line + 1;
01024         if (!s[l - 1].isSpace()) { //add space in next line if necessary
01025           actionCursor.x = 0;
01026           recordInsert(actionCursor, " ");
01027         }
01028         actionCursor.x = textLine->length() - pos;
01029         recordAction(KateAction::wordWrap, actionCursor);
01030       }
01031       line++;
01032     } while (true);
01033   }
01034   recordEnd(c);
01035   return true;
01036 }
01037 
01038 QString tabString(int pos, int tabChars) {
01039   QString s;
01040   while (pos >= tabChars) {
01041     s += '\t';
01042     pos -= tabChars;
01043   }
01044   while (pos > 0) {
01045     s += ' ';
01046     pos--;
01047   }
01048   return s;
01049 }
01050 
01051 void KateDocument::newLine(VConfig &c) {
01052 
01053   //auto deletion of marked text is done by the view to have a more
01054   // "low level" KateDocument::newLine method
01055   recordStart(c, KateActionGroup::ugInsLine);
01056 
01057   if (!(c.flags & KateView::cfAutoIndent)) {
01058     recordAction(KateAction::newLine,c.cursor);
01059     c.cursor.y++;
01060     c.cursor.x = 0;
01061   } else {
01062     TextLine::Ptr textLine = getTextLine(c.cursor.y);
01063     int pos = textLine->firstChar();
01064     if (c.cursor.x < pos) c.cursor.x = pos; // place cursor on first char if before
01065 
01066     int y = c.cursor.y;
01067     while ((y > 0) && (pos < 0)) { // search a not empty text line
01068       textLine = getTextLine(--y);
01069       pos = textLine->firstChar();
01070     }
01071     recordAction(KateAction::newLine, c.cursor);
01072     c.cursor.y++;
01073     c.cursor.x = 0;
01074     if (pos > 0) {
01075       pos = textLine->cursorX(pos, tabChars);
01076 //      if (getTextLine(c.cursor.y)->length() > 0) {
01077         QString s = tabString(pos, (c.flags & KateView::cfSpaceIndent) ? 0xffffff : tabChars);
01078         recordInsert(c.cursor, s);
01079         pos = s.length();
01080 //      }
01081 //      recordInsert(c.cursor, QString(textLine->getText(), pos));
01082       c.cursor.x = pos;
01083     }
01084   }
01085 
01086   recordEnd(c);
01087 }
01088 
01089 void KateDocument::killLine(VConfig &c) {
01090 
01091   recordStart(c, KateActionGroup::ugDelLine);
01092   c.cursor.x = 0;
01093   recordDelete(c.cursor, 0xffffff);
01094   if (c.cursor.y < lastLine()) {
01095     recordAction(KateAction::killLine, c.cursor);
01096   }
01097   recordEnd(c);
01098 }
01099 
01100 void KateDocument::backspace(VConfig &c) {
01101 
01102   if (c.cursor.x <= 0 && c.cursor.y <= 0) return;
01103 
01104   if (c.cursor.x > 0) {
01105     recordStart(c, KateActionGroup::ugDelChar);
01106     if (!(c.flags & KateView::cfBackspaceIndents)) {
01107       // ordinary backspace
01108       c.cursor.x--;
01109       recordDelete(c.cursor, 1);
01110     } else {
01111       // backspace indents: erase to next indent position
01112       int l = 1; // del one char
01113 
01114       TextLine::Ptr textLine = getTextLine(c.cursor.y);
01115       int pos = textLine->firstChar();
01116       if (pos < 0 || pos >= c.cursor.x) {
01117         // only spaces on left side of cursor
01118         // search a line with less spaces
01119         int y = c.cursor.y;
01120         while (y > 0) {
01121           textLine = getTextLine(--y);
01122           pos = textLine->firstChar();
01123           if (pos >= 0 && pos < c.cursor.x) {
01124             l = c.cursor.x - pos; // del more chars
01125             break;
01126           }
01127         }
01128       }
01129       // break effectively jumps here
01130       c.cursor.x -= l;
01131       recordDelete(c.cursor, l);
01132     }
01133   } else {
01134     // c.cursor.x == 0: wrap to previous line
01135     recordStart(c, KateActionGroup::ugDelLine);
01136     c.cursor.y--;
01137     c.cursor.x = getTextLine(c.cursor.y)->length();
01138     recordAction(KateAction::delLine,c.cursor);
01139   }
01140   recordEnd(c);
01141 }
01142 
01143 
01144 void KateDocument::del(VConfig &c) {
01145   TextLine::Ptr textLine = getTextLine(c.cursor.y);
01146   int len =  (c.flags & KateView::cfRemoveSpaces) ? textLine->lastChar() : textLine->length();
01147   if (c.cursor.x < len/*getTextLine(c.cursor.y)->length()*/) {
01148     // delete one character
01149     recordStart(c, KateActionGroup::ugDelChar);
01150     recordDelete(c.cursor, 1);
01151     recordEnd(c);
01152   } else {
01153     if (c.cursor.y < lastLine()) {
01154       // wrap next line to this line
01155       textLine->truncate(c.cursor.x); // truncate spaces
01156       recordStart(c, KateActionGroup::ugDelLine);
01157       recordAction(KateAction::delLine,c.cursor);
01158       recordEnd(c);
01159     }
01160   }
01161 }
01162 
01163 void KateDocument::clear() {
01164   PointStruc cursor;
01165   KateView *view;
01166 
01167   setPseudoModal(0L);
01168   cursor.x = cursor.y = 0;
01169   for (view = views.first(); view != 0L; view = views.next() ) {
01170     view->updateCursor(cursor);
01171     view->tagAll();
01172   }
01173 
01174   eolMode = KateDocument::eolUnix;
01175 
01176   buffer->clear();
01177   longestLine = buffer->line(0);
01178 
01179   maxLength = 0;
01180 
01181   select.x = -1;
01182 
01183   selectStart = 0xffffff;
01184   selectEnd = 0;
01185   oldMarkState = false;
01186 
01187   setModified(false);
01188 
01189   undoList.clear();
01190   currentUndo = 0;
01191   newUndo();
01192 }
01193 
01194 void KateDocument::cut(VConfig &c) {
01195 
01196   if (selectEnd < selectStart) return;
01197 
01198   copy(c.flags);
01199   delMarkedText(c);
01200 }
01201 
01202 void KateDocument::copy(int flags) {
01203 
01204   if (selectEnd < selectStart) return;
01205 
01206   QString s = markedText(flags);
01207   if (!s.isEmpty()) {
01208 //#if defined(_WS_X11_)
01209     if (m_singleSelection)
01210       disconnect(QApplication::clipboard(), SIGNAL(dataChanged()), this, 0);
01211 //#endif
01212     QApplication::clipboard()->setText(s);
01213 //#if defined(_WS_X11_)
01214     if (m_singleSelection) {
01215       connect(QApplication::clipboard(), SIGNAL(dataChanged()),
01216         this, SLOT(clipboardChanged()));
01217     }
01218 //#endif
01219   }
01220 }
01221 
01222 void KateDocument::paste(VConfig &c) {
01223   QString s = QApplication::clipboard()->text();
01224   if (!s.isEmpty()) {
01225     insert(c, s);
01226   }
01227 }
01228 
01229 void KateDocument::toggleRect(int start, int end, int x1, int x2) {
01230   int z, line;
01231   bool t;
01232 
01233   if (x1 > x2) {
01234     z = x1;
01235     x1 = x2;
01236     x2 = z;
01237   }
01238   if (start > end) {
01239     z = start;
01240     start = end;
01241     end = z;
01242   }
01243 
01244   t = false;
01245   for (line = start; line < end; line++) {
01246     int x, oldX, s, e, newX1, newX2;
01247     QChar ch;
01248     Attribute *a;
01249 
01250     TextLine::Ptr textLine = getTextLine(line);
01251 
01252     //--- speed optimization
01253     //s = textPos(textLine, x1, newX1);
01254     x = oldX = z = 0;
01255     while (x < x1) { // && z < len) {
01256       oldX = x;
01257       ch = textLine->getChar(z);
01258       a = &m_attribs[textLine->getAttr(z)];
01259 
01260     if (ch == '\t')
01261       x += m_tabWidth - (x % m_tabWidth);
01262     else if (a->bold && a->italic)
01263       x += myFontMetricsBI.width(ch);
01264     else if (a->bold)
01265       x += myFontMetricsBold.width(ch);
01266     else if (a->italic)
01267       x += myFontMetricsItalic.width(ch);
01268     else
01269       x += myFontMetrics.width(ch);
01270 
01271       z++;
01272     }
01273     s = z;
01274     if (x1 - oldX < x - x1 && z > 0) {
01275       s--;
01276       newX1 = oldX;
01277     } else newX1 = x;
01278     //e = textPos(textLine, x2, newX2);
01279     while (x < x2) { // && z < len) {
01280       oldX = x;
01281       ch = textLine->getChar(z);
01282       a = &m_attribs[textLine->getAttr(z)];
01283 
01284     if (ch == '\t')
01285       x += m_tabWidth - (x % m_tabWidth);
01286     else if (a->bold && a->italic)
01287       x += myFontMetricsBI.width(ch);
01288     else if (a->bold)
01289       x += myFontMetricsBold.width(ch);
01290     else if (a->italic)
01291       x += myFontMetricsItalic.width(ch);
01292     else
01293       x += myFontMetrics.width(ch);
01294 
01295       z++;
01296     }
01297     e = z;
01298     if (x2 - oldX < x - x2 && z > 0) {
01299       e--;
01300       newX2 = oldX;
01301     } else newX2 = x;
01302     //---
01303 
01304     if (e > s) {
01305       textLine->toggleSelect(s, e);
01306       tagLineRange(line, newX1, newX2);
01307       t = true;
01308     }
01309   }
01310   if (t) {
01311     end--;
01312 //    tagLines(start, end);
01313 
01314     if (start < selectStart) selectStart = start;
01315     if (end > selectEnd) selectEnd = end;
01316     emit selectionChanged();
01317   }
01318 }
01319 
01320 void KateDocument::selectTo(VConfig &c, PointStruc &cursor, int cXPos) {
01321   //c.cursor = old cursor position
01322   //cursor = new cursor position
01323 
01324   if (c.cursor.x != select.x || c.cursor.y != select.y) {
01325     //new selection
01326 
01327     if (!(c.flags & KateView::cfKeepSelection)) deselectAll();
01328 //      else recordReset();
01329 
01330     anchor = c.cursor;
01331     aXPos = c.cXPos;
01332   }
01333 
01334   if (!(c.flags & KateView::cfVerticalSelect)) {
01335     //horizontal selections
01336     int x, y, sXPos;
01337     int ex, ey, eXPos;
01338     bool sel;
01339 
01340     if (cursor.y > c.cursor.y || (cursor.y == c.cursor.y && cursor.x > c.cursor.x)) {
01341       x = c.cursor.x;
01342       y = c.cursor.y;
01343       sXPos = c.cXPos;
01344       ex = cursor.x;
01345       ey = cursor.y;
01346       eXPos = cXPos;
01347       sel = true;
01348     } else {
01349       x = cursor.x;
01350       y = cursor.y;
01351       sXPos = cXPos;
01352       ex = c.cursor.x;
01353       ey = c.cursor.y;
01354       eXPos = c.cXPos;
01355       sel = false;
01356     }
01357 
01358 //    tagLines(y, ye);
01359     if (y < ey) {
01360       //tagLineRange(y, sXPos, 0xffffff);
01361       tagLines(y, ey -1);
01362       tagLineRange(ey, 0, eXPos);
01363     } else tagLineRange(y, sXPos, eXPos);
01364 
01365     if (y < selectStart) selectStart = y;
01366     if (ey > selectEnd) selectEnd = ey;
01367 
01368     TextLine::Ptr textLine = getTextLine(y);
01369 
01370     if (c.flags & KateView::cfXorSelect) {
01371       //xor selection with old selection
01372       while (y < ey) {
01373         textLine->toggleSelectEol(x);
01374         x = 0;
01375         y++;
01376         textLine = getTextLine(y);
01377       }
01378       textLine->toggleSelect(x, ex);
01379     } else {
01380       //set selection over old selection
01381 
01382       if (anchor.y > y || (anchor.y == y && anchor.x > x)) {
01383         if (anchor.y < ey || (anchor.y == ey && anchor.x < ex)) {
01384           sel = !sel;
01385           while (y < anchor.y) {
01386             textLine->selectEol(sel, x);
01387             x = 0;
01388             y++;
01389             textLine = getTextLine(y);
01390           }
01391           textLine->select(sel, x, anchor.x);
01392           x = anchor.x;
01393         }
01394         sel = !sel;
01395       }
01396       while (y < ey) {
01397         textLine->selectEol(sel, x);
01398         x = 0;
01399         y++;
01400         textLine = getTextLine(y);
01401       }
01402       textLine->select(sel, x, ex);
01403     }
01404   } else {
01405     //vertical (block) selections
01406 //    int ax, sx, ex;
01407 
01408 //    ax = textWidth(anchor);
01409 //    sx = textWidth(start);
01410 //    ex = textWidth(end);
01411 
01412     toggleRect(c.cursor.y + 1, cursor.y + 1, aXPos, c.cXPos);
01413     toggleRect(anchor.y, cursor.y + 1, c.cXPos, cXPos);
01414   }
01415   select = cursor;
01416   optimizeSelection();
01417   emit selectionChanged();
01418 }
01419 
01420 
01421 void KateDocument::selectAll() {
01422   int z;
01423   TextLine::Ptr textLine;
01424 
01425   select.x = -1;
01426 
01427 //  if (selectStart != 0 || selectEnd != lastLine()) recordReset();
01428 
01429   selectStart = 0;
01430   selectEnd = lastLine();
01431 
01432   tagLines(selectStart,selectEnd);
01433 
01434   for (z = selectStart; z < selectEnd; z++) {
01435     textLine = getTextLine(z);
01436     textLine->selectEol(true,0);
01437   }
01438   textLine = getTextLine(z);
01439   textLine->select(true,0,textLine->length());
01440   emit selectionChanged();
01441 }
01442 
01443 void KateDocument::deselectAll() {
01444   select.x = -1;
01445   if (selectEnd < selectStart) return;
01446 
01447 //  recordReset();
01448 
01449   tagLines(selectStart,selectEnd);
01450 
01451   for (int z = selectStart; z <= selectEnd; z++) {
01452     TextLine::Ptr textLine = getTextLine(z);
01453     textLine->selectEol(false,0);
01454   }
01455   selectStart = 0xffffff;
01456   selectEnd = 0;
01457   emit selectionChanged();
01458 }
01459 
01460 void KateDocument::invertSelection() {
01461   TextLine::Ptr textLine;
01462 
01463   select.x = -1;
01464 
01465 //  if (selectStart != 0 || selectEnd != lastLine()) recordReset();
01466 
01467   selectStart = 0;
01468   selectEnd = lastLine();
01469 
01470   tagLines(selectStart,selectEnd);
01471 
01472   for (int z = selectStart; z < selectEnd; z++) {
01473     textLine = getTextLine(z);
01474     textLine->toggleSelectEol(0);
01475   }
01476   textLine = getTextLine(selectEnd);
01477   textLine->toggleSelect(0,textLine->length());
01478   optimizeSelection();
01479   emit selectionChanged();
01480 }
01481 
01482 void KateDocument::selectWord(PointStruc &cursor, int flags) {
01483   int start, end, len;
01484 
01485   TextLine::Ptr textLine = getTextLine(cursor.y);
01486   len = textLine->length();
01487   start = end = cursor.x;
01488   while (start > 0 && m_highlight->isInWord(textLine->getChar(start - 1))) start--;
01489   while (end < len && m_highlight->isInWord(textLine->getChar(end))) end++;
01490   if (end <= start) return;
01491   if (!(flags & KateView::cfKeepSelection)) deselectAll();
01492 //    else recordReset();
01493 
01494   textLine->select(true, start, end);
01495 
01496   anchor.x = start;
01497   select.x = end;
01498   anchor.y = select.y = cursor.y;
01499   tagLines(cursor.y, cursor.y);
01500   if (cursor.y < selectStart) selectStart = cursor.y;
01501   if (cursor.y > selectEnd) selectEnd = cursor.y;
01502   emit selectionChanged();
01503 }
01504 
01505 void KateDocument::selectLength(PointStruc &cursor, int length, int flags) {
01506   int start, end;
01507 
01508   TextLine::Ptr textLine = getTextLine(cursor.y);
01509   start = cursor.x;
01510   end = start + length;
01511   if (end <= start) return;
01512   if (!(flags & KateView::cfKeepSelection)) deselectAll();
01513 
01514   textLine->select(true, start, end);
01515 
01516   anchor.x = start;
01517   select.x = end;
01518   anchor.y = select.y = cursor.y;
01519   tagLines(cursor.y, cursor.y);
01520   if (cursor.y < selectStart) selectStart = cursor.y;
01521   if (cursor.y > selectEnd) selectEnd = cursor.y;
01522   emit selectionChanged();
01523 }
01524 
01525 void KateDocument::doIndent(VConfig &c, int change) {
01526 
01527   c.cursor.x = 0;
01528 
01529   recordStart(c, (change < 0) ? KateActionGroup::ugUnindent
01530     : KateActionGroup::ugIndent);
01531 
01532   if (selectEnd < selectStart) {
01533     // single line
01534     optimizeLeadingSpace(c.cursor.y, c.flags, change);
01535   } else {
01536     // entire selection
01537     TextLine::Ptr textLine;
01538     int line, z;
01539     QChar ch;
01540 
01541     if (c.flags & KateView::cfKeepIndentProfile && change < 0) {
01542       // unindent so that the existing indent profile doesn´t get screwed
01543       // if any line we may unindent is already full left, don't do anything
01544       for (line = selectStart; line <= selectEnd; line++) {
01545         textLine = getTextLine(line);
01546         if (textLine->isSelected() || textLine->numSelected()) {
01547           for (z = 0; z < tabChars; z++) {
01548             ch = textLine->getChar(z);
01549             if (ch == '\t') break;
01550             if (ch != ' ') {
01551               change = 0;
01552               goto jumpOut;
01553             }
01554           }
01555         }
01556       }
01557       jumpOut:;
01558     }
01559 
01560     for (line = selectStart; line <= selectEnd; line++) {
01561       textLine = getTextLine(line);
01562       if (textLine->isSelected() || textLine->numSelected()) {
01563         optimizeLeadingSpace(line, c.flags, change);
01564       }
01565     }
01566   }
01567   // recordEnd now removes empty undo records
01568   recordEnd(c.view, c.cursor, c.flags | KateView::cfPersistent);
01569 }
01570 
01571 /*
01572   Optimize the leading whitespace for a single line.
01573   If change is > 0, it adds indentation units (tabChars)
01574   if change is == 0, it only optimizes
01575   If change is < 0, it removes indentation units
01576   This will be used to indent, unindent, and optimal-fill a line.
01577   If excess space is removed depends on the flag cfKeepExtraSpaces
01578   which has to be set by the user
01579 */
01580 void KateDocument::optimizeLeadingSpace(int line, int flags, int change) {
01581   int len;
01582   int chars, space, okLen;
01583   QChar ch;
01584   int extra;
01585   QString s;
01586   PointStruc cursor;
01587 
01588   TextLine::Ptr textLine = getTextLine(line);
01589   len = textLine->length();
01590   space = 0; // length of space at the beginning of the textline
01591   okLen = 0; // length of space which does not have to be replaced
01592   for (chars = 0; chars < len; chars++) {
01593     ch = textLine->getChar(chars);
01594     if (ch == ' ') {
01595       space++;
01596       if (flags & KateView::cfSpaceIndent && okLen == chars) okLen++;
01597     } else if (ch == '\t') {
01598       space += tabChars - space % tabChars;
01599       if (!(flags & KateView::cfSpaceIndent) && okLen == chars) okLen++;
01600     } else break;
01601   }
01602 
01603   space += change*tabChars; // modify space width
01604   // if line contains only spaces it will be cleared
01605   if (space < 0 || chars == len) space = 0;
01606 
01607   extra = space % tabChars; // extra spaces which don´t fit the indentation pattern
01608   if (flags & KateView::cfKeepExtraSpaces) chars -= extra;
01609 
01610   if (flags & KateView::cfSpaceIndent) {
01611     space -= extra;
01612     ch = ' ';
01613   } else {
01614     space /= tabChars;
01615     ch = '\t';
01616   }
01617 
01618   // don´t replace chars which are already ok
01619   cursor.x = QMIN(okLen, QMIN(chars, space));
01620   chars -= cursor.x;
01621   space -= cursor.x;
01622   if (chars == 0 && space == 0) return; //nothing to do
01623 
01624   s.fill(ch, space);
01625 
01626 //printf("chars %d insert %d cursor.x %d\n", chars, insert, cursor.x);
01627   cursor.y = line;
01628   recordReplace(cursor, chars, s);
01629 }
01630 
01631 void KateDocument::doComment(VConfig &c, int change)
01632 {
01633   c.flags |=KateView:: cfPersistent;
01634 
01635   recordStart(c, (change < 0) ? KateActionGroup::ugUncomment
01636     : KateActionGroup::ugComment);
01637 
01638   QString startComment = m_highlight->getCommentStart();
01639   QString startLineComment = m_highlight->getCommentSingleLineStart();
01640   QString endComment = m_highlight->getCommentEnd();
01641 
01642   int startCommentLen = startComment.length();
01643   int startLineCommentLen = startLineComment.length();
01644   int endCommentLen = endComment.length();
01645 
01646   if (change > 0)
01647   {
01648     if ( !hasMarkedText() )
01649     {
01650       if (startLineComment != "")
01651       {
01652         // Add a start comment mark
01653         c.cursor.x = 0;
01654         recordReplace(c.cursor, 0, startLineComment);
01655       }
01656       else  if ((startComment != "") && (endComment != ""))
01657       {
01658         // Add a start comment mark
01659         c.cursor.x = 0;
01660         recordReplace(c.cursor, 0, startComment);
01661 
01662         // Add an end comment mark
01663         TextLine* textline = getTextLine(c.cursor.y);
01664         c.cursor.x = textline->length();
01665         recordReplace(c.cursor, 0, endComment);
01666         c.cursor.x = 0;
01667       }
01668     }
01669     else if ((startComment != "") && (endComment != ""))
01670     {
01671       QString marked (c.view->markedText ());
01672       int preDeleteLine = -1, preDeleteCol = -1;
01673       c.view->getCursorPosition (&preDeleteLine, &preDeleteCol);
01674 
01675       if (marked.length() > 0)
01676         c.view->keyDelete ();
01677 
01678       int line = -1, col = -1;
01679       c.view->getCursorPosition (&line, &col);
01680 
01681       c.view->insertText (startComment + marked + endComment);
01682     }
01683   }
01684   else
01685   {
01686     if ( !hasMarkedText() )
01687     {
01688       TextLine* textline = getTextLine(c.cursor.y);
01689 
01690       if(textline->startingWith(startLineComment))
01691       {
01692         // Remove start comment mark
01693         c.cursor.x = 0;
01694         recordReplace(c.cursor, startLineCommentLen, "");
01695       }
01696       else if (textline->startingWith(startComment) && textline->endingWith(endComment))
01697       {
01698         // Remove start comment mark
01699         c.cursor.x = 0;
01700         recordReplace(c.cursor, startCommentLen, "");
01701 
01702         // Remove end comment mark
01703         if(endComment != "")
01704         {
01705           c.cursor.x = textline->length() - endCommentLen;
01706           recordReplace(c.cursor, endCommentLen, "");
01707           c.cursor.x = 0;
01708         }
01709       }
01710     }
01711     else
01712     {
01713       QString marked (c.view->markedText ());
01714       int preDeleteLine = -1, preDeleteCol = -1;
01715       c.view->getCursorPosition (&preDeleteLine, &preDeleteCol);
01716 
01717       int start = marked.find (startComment);
01718       int end = marked.findRev (endComment);
01719 
01720       if ((start > -1) && (end > -1))
01721       {
01722         marked.remove (start, startCommentLen);
01723         marked.remove (end-startCommentLen, endCommentLen);
01724 
01725         c.view->keyDelete ();
01726 
01727         int line = -1, col = -1;
01728         c.view->getCursorPosition (&line, &col);
01729         c.view->insertText (marked);
01730       }
01731     }
01732   }
01733 
01734   recordEnd(c.view, c.cursor, c.flags | KateView::cfPersistent);
01735 }
01736 
01737 
01738 QString KateDocument::text() const
01739 {
01740   QString s;
01741 
01742   for (int i=0; i < buffer->count(); i++)
01743   {
01744     TextLine::Ptr textLine = buffer->line(i);
01745     s.insert(s.length(), textLine->getText(), textLine->length());
01746     if ( (i < (buffer->count()-1)) )
01747       s.append('\n');
01748   }
01749 
01750   return s;
01751 }
01752 
01753 QString KateDocument::getWord(PointStruc &cursor) {
01754   int start, end, len;
01755 
01756   TextLine::Ptr textLine = getTextLine(cursor.y);
01757   len = textLine->length();
01758   start = end = cursor.x;
01759   while (start > 0 && m_highlight->isInWord(textLine->getChar(start - 1))) start--;
01760   while (end < len && m_highlight->isInWord(textLine->getChar(end))) end++;
01761   len = end - start;
01762   return QString(&textLine->getText()[start], len);
01763 }
01764 
01765 void KateDocument::setText(const QString &s) {
01766   int pos;
01767   QChar ch;
01768 
01769   clear();
01770 
01771   int line=1;
01772 
01773   TextLine::Ptr textLine = buffer->line(0);
01774   for (pos = 0; pos <= (int) s.length(); pos++) {
01775     ch = s[pos];
01776     if (ch.isPrint() || ch == '\t') {
01777       textLine->append(&ch, 1);
01778     } else if (ch == '\n')
01779     {
01780       textLine = new TextLine();
01781       buffer->insertLine (line, textLine);
01782       line++;
01783     }
01784   }
01785   updateLines();
01786 }
01787 
01788 
01789 QString KateDocument::markedText(int flags) {
01790   TextLine::Ptr textLine;
01791   int len, z, start, end, i;
01792 
01793   len = 1;
01794   if (!(flags & KateView::cfVerticalSelect)) {
01795     for (z = selectStart; z <= selectEnd; z++) {
01796       textLine = getTextLine(z);
01797       len += textLine->numSelected();
01798       if (textLine->isSelected()) len++;
01799     }
01800     QString s;
01801     len = 0;
01802     for (z = selectStart; z <= selectEnd; z++) {
01803       textLine = getTextLine(z);
01804       end = 0;
01805       do {
01806         start = textLine->findUnselected(end);
01807         end = textLine->findSelected(start);
01808         for (i = start; i < end; i++) {
01809           s[len] = textLine->getChar(i);
01810           len++;
01811         }
01812       } while (start < end);
01813       if (textLine->isSelected()) {
01814         s[len] = '\n';
01815         len++;
01816       }
01817     }
01818 //    s[len] = '\0';
01819     return s;
01820   } else {
01821     for (z = selectStart; z <= selectEnd; z++) {
01822       textLine = getTextLine(z);
01823       len += textLine->numSelected() + 1;
01824     }
01825     QString s;
01826     len = 0;
01827     for (z = selectStart; z <= selectEnd; z++) {
01828       textLine = getTextLine(z);
01829       end = 0;
01830       do {
01831         start = textLine->findUnselected(end);
01832         end = textLine->findSelected(start);
01833         for (i = start; i < end; i++) {
01834           s[len] = textLine->getChar(i);
01835           len++;
01836         }
01837       } while (start < end);
01838       s[len] = '\n';
01839       len++;
01840     }
01841 //    s[len] = '\0';       //  the final \0 is not counted in length()
01842     return s;
01843   }
01844 }
01845 
01846 void KateDocument::delMarkedText(VConfig &c/*, bool undo*/) {
01847   int end = 0;
01848 
01849   if (selectEnd < selectStart) return;
01850 
01851   // the caller may have already started an undo record for the current action
01852 //  if (undo)
01853 
01854   //auto deletion of the marked text occurs not very often and can therefore
01855   //  be recorded separately
01856   recordStart(c, KateActionGroup::ugDelBlock);
01857 
01858   for (c.cursor.y = selectEnd; c.cursor.y >= selectStart; c.cursor.y--) {
01859     TextLine::Ptr textLine = getTextLine(c.cursor.y);
01860 
01861     c.cursor.x = textLine->length();
01862     do {
01863       end = textLine->findRevUnselected(c.cursor.x);
01864       if (end == 0) break;
01865       c.cursor.x = textLine->findRevSelected(end);
01866       recordDelete(c.cursor, end - c.cursor.x);
01867     } while (true);
01868     end = c.cursor.x;
01869     c.cursor.x = textLine->length();
01870     if (textLine->isSelected()) recordAction(KateAction::delLine,c.cursor);
01871   }
01872   c.cursor.y++;
01873   /*if (end < c.cursor.x)*/ c.cursor.x = end;
01874 
01875   selectEnd = -1;
01876   select.x = -1;
01877 
01878   /*if (undo)*/ recordEnd(c);
01879 }
01880 
01881 void KateDocument::tagLineRange(int line, int x1, int x2) {
01882   int z;
01883 
01884   for (z = 0; z < (int) views.count(); z++) {
01885     views.at(z)->tagLines(line, line, x1, x2);
01886   }
01887 }
01888 
01889 void KateDocument::tagLines(int start, int end) {
01890   int z;
01891 
01892   for (z = 0; z < (int) views.count(); z++) {
01893     views.at(z)->tagLines(start, end, 0, 0xffffff);
01894   }
01895 }
01896 
01897 void KateDocument::tagAll() {
01898   int z;
01899 
01900   for (z = 0; z < (int) views.count(); z++) {
01901     views.at(z)->tagAll();
01902   }
01903 }
01904 
01905 void KateDocument::updateLines(int startLine, int endLine, int flags, int cursorY) {
01906   TextLine::Ptr textLine;
01907   int line, last_line;
01908   int ctxNum, endCtx;
01909 //  kdDebug(13020)<<"******************KateDocument::updateLines Checkpoint 1"<<endl;
01910   if (buffer->line(startLine)==0) {kdDebug(13020)<<"********************No buffer for line " << startLine << " found**************"<<endl; return;};
01911 //  kdDebug(13020)<<"KateDocument::updateLines Checkpoint 2"<<endl;
01912   last_line = lastLine();
01913 //  if (endLine >= last_line) endLine = last_line;
01914 
01915   line = startLine;
01916   ctxNum = 0;
01917   if (line > 0) ctxNum = getTextLine(line - 1)->getContext();
01918   do {
01919 //    kdDebug(13020)<<QString("**************Working on line: %1").arg(line)<<endl;
01920     textLine = getTextLine(line);
01921     if (textLine==0) kdDebug(13020)<<"****updateLines()>> error textLine==0"<<endl;
01922     if (line <= endLine && line != cursorY) {
01923       if (flags & KateView::cfRemoveSpaces) textLine->removeSpaces();
01924       updateMaxLength(textLine);
01925     }
01926     endCtx = textLine->getContext();
01927 //    odebug << "DOHIGHLIGHT" << oendl;
01928 
01929     ctxNum = m_highlight->doHighlight(ctxNum,textLine);
01930     textLine->setContext(ctxNum);
01931     line++;
01932   } while ((buffer->line(line)!=0) && (line <= endLine || endCtx != ctxNum));
01933 //  kdDebug(13020)<<"updateLines :: while loop left"<<endl;
01934   tagLines(startLine, line - 1);
01935 }
01936 
01937 
01938 void KateDocument::updateMaxLength(TextLine::Ptr &textLine) {
01939   int len;
01940 
01941   len = textWidth(textLine,textLine->length());
01942 
01943   if (len > maxLength) {
01944     longestLine = textLine;
01945     maxLength = len;
01946     newDocGeometry = true;
01947   } else {
01948     if (!longestLine || (textLine == longestLine && len <= maxLength*3/4)) {
01949       maxLength = -1;
01950       for (int i = 0; i < numLines();i++) {
01951         textLine = getTextLine(i);
01952         len = textWidth(textLine,textLine->length());
01953         if (len > maxLength) {
01954           maxLength = len;
01955           longestLine = textLine;
01956         }
01957       }
01958       newDocGeometry = true;
01959     }
01960   }
01961 }
01962 
01963 void KateDocument::slotBufferChanged() {
01964   newDocGeometry = true;
01965   //updateLines();//JW
01966   updateViews();
01967 }
01968 
01969 void KateDocument::slotBufferHighlight(long start,long stop) {
01970   kdDebug(13020)<<"KateDocument::slotBufferHighlight"<<QString("%1-%2").arg(start).arg(stop)<<endl;
01971   updateLines(start,stop);
01972 //  buffer->startLoadTimer();
01973 }
01974 
01975 void KateDocument::updateViews(KateView *exclude) {
01976   KateView *view;
01977   int flags;
01978   bool markState = hasMarkedText();
01979 
01980   flags = (newDocGeometry) ? KateView::ufDocGeometry : 0;
01981   for (view = views.first(); view != 0L; view = views.next() ) {
01982     if (view != exclude) view->updateView(flags);
01983 
01984     // notify every view about the changed mark state....
01985     if (oldMarkState != markState) emit view->newMarkStatus();
01986   }
01987   oldMarkState = markState;
01988   newDocGeometry = false;
01989 }
01990 
01991 QColor &KateDocument::cursorCol(int x, int y) {
01992   int attr;
01993   Attribute *a;
01994 
01995   TextLine::Ptr textLine = getTextLine(y);
01996   attr = textLine->getRawAttr(x);
01997   a = &m_attribs[attr & taAttrMask];
01998   if (attr & taSelected) return a->selCol; else return a->col;
01999 }
02000 
02001 void KateDocument::paintTextLine(QPainter &paint, int line, int xStart, int xEnd, bool showTabs)
02002 {
02003   paintTextLine (paint, line, 0, xStart, xEnd, showTabs);
02004 }
02005 
02006 void KateDocument::paintTextLine(QPainter &paint, int line, int y, int xStart, int xEnd, bool showTabs)
02007 {
02008   TextLine::Ptr textLine;
02009   int len;
02010   const QChar *s;
02011   int z, x;
02012   QChar ch;
02013   Attribute *a = 0L;
02014   int attr, nextAttr;
02015   int xs;
02016   int xc, zc;
02017 
02018   if (line > lastLine()) {
02019     paint.fillRect(0, y, xEnd - xStart,fontHeight, colors[0]);
02020     return;
02021   }
02022 
02023   textLine = getTextLine(line);
02024   len = textLine->length();
02025   s = textLine->getText();
02026 
02027   // skip to first visible character
02028   x = 0;
02029   z = 0;
02030   do {
02031     xc = x;
02032     zc = z;
02033     if (z == len) break;
02034     ch = s[z];//textLine->getChar(z);
02035     if (ch == '\t') {
02036       x += m_tabWidth - (x % m_tabWidth);
02037     } else {
02038      a = &m_attribs[textLine->getAttr(z)];
02039 
02040    if (a->bold && a->italic)
02041       x += myFontMetricsBI.width(ch);
02042     else if (a->bold)
02043       x += myFontMetricsBold.width(ch);
02044     else if (a->italic)
02045       x += myFontMetricsItalic.width(ch);
02046     else
02047       x += myFontMetrics.width(ch);
02048     }
02049     z++;
02050   } while (x <= xStart);
02051 
02052   // draw background
02053   xs = xStart;
02054   attr = textLine->getRawAttr(zc);
02055   while (x < xEnd)
02056   {
02057     nextAttr = textLine->getRawAttr(z);
02058     if ((nextAttr ^ attr) & taSelected)
02059     {
02060       if (attr & taSelected)
02061         paint.fillRect(xs - xStart, y, x - xs, fontHeight, colors[1]);
02062       else
02063         paint.fillRect(xs - xStart, y, x - xs, fontHeight, colors[0]);
02064 
02065       xs = x;
02066       attr = nextAttr;
02067     }
02068 
02069     if (z == len) break;
02070 
02071     ch = s[z];//textLine->getChar(z);
02072 
02073     if (ch == '\t')
02074       x += m_tabWidth - (x % m_tabWidth);
02075     else
02076     {
02077       a = &m_attribs[textLine->getAttr(z)];
02078 
02079       if (a->bold && a->italic)
02080         x += myFontMetricsBI.width(ch);
02081       else if (a->bold)
02082         x += myFontMetricsBold.width(ch);
02083       else if (a->italic)
02084         x += myFontMetricsItalic.width(ch);
02085       else
02086         x += myFontMetrics.width(ch);
02087     }
02088     z++;
02089   }
02090 
02091   if (attr & taSelected)
02092     paint.fillRect(xs - xStart, y, xEnd - xs, fontHeight, colors[1]);
02093   else
02094     paint.fillRect(xs - xStart, y, xEnd - xs, fontHeight, colors[0]);
02095 
02096   len = z; //reduce length to visible length
02097 
02098   // draw text
02099   x = xc;
02100   z = zc;
02101   y += fontAscent;// -1;
02102   attr = -1;
02103   while (z < len) {
02104     ch = s[z];//textLine->getChar(z);
02105     if (ch == '\t') {
02106       if (z > zc) {
02107         //this should cause no copy at all
02108         QConstString str((QChar *) &s[zc], z - zc /*+1*/);
02109         QString s = str.string();
02110         paint.drawText(x - xStart, y, s);
02111 
02112    if (a->bold && a->italic)
02113       x += myFontMetricsBI.width(s);
02114     else if (a->bold)
02115       x += myFontMetricsBold.width(s);
02116     else if (a->italic)
02117       x += myFontMetricsItalic.width(s);
02118     else
02119       x += myFontMetrics.width(s);
02120       }
02121       zc = z +1;
02122 
02123       if (showTabs) {
02124         nextAttr = textLine->getRawAttr(z);
02125         if (nextAttr != attr) {
02126           attr = nextAttr;
02127           a = &m_attribs[attr & taAttrMask];
02128 
02129           if (attr & taSelected) paint.setPen(a->selCol);
02130             else paint.setPen(a->col);
02131 
02132    if (a->bold && a->italic)
02133      paint.setFont(myFontBI);
02134     else if (a->bold)
02135       paint.setFont(myFontBold);
02136     else if (a->italic)
02137       paint.setFont(myFontItalic);
02138     else
02139       paint.setFont(myFont);
02140         }
02141 
02142 //        paint.drawLine(x - xStart, y -2, x - xStart, y);
02143 //        paint.drawLine(x - xStart, y, x - xStart + 2, y);
02144         paint.drawPoint(x - xStart, y);
02145         paint.drawPoint(x - xStart +1, y);
02146         paint.drawPoint(x - xStart, y -1);
02147       }
02148       x += m_tabWidth - (x % m_tabWidth);
02149     } else {
02150       nextAttr = textLine->getRawAttr(z);
02151       if (nextAttr != attr) {
02152         if (z > zc) {
02153           QConstString str((QChar *) &s[zc], z - zc /*+1*/);
02154           QString s = str.string();
02155           paint.drawText(x - xStart, y, s);
02156 
02157    if (a->bold && a->italic)
02158       x += myFontMetricsBI.width(s);
02159     else if (a->bold)
02160       x += myFontMetricsBold.width(s);
02161     else if (a->italic)
02162       x += myFontMetricsItalic.width(s);
02163     else
02164       x += myFontMetrics.width(s);
02165           zc = z;
02166         }
02167         attr = nextAttr;
02168         a = &m_attribs[attr & taAttrMask];
02169 
02170         if (attr & taSelected) paint.setPen(a->selCol);
02171           else paint.setPen(a->col);
02172 
02173    if (a->bold && a->italic)
02174      paint.setFont(myFontBI);
02175     else if (a->bold)
02176       paint.setFont(myFontBold);
02177     else if (a->italic)
02178       paint.setFont(myFontItalic);
02179     else
02180       paint.setFont(myFont);
02181       }
02182     }
02183     z++;
02184   }
02185   if (z > zc) {
02186     QConstString str((QChar *) &s[zc], z - zc /*+1*/);
02187     paint.drawText(x - xStart, y, str.string());
02188   }
02189 }
02190 
02191 // Applies the search context, and returns whether a match was found. If one is,
02192 // the length of the string matched is also returned.
02193 bool KateDocument::doSearch(SConfig &sc, const QString &searchFor) {
02194   int line, col;
02195   int searchEnd;
02196   int bufLen, tlen;
02197   QChar *t;
02198   TextLine::Ptr textLine;
02199   int pos, newPos;
02200 
02201   if (searchFor.isEmpty()) return false;
02202 
02203   bufLen = 0;
02204   t = 0L;
02205 
02206   line = sc.cursor.y;
02207   col = sc.cursor.x;
02208   if (!(sc.flags & KateView::sfBackward)) {
02209     //forward search
02210     if (sc.flags & KateView::sfSelected) {
02211       if (line < selectStart) {
02212         line = selectStart;
02213         col = 0;
02214       }
02215       searchEnd = selectEnd;
02216     } else searchEnd = lastLine();
02217 
02218     while (line <= searchEnd) {
02219       textLine = getTextLine(line);
02220       tlen = textLine->length();
02221       if (tlen > bufLen) {
02222         delete t;
02223         bufLen = (tlen + 255) & (~255);
02224         t = new QChar[bufLen];
02225       }
02226       memcpy(t, textLine->getText(), tlen*sizeof(QChar));
02227       if (sc.flags & KateView::sfSelected) {
02228         pos = 0;
02229         do {
02230           pos = textLine->findSelected(pos);
02231           newPos = textLine->findUnselected(pos);
02232           memset(&t[pos], 0, (newPos - pos)*sizeof(QChar));
02233           pos = newPos;
02234         } while (pos < tlen);
02235       }
02236 
02237       QString text(t, tlen);
02238       if (sc.flags & KateView::sfWholeWords) {
02239         // Until the end of the line...
02240         while (col < tlen) {
02241           // ...find the next match.
02242           col = sc.search(text, col);
02243           if (col != -1) {
02244             // Is the match delimited correctly?
02245             if (((col == 0) || (!m_highlight->isInWord(t[col]))) &&
02246               ((col + sc.matchedLength == tlen) || (!m_highlight->isInWord(t[col + sc.matchedLength])))) {
02247               goto found;
02248             }
02249             else {
02250               // Start again from the next character.
02251               col++;
02252             }
02253           }
02254           else {
02255             // No match.
02256             break;
02257           }
02258         }
02259       }
02260       else {
02261         // Non-whole-word search.
02262         col = sc.search(text, col);
02263         if (col != -1)
02264           goto found;
02265       }
02266       col = 0;
02267       line++;
02268     }
02269   } else {
02270     // backward search
02271     if (sc.flags & KateView::sfSelected) {
02272       if (line > selectEnd) {
02273         line = selectEnd;
02274         col = -1;
02275       }
02276       searchEnd = selectStart;
02277     } else searchEnd = 0;
02278 
02279     while (line >= searchEnd) {
02280       textLine = getTextLine(line);
02281       tlen = textLine->length();
02282       if (tlen > bufLen) {
02283         delete t;
02284         bufLen = (tlen + 255) & (~255);
02285         t = new QChar[bufLen];
02286       }
02287       memcpy(t, textLine->getText(), tlen*sizeof(QChar));
02288       if (sc.flags & KateView::sfSelected) {
02289         pos = 0;
02290         do {
02291           pos = textLine->findSelected(pos);
02292           newPos = textLine->findUnselected(pos);
02293           memset(&t[pos], 0, (newPos - pos)*sizeof(QChar));
02294           pos = newPos;
02295         } while (pos < tlen);
02296       }
02297 
02298       if (col < 0 || col > tlen) col = tlen;
02299 
02300       QString text(t, tlen);
02301       if (sc.flags & KateView::sfWholeWords) {
02302         // Until the beginning of the line...
02303         while (col >= 0) {
02304           // ...find the next match.
02305           col = sc.search(text, col);
02306           if (col != -1) {
02307             // Is the match delimited correctly?
02308             if (((col == 0) || (!m_highlight->isInWord(t[col]))) &&
02309               ((col + sc.matchedLength == tlen) || (!m_highlight->isInWord(t[col + sc.matchedLength])))) {
02310               goto found;
02311             }
02312             else {
02313               // Start again from the previous character.
02314               col--;
02315             }
02316           }
02317           else {
02318             // No match.
02319             break;
02320           }
02321         }
02322       }
02323       else {
02324         // Non-whole-word search.
02325         col = sc.search(text, col);
02326         if (col != -1)
02327           goto found;
02328       }
02329       col = -1;
02330       line--;
02331     }
02332   }
02333   sc.flags |= KateView::sfWrapped;
02334   return false;
02335 found:
02336   if (sc.flags & KateView::sfWrapped) {
02337     if ((line > sc.startCursor.y || (line == sc.startCursor.y && col >= sc.startCursor.x))
02338       ^ ((sc.flags & KateView::sfBackward) != 0)) return false;
02339   }
02340   sc.cursor.x = col;
02341   sc.cursor.y = line;
02342   return true;
02343 }
02344 
02345 void KateDocument::tagLine(int line) {
02346 
02347   if (tagStart > line) tagStart = line;
02348   if (tagEnd < line) tagEnd = line;
02349 }
02350 
02351 void KateDocument::insLine(int line) {
02352   KateView *view;
02353 
02354   if (selectStart >= line) selectStart++;
02355   if (selectEnd >= line) selectEnd++;
02356   if (tagStart >= line) tagStart++;
02357   if (tagEnd >= line) tagEnd++;
02358 
02359   newDocGeometry = true;
02360   for (view = views.first(); view != 0L; view = views.next() ) {
02361     view->insLine(line);
02362   }
02363 }
02364 
02365 void KateDocument::delLine(int line) {
02366   KateView *view;
02367 
02368   if (selectStart >= line && selectStart > 0) selectStart--;
02369   if (selectEnd >= line) selectEnd--;
02370   if (tagStart >= line && tagStart > 0) tagStart--;
02371   if (tagEnd >= line) tagEnd--;
02372 
02373   newDocGeometry = true;
02374   for (view = views.first(); view != 0L; view = views.next() ) {
02375     view->delLine(line);
02376   }
02377 }
02378 
02379 void KateDocument::optimizeSelection() {
02380   TextLine::Ptr textLine;
02381 
02382   while (selectStart <= selectEnd) {
02383     textLine = getTextLine(selectStart);
02384     if (textLine->isSelected() || textLine->numSelected() > 0) break;
02385     selectStart++;
02386   }
02387   while (selectEnd >= selectStart) {
02388     textLine = getTextLine(selectEnd);
02389     if (textLine->isSelected() || textLine->numSelected() > 0) break;
02390     selectEnd--;
02391   }
02392   if (selectStart > selectEnd) {
02393     selectStart = 0xffffff;
02394     selectEnd = 0;
02395   }
02396 }
02397 
02398 void KateDocument::doAction(KateAction *a) {
02399 
02400   switch (a->action) {
02401     case KateAction::replace:
02402       doReplace(a);
02403       break;
02404     case KateAction::wordWrap:
02405       doWordWrap(a);
02406       break;
02407     case KateAction::wordUnWrap:
02408       doWordUnWrap(a);
02409       break;
02410     case KateAction::newLine:
02411       doNewLine(a);
02412       break;
02413     case KateAction::delLine:
02414       doDelLine(a);
02415       break;
02416     case KateAction::insLine:
02417       doInsLine(a);
02418       break;
02419     case KateAction::killLine:
02420       doKillLine(a);
02421       break;
02422 /*    case KateAction::doubleLine:
02423       break;
02424     case KateAction::removeLine:
02425       break;*/
02426   }
02427 }
02428 
02429 void KateDocument::doReplace(KateAction *a) {
02430   TextLine::Ptr textLine;
02431   int l;
02432 
02433   //exchange current text with stored text in KateAction *a
02434 
02435   textLine = getTextLine(a->cursor.y);
02436   l = textLine->length() - a->cursor.x;
02437   if (l > a->len) l = a->len;
02438 
02439   QString oldText(&textLine->getText()[a->cursor.x], (l < 0) ? 0 : l);
02440   textLine->replace(a->cursor.x, a->len, a->text.unicode(), a->text.length());
02441 
02442   a->len = a->text.length();
02443   a->text = oldText;
02444 
02445   buffer->changeLine(a->cursor.y);
02446 
02447   tagLine(a->cursor.y);
02448 }
02449 
02450 void KateDocument::doWordWrap(KateAction *a) {
02451   TextLine::Ptr textLine;
02452 
02453   textLine = getTextLine(a->cursor.y - 1);
02454   a->len = textLine->length() - a->cursor.x;
02455   textLine->wrap(getTextLine(a->cursor.y),a->len);
02456 
02457   buffer->changeLine(a->cursor.y - 1);
02458   buffer->changeLine(a->cursor.y);
02459 
02460   tagLine(a->cursor.y - 1);
02461   tagLine(a->cursor.y);
02462   if (selectEnd == a->cursor.y - 1) selectEnd++;
02463 
02464   a->action = KateAction::wordUnWrap;
02465 }
02466 
02467 void KateDocument::doWordUnWrap(KateAction *a) {
02468   TextLine::Ptr textLine;
02469 
02470   textLine = getTextLine(a->cursor.y - 1);
02471 //  textLine->setLength(a->len);
02472   textLine->unWrap(a->len, getTextLine(a->cursor.y),a->cursor.x);
02473 
02474   buffer->changeLine(a->cursor.y - 1);
02475   buffer->changeLine(a->cursor.y);
02476 
02477   tagLine(a->cursor.y - 1);
02478   tagLine(a->cursor.y);
02479 
02480   a->action = KateAction::wordWrap;
02481 }
02482 
02483 void KateDocument::doNewLine(KateAction *a) {
02484   TextLine::Ptr textLine, newLine;
02485 
02486   textLine = getTextLine(a->cursor.y);
02487   newLine = new TextLine(textLine->getRawAttr(), textLine->getContext());
02488   textLine->wrap(newLine,a->cursor.x);
02489 
02490   buffer->insertLine(a->cursor.y + 1, newLine);
02491   buffer->changeLine(a->cursor.y);
02492 
02493   insLine(a->cursor.y + 1);
02494   tagLine(a->cursor.y);
02495   tagLine(a->cursor.y + 1);
02496   if (selectEnd == a->cursor.y) selectEnd++;//addSelection(a->cursor.y + 1);
02497 
02498   a->action = KateAction::delLine;
02499 }
02500 
02501 void KateDocument::doDelLine(KateAction *a) {
02502   TextLine::Ptr textLine, nextLine;
02503 
02504   textLine = getTextLine(a->cursor.y);
02505   nextLine = getTextLine(a->cursor.y+1);
02506 //  textLine->setLength(a->cursor.x);
02507   textLine->unWrap(a->cursor.x, nextLine,nextLine->length());
02508   textLine->setContext(nextLine->getContext());
02509   if (longestLine == nextLine) longestLine = 0L;
02510 
02511   buffer->changeLine(a->cursor.y);
02512   buffer->removeLine(a->cursor.y+1);
02513 
02514   tagLine(a->cursor.y);
02515   delLine(a->cursor.y + 1);
02516 
02517   a->action = KateAction::newLine;
02518 }
02519 
02520 void KateDocument::doInsLine(KateAction *a) {
02521 
02522   buffer->insertLine(a->cursor.y, new TextLine());
02523 
02524   insLine(a->cursor.y);
02525 
02526   a->action = KateAction::killLine;
02527 }
02528 
02529 void KateDocument::doKillLine(KateAction *a) {
02530   TextLine::Ptr textLine = getTextLine(a->cursor.y);
02531   if (longestLine == textLine) longestLine = 0L;
02532 
02533   buffer->removeLine(a->cursor.y);
02534 
02535   delLine(a->cursor.y);
02536   tagLine(a->cursor.y);
02537 
02538   a->action = KateAction::insLine;
02539 }
02540 
02541 void KateDocument::newUndo() {
02542   KTextEditor::View *view;
02543   int state;
02544 
02545   state = 0;
02546   if (currentUndo > 0) state |= 1;
02547   if (currentUndo < (int) undoList.count()) state |= 2;
02548   undoState = state;
02549   for (view = m_views.first(); view != 0L; view = m_views.next() ) {
02550     emit static_cast<KateView *>( view )->newUndo();
02551   }
02552 }
02553 
02554 void KateDocument::recordStart(VConfig &c, int newUndoType) {
02555   recordStart(c.view, c.cursor, c.flags, newUndoType);
02556 }
02557 
02558 void KateDocument::recordStart(KateView *, PointStruc &cursor, int flags,
02559   int newUndoType, bool keepModal, bool mergeUndo) {
02560 
02561   KateActionGroup *g;
02562 
02563 //  if (newUndoType == KateActionGroup::ugNone) {
02564     // only a bug would cause this
02565 //why should someone do this? we can't prevent all programming errors :) (jochen whilhelmy)
02566 //    debug("KateDocument::recordStart() called with no undo group type!");
02567 //    return;
02568 //  }
02569 
02570   if (!keepModal) setPseudoModal(0L);
02571 
02572   //i optimized the group undo stuff a bit (jochen wilhelmy)
02573   //  recordReset() is not needed any more
02574   g = undoList.getLast();
02575   if (g != 0L && ((undoCount < 1024 && flags & KateView::cfGroupUndo
02576     && g->end.x == cursor.x && g->end.y == cursor.y) || mergeUndo)) {
02577 
02578     //undo grouping : same actions are put into one undo step
02579     //precondition : new action starts where old stops or mergeUndo flag
02580     if (g->undoType == newUndoType
02581       || (g->undoType == KateActionGroup::ugInsChar
02582         && newUndoType == KateActionGroup::ugInsLine)
02583       || (g->undoType == KateActionGroup::ugDelChar
02584         && newUndoType == KateActionGroup::ugDelLine)) {
02585 
02586       undoCount++;
02587       if (g->undoType != newUndoType) undoCount = 0xffffff;
02588       return;
02589     }
02590   }
02591   undoCount = 0;
02592 /*
02593   if (undoView != view) {
02594     // always kill the current undo group if the editing view changes
02595     recordReset();
02596     undoType = newUndoType;
02597   } else if (newUndoType == undoType) {
02598 printf("bla!!!\n");
02599     // same as current type, keep using it
02600     return;
02601   } else if  ( (undoType == KateActionGroup::ugInsChar && newUndoType == KateActionGroup::ugInsLine) ||
02602                (undoType == KateActionGroup::ugDelChar && newUndoType == KateActionGroup::ugDelLine) ) {
02603     // some type combinations can run together...
02604     undoType += 1000;
02605     return;
02606   } else {
02607     recordReset();
02608     undoType = newUndoType;
02609   }
02610 
02611   undoView = view;
02612 */
02613   while ((int) undoList.count() > currentUndo) undoList.removeLast();
02614   while ((int) undoList.count() > undoSteps) {
02615     undoList.removeFirst();
02616     currentUndo--;
02617   }
02618 
02619   g = new KateActionGroup(cursor, newUndoType);
02620   undoList.append(g);
02621 //  currentUndo++;
02622 
02623   tagEnd = 0;
02624   tagStart = 0xffffff;
02625 }
02626 
02627 void KateDocument::recordAction(KateAction::Action action, PointStruc &cursor) {
02628   KateAction *a;
02629 
02630   a = new KateAction(action, cursor);
02631   doAction(a);
02632   undoList.getLast()->insertAction(a);
02633 }
02634 
02635 void KateDocument::recordInsert(VConfig &c, const QString &text) {
02636   recordReplace(c, 0, text);
02637 }
02638 
02639 void KateDocument::recordReplace(VConfig &c, int len, const QString &text) {
02640   if (c.cursor.x > 0 && !(c.flags & KateView::cfSpaceIndent)) {
02641     TextLine::Ptr textLine = getTextLine(c.cursor.y);
02642     if (textLine->length() == 0) {
02643       QString s = tabString(c.cursor.x, tabChars);
02644       int len = s.length();
02645       s += text;
02646       c.cursor.x = 0;
02647       recordReplace(c.cursor, len, s);
02648       c.cursor.x = len;
02649       return;
02650     }
02651   }
02652   recordReplace(c.cursor, len, text);
02653 }
02654 
02655 void KateDocument::recordInsert(PointStruc &cursor, const QString &text) {
02656   recordReplace(cursor, 0, text);
02657 }
02658 
02659 void KateDocument::recordDelete(PointStruc &cursor, int len) {
02660   recordReplace(cursor, len, QString::null);
02661 }
02662 
02663 void KateDocument::recordReplace(PointStruc &cursor, int len, const QString &text) {
02664   KateAction *a;
02665   TextLine::Ptr textLine;
02666   int l;
02667 
02668   if (len == 0 && text.isEmpty()) return;
02669 
02670   //try to append to last replace action
02671   a = undoList.getLast()->action;
02672   if (a == 0L || a->action != KateAction::replace
02673     || a->cursor.x + a->len != cursor.x || a->cursor.y != cursor.y) {
02674 
02675 //if (a != 0L) printf("new %d %d\n", a->cursor.x + a->len, cursor.x);
02676     a = new KateAction(KateAction::replace, cursor);
02677     undoList.getLast()->insertAction(a);
02678   }
02679 
02680   //replace
02681   textLine = getTextLine(cursor.y);
02682   l = textLine->length() - cursor.x;
02683   if (l > len) l = len;
02684   a->text.insert(a->text.length(), &textLine->getText()[cursor.x], (l < 0) ? 0 : l);
02685   textLine->replace(cursor.x, len, text.unicode(), text.length());
02686   a->len += text.length();
02687 
02688   buffer->changeLine(a->cursor.y);
02689   updateMaxLength(textLine);
02690   tagLine(a->cursor.y);
02691 }
02692 
02693 void KateDocument::recordEnd(VConfig &c) {
02694   recordEnd(c.view, c.cursor, c.flags);
02695 }
02696 
02697 void KateDocument::recordEnd(KateView *view, PointStruc &cursor, int flags) {
02698   KateActionGroup *g;
02699 
02700   // clear selection if option "persistent selections" is off
02701 //  if (!(flags & cfPersistent)) deselectAll();
02702 
02703   g = undoList.getLast();
02704   if (g->action == 0L) {
02705     // no action has been done: remove empty undo record
02706     undoList.removeLast();
02707     return;
02708   }
02709   // store end cursor position for redo
02710   g->end = cursor;
02711   currentUndo = undoList.count();
02712 
02713   if (tagStart <= tagEnd) {
02714     optimizeSelection();
02715     updateLines(tagStart, tagEnd, flags, cursor.y);
02716     setModified(true);
02717   }
02718 
02719   view->updateCursor(cursor, flags);
02720 
02721 //  newUndo();
02722 /*
02723   undoCount++;
02724   // we limit the number of individual undo operations for sanity - is 1K reasonable?
02725   // this is also where we handle non-group undo preference
02726   // if the undo type is singlular, we always finish it now
02727   if ( undoType == KateActionGroup::ugPaste ||
02728        undoType == KateActionGroup::ugDelBlock ||
02729        undoType > 1000 ||
02730        undoCount > 1024 || !(flags & cfGroupUndo) ) {
02731 printf("recordend %d %d\n", undoType, undoCount);
02732     recordReset();
02733   }
02734 */
02735 
02736   // this should keep the flood of signals down a little...
02737   if (undoCount == 0) newUndo();
02738   emit textChanged();
02739 }
02740 /*
02741 void KateDocument::recordReset()
02742 {
02743   if (pseudoModal)
02744     return;
02745 
02746   // forces the next call of recordStart() to begin a new undo group
02747   // not used in normal editing, but used by markFound(), etc.
02748   undoType = KateActionGroup::ugNone;
02749   undoCount = 0;
02750   undoView = NULL;
02751   undoReported = false;
02752 printf("recordreset\n");
02753 }
02754 */
02755 
02756 /*
02757 void KateDocument::recordDel(PointStruc &cursor, TextLine::Ptr &textLine, int l) {
02758   int len;
02759 
02760   len = textLine->length() - cursor.x;
02761   if (len > l) len = l;
02762   if (len > 0) {
02763     insertUndo(new KateAction(KateAction::replace,cursor,&textLine->getText()[cursor.x],len));
02764   }
02765 }
02766 */
02767 
02768 
02769 void KateDocument::doActionGroup(KateActionGroup *g, int flags, bool undo) {
02770   KateAction *a, *next;
02771 
02772   setPseudoModal(0L);
02773   if (!(flags & KateView::cfPersistent)) deselectAll();
02774   tagEnd = 0;
02775   tagStart = 0xffffff;
02776 
02777   a = g->action;
02778   g->action = 0L;
02779   while (a) {
02780     doAction(a);
02781     next = a->next;
02782     g->insertAction(a);
02783     a = next;
02784   }
02785   optimizeSelection();
02786   if (tagStart <= tagEnd) updateLines(tagStart, tagEnd, flags);
02787 
02788   // the undo/redo functions set undo to true, all others should leave it
02789   // alone (default)
02790   if (!undo) {
02791     setModified(true);
02792     newUndo();
02793   }
02794 }
02795 
02796 int KateDocument::nextUndoType()
02797 {
02798   KateActionGroup *g;
02799 
02800   if (currentUndo <= 0) return KateActionGroup::ugNone;
02801   g = undoList.at(currentUndo - 1);
02802   return g->undoType;
02803 }
02804 
02805 int KateDocument::nextRedoType()
02806 {
02807   KateActionGroup *g;
02808 
02809   if (currentUndo >= (int) undoList.count()) return KateActionGroup::ugNone;
02810   g = undoList.at(currentUndo);
02811 //  if (!g) return KateActionGroup::ugNone;
02812   return g->undoType;
02813 }
02814 
02815 void KateDocument::undoTypeList(QValueList<int> &lst)
02816 {
02817   lst.clear();
02818   for (int i = currentUndo-1; i>=0 ;i--)
02819     lst.append(undoList.at(i)->undoType);
02820 }
02821 
02822 void KateDocument::redoTypeList(QValueList<int> &lst)
02823 {
02824   lst.clear();
02825   for (int i = currentUndo+1; i<(int)undoList.count(); i++)
02826     lst.append(undoList.at(i)->undoType);
02827 }
02828 
02829 void KateDocument::undo(VConfig &c, int count) {
02830   KateActionGroup *g = 0L;
02831   int num;
02832   bool needUpdate = false; // don't update the cursor until completely done
02833 
02834   if (count <= 0) return;
02835 
02836   for (num = 0 ; num < count ; num++) {
02837     if (currentUndo <= 0) break;
02838     currentUndo--;
02839     g = undoList.at(currentUndo);
02840     doActionGroup(g, c.flags, true); // do not setModified() or newUndo()
02841     needUpdate = true;
02842 
02843 //    if (num == 0) recordReset();
02844   }
02845 
02846   if (needUpdate) {
02847     // since we told doActionGroup() not to do this stuff, we need to do it now
02848     c.view->updateCursor(g->start);
02849     setModified(true);
02850     newUndo();
02851   }
02852 }
02853 
02854 void KateDocument::redo(VConfig &c, int count) {
02855   KateActionGroup *g = 0L;
02856   int num;
02857   bool needUpdate = false; // don't update the cursor until completely done
02858 
02859   if (count <= 0) return;
02860 
02861   for (num = 0 ; num < count ; num++) {
02862     if (currentUndo+1 > (int)undoList.count()) break;
02863     g = undoList.at(currentUndo);
02864     currentUndo++;
02865     doActionGroup(g, c.flags, true); // do not setModified() or newUndo()
02866     needUpdate = true;
02867 
02868 //    if (num == 0) recordReset();
02869   }
02870 
02871   if (needUpdate) {
02872     // since we told doActionGroup() not to do this stuff, we need to do it now
02873     c.view->updateCursor(g->end);
02874     setModified(true);
02875     newUndo();
02876   }
02877 }
02878 
02879 void KateDocument::clearRedo() {
02880   // disable redos
02881   // this was added as an assist to the spell checker
02882   bool deleted = false;
02883 
02884   while ((int) undoList.count() > currentUndo) {
02885     deleted = true;
02886     undoList.removeLast();
02887   }
02888 
02889   if (deleted) newUndo();
02890 }
02891 
02892 void KateDocument::setUndoSteps(int steps) {
02893   if (steps < 5) steps = 5;
02894   undoSteps = steps;
02895 }
02896 
02897 void KateDocument::setPseudoModal(QWidget *w) {
02898 //  QWidget *old = pseudoModal;
02899 
02900   // (glenebob)
02901   // this is a temporary hack to make the spell checker work a little
02902   // better - as kspell progresses, this sort of thing should become
02903   // obsolete or worked around more cleanly
02904   // this is relied upon *only* by the spell-check code
02905   if (pseudoModal && pseudoModal != (QWidget*)1L)
02906     delete pseudoModal;
02907 
02908 //  pseudoModal = 0L;
02909 //  if (old || w) recordReset();
02910 
02911   pseudoModal = w;
02912 }
02913 
02914 
02915 void KateDocument::newBracketMark(PointStruc &cursor, BracketMark &bm)
02916 {
02917   TextLine::Ptr textLine;
02918   int x, line, count, attr;
02919   QChar bracket, opposite, ch;
02920   Attribute *a;
02921 
02922   bm.eXPos = -1; //mark bracked mark as invalid
02923   x = cursor.x -1; // -1 to look at left side of cursor
02924   if (x < 0) return;
02925   line = cursor.y; //current line
02926   count = 0; //bracket counter for nested brackets
02927 
02928   textLine = getTextLine(line);
02929   if (!textLine) return;
02930 
02931   bracket = textLine->getChar(x);
02932   attr = textLine->getAttr(x);
02933 
02934   if (bracket == '(' || bracket == '[' || bracket == '{')
02935   {
02936     //get opposite bracket
02937     opposite = ')';
02938     if (bracket == '[') opposite = ']';
02939     if (bracket == '{') opposite = '}';
02940     //get attribute of bracket (opposite bracket must have the same attribute)
02941     x++;
02942     while (line - cursor.y < 40) {
02943       //go to next line on end of line
02944       while (x >= (int) textLine->length()) {
02945         line++;
02946         if (line > lastLine()) return;
02947         textLine = getTextLine(line);
02948         x = 0;
02949       }
02950       if (textLine->getAttr(x) == attr) {
02951         //try to find opposite bracked
02952         ch = textLine->getChar(x);
02953         if (ch == bracket) count++; //same bracket : increase counter
02954         if (ch == opposite) {
02955           count--;
02956           if (count < 0) goto found;
02957         }
02958       }
02959       x++;
02960     }
02961   }
02962   else if (bracket == ')' || bracket == ']' || bracket == '}')
02963   {
02964     opposite = '(';
02965     if (bracket == ']') opposite = '[';
02966     if (bracket == '}') opposite = '{';
02967     x--;
02968     while (cursor.y - line < 20) {
02969 
02970       while (x < 0) {
02971         line--;
02972         if (line < 0) return;
02973         textLine = getTextLine(line);
02974         x = textLine->length() -1;
02975       }
02976       if (textLine->getAttr(x) == attr) {
02977         ch = textLine->getChar(x);
02978         if (ch == bracket) count++;
02979         if (ch == opposite) {
02980           count--;
02981           if (count < 0) goto found;
02982         }
02983       }
02984       x--;
02985     }
02986   }
02987   return;
02988 
02989 found:
02990   //cursor position of opposite bracket
02991   bm.cursor.x = x;
02992   bm.cursor.y = line;
02993   //x position (start and end) of related bracket
02994   bm.sXPos = textWidth(textLine, x);
02995   a = &m_attribs[attr];
02996 
02997    if (a->bold && a->italic)
02998       bm.eXPos = bm.sXPos + myFontMetricsBI.width(bracket);
02999     else if (a->bold)
03000       bm.eXPos = bm.sXPos + myFontMetricsBold.width(bracket);
03001     else if (a->italic)
03002       bm.eXPos = bm.sXPos + myFontMetricsItalic.width(bracket);
03003     else
03004       bm.eXPos = bm.sXPos + myFontMetrics.width(bracket);
03005 }
03006 
03007 void KateDocument::clipboardChanged() { //slot
03008 //#if defined(_WS_X11_)
03009   if (m_singleSelection) {
03010     disconnect(QApplication::clipboard(), SIGNAL(dataChanged()),
03011       this, SLOT(clipboardChanged()));
03012     deselectAll();
03013     updateViews();
03014   }
03015 //#endif
03016 }
03017 
03018 #if 0
03019 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
03020 {
03021   KParts::ReadWritePart::guiActivateEvent( ev );
03022   if ( ev->activated() )
03023     emit selectionChanged();
03024 }
03025 #endif
03026 
03027 void KateDocument::setDocName (QString docName)
03028 {
03029   myDocName = docName;
03030   emit nameChanged (this);
03031 }
03032 
03033 void KateDocument::setDocFile (QString docFile)
03034 {
03035   m_file = docFile;
03036   emit fileNameChanged ();
03037 }
03038 
03039 void KateDocument::setMTime()
03040 {
03041     if (fileInfo && !fileInfo->fileName().isEmpty()) {
03042       fileInfo->refresh();
03043       mTime = fileInfo->lastModified();
03044     }
03045 }
03046 
03047 void KateDocument::isModOnHD(bool forceReload)
03048 {
03049   if (fileInfo && !fileInfo->fileName().isEmpty()) {
03050     fileInfo->refresh();
03051     if (fileInfo->lastModified() > mTime) {
03052       if ( forceReload ||
03053            (KMessageBox::warningContinueCancel(0,
03054                (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),
03055                i18n("File has changed on Disk"),
03056                i18n("Yes") ) == KMessageBox::Continue)
03057           )
03058         reloadFile();
03059       else
03060         setMTime();
03061     }
03062   }
03063 }
03064 
03065 void KateDocument::reloadFile()
03066 {
03067 #warning fixme
03068 #if 0
03069   if (fileInfo && !fileInfo->fileName().isEmpty()) {
03070     KateDocument::openFile();
03071     setMTime();
03072   }
03073 #endif
03074 }
03075 
03076 void KateDocument::slotModChanged()
03077 {
03078   emit modStateChanged (this);
03079 }
03080 
03081 QList<Kate::Mark> KateDocument::marks ()
03082 {
03083   QList<Kate::Mark> list;
03084   TextLine::Ptr line;
03085 
03086   for (int i=0; i < numLines(); i++)
03087   {
03088     line = getTextLine(i);
03089     if (line->mark() != 0)
03090     {
03091       Kate::Mark *mark=new Kate::Mark;
03092       mark->line = i;
03093       mark->type = line->mark();
03094       list.append (mark);
03095     }
03096   }
03097 
03098   return list;
03099 }
03100 
03101 void KateDocument::flush ()
03102 {
03103   if (isReadOnly())
03104     return;
03105 
03106   m_url = QString::null;
03107   fileInfo->setFile (QString());
03108   setMTime();
03109 
03110   clear();
03111   updateViews();
03112 
03113   emit fileNameChanged ();
03114 }
03115 
03116 void KateDocument::open (const QString &name)
03117 {
03118   openURL (name);
03119 }
03120 
03121 void KateDocument::wrapText (uint col)
03122 {
03123   int line = 0;
03124   int z = 0;
03125 
03126   while(true)
03127   {
03128     TextLine::Ptr l = getTextLine(line);
03129 
03130     if (l->length() > col)
03131     {
03132       TextLine::Ptr tl = new TextLine();
03133       buffer->insertLine(line+1,tl);
03134       const QChar *text = l->getText();
03135 
03136       for (z=col; z>0; z--)
03137       {
03138         if (z < 1) break;
03139         if (text[z].isSpace()) break;
03140       }
03141 
03142       if (z < 1) z=col;
03143 
03144       l->wrap (tl, z);
03145     }
03146 
03147     line++;
03148     if (line >= numLines()) break;
03149   };
03150 
03151   newDocGeometry=true;
03152   updateLines();
03153   updateViews();
03154 }
03155 
03156 void KateDocument::setWordWrap (bool on)
03157 {
03158   if (on != myWordWrap && on)
03159     wrapText (myWordWrapAt);
03160 
03161   myWordWrap = on;
03162 }
03163 
03164 void KateDocument::setWordWrapAt (uint col)
03165 {
03166   if (myWordWrapAt != col && myWordWrap)
03167     wrapText (myWordWrapAt);
03168 
03169   myWordWrapAt = col;
03170 }
03171 
03172 void KateDocument::applyWordWrap ()
03173 {
03174   wrapText (myWordWrapAt);
03175 }

Generated on Sat Nov 5 16:17:10 2005 for OPIE by  doxygen 1.4.2