00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041 #include "katedocument.h"
00042 #include "kmessagebox.h"
00043 #include "kglobal.h"
00044
00045
00046 #include "kdebug.h"
00047
00048
00049 #include "kglobalsettings.h"
00050
00051
00052
00053 #include "../view/kateview.h"
00054 #include "katebuffer.h"
00055 #include "katetextline.h"
00056
00057 #include "katecmd.h"
00058
00059
00060 #include <opie2/odebug.h>
00061 #include <qpe/config.h>
00062
00063
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
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
00109
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
00156
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
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);
00203
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');
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');
00238 maxLength=maxLength*(float)newwidth/(float)oldwidth;
00239
00240 updateFontData();
00241 updateViews();
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
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;
00335
00336 QTextStream stream(&f);
00337
00338 stream.setEncoding(QTextStream::RawUnicode);
00339 #warning fixme
00340
00341 stream.setCodec(QTextCodec::codecForLocale());
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;
00413 c.cursor.x = col;
00414 c.cursor.y = line;
00415 c.cXPos = 0;
00416 c.flags = 0;
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
00429
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
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
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
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
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
00566
00567 if ( m != newDoc )
00568 {
00569 newDoc = m;
00571
00572
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
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
00633 }
00634
00635 void KateDocument::readSessionConfig(KateConfig *config)
00636 {
00637 m_url = config->readEntry("URL");
00638 setHighlight(hlManager->nameFind(config->readEntry("Highlight")));
00639
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);
00653 config->writeEntry("Highlight", m_highlight->name());
00654
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)
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
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() {
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
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
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) {
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
00849 }
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;
00876 } else if (ch == '\n') {
00877 recordAction(KateAction::newLine, c.cursor);
00878 recordInsert(c, buf);
00879
00880 buf.truncate(0);
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
00976
00977
00978 if (buf.isEmpty()) return false;
00979
00980
00981
00982 if (c.flags &KateView:: cfDelOnInput) delMarkedText(c);
00983
00984 recordStart(c, KateActionGroup::ugInsChar);
00985 recordReplace(c, (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
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;
01000 if (z >= l) break;
01001 pos = myWordWrapAt;
01002 for (; z >= 0; z--) {
01003 if (s[z].isSpace()) {
01004 pos = z + 1;
01005 break;
01006 }
01007 }
01008
01009
01010 if (line == c.cursor.y && pos <= c.cursor.x) {
01011
01012 c.cursor.y++;
01013 c.cursor.x -= pos;
01014 }
01015
01016 if (line == lastLine() || (getTextLine(line+1)->length() == 0) ) {
01017
01018 actionCursor.x = pos;
01019 actionCursor.y = line;
01020 recordAction(KateAction::newLine,actionCursor);
01021 } else {
01022
01023 actionCursor.y = line + 1;
01024 if (!s[l - 1].isSpace()) {
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
01054
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;
01065
01066 int y = c.cursor.y;
01067 while ((y > 0) && (pos < 0)) {
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
01077 QString s = tabString(pos, (c.flags & KateView::cfSpaceIndent) ? 0xffffff : tabChars);
01078 recordInsert(c.cursor, s);
01079 pos = s.length();
01080
01081
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
01108 c.cursor.x--;
01109 recordDelete(c.cursor, 1);
01110 } else {
01111
01112 int l = 1;
01113
01114 TextLine::Ptr textLine = getTextLine(c.cursor.y);
01115 int pos = textLine->firstChar();
01116 if (pos < 0 || pos >= c.cursor.x) {
01117
01118
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;
01125 break;
01126 }
01127 }
01128 }
01129
01130 c.cursor.x -= l;
01131 recordDelete(c.cursor, l);
01132 }
01133 } else {
01134
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) {
01148
01149 recordStart(c, KateActionGroup::ugDelChar);
01150 recordDelete(c.cursor, 1);
01151 recordEnd(c);
01152 } else {
01153 if (c.cursor.y < lastLine()) {
01154
01155 textLine->truncate(c.cursor.x);
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
01209 if (m_singleSelection)
01210 disconnect(QApplication::clipboard(), SIGNAL(dataChanged()), this, 0);
01211
01212 QApplication::clipboard()->setText(s);
01213
01214 if (m_singleSelection) {
01215 connect(QApplication::clipboard(), SIGNAL(dataChanged()),
01216 this, SLOT(clipboardChanged()));
01217 }
01218
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
01253
01254 x = oldX = z = 0;
01255 while (x < x1) {
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
01279 while (x < x2) {
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
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
01322
01323
01324 if (c.cursor.x != select.x || c.cursor.y != select.y) {
01325
01326
01327 if (!(c.flags & KateView::cfKeepSelection)) deselectAll();
01328
01329
01330 anchor = c.cursor;
01331 aXPos = c.cXPos;
01332 }
01333
01334 if (!(c.flags & KateView::cfVerticalSelect)) {
01335
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
01359 if (y < ey) {
01360
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
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
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
01406
01407
01408
01409
01410
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
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
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
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
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
01534 optimizeLeadingSpace(c.cursor.y, c.flags, change);
01535 } else {
01536
01537 TextLine::Ptr textLine;
01538 int line, z;
01539 QChar ch;
01540
01541 if (c.flags & KateView::cfKeepIndentProfile && change < 0) {
01542
01543
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
01568 recordEnd(c.view, c.cursor, c.flags | KateView::cfPersistent);
01569 }
01570
01571
01572
01573
01574
01575
01576
01577
01578
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;
01591 okLen = 0;
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;
01604
01605 if (space < 0 || chars == len) space = 0;
01606
01607 extra = space % tabChars;
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
01619 cursor.x = QMIN(okLen, QMIN(chars, space));
01620 chars -= cursor.x;
01621 space -= cursor.x;
01622 if (chars == 0 && space == 0) return;
01623
01624 s.fill(ch, space);
01625
01626
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
01653 c.cursor.x = 0;
01654 recordReplace(c.cursor, 0, startLineComment);
01655 }
01656 else if ((startComment != "") && (endComment != ""))
01657 {
01658
01659 c.cursor.x = 0;
01660 recordReplace(c.cursor, 0, startComment);
01661
01662
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
01693 c.cursor.x = 0;
01694 recordReplace(c.cursor, startLineCommentLen, "");
01695 }
01696 else if (textline->startingWith(startComment) && textline->endingWith(endComment))
01697 {
01698
01699 c.cursor.x = 0;
01700 recordReplace(c.cursor, startCommentLen, "");
01701
01702
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
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
01842 return s;
01843 }
01844 }
01845
01846 void KateDocument::delMarkedText(VConfig &c) {
01847 int end = 0;
01848
01849 if (selectEnd < selectStart) return;
01850
01851
01852
01853
01854
01855
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 c.cursor.x = end;
01874
01875 selectEnd = -1;
01876 select.x = -1;
01877
01878 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
01910 if (buffer->line(startLine)==0) {kdDebug(13020)<<"********************No buffer for line " << startLine << " found**************"<<endl; return;};
01911
01912 last_line = lastLine();
01913
01914
01915 line = startLine;
01916 ctxNum = 0;
01917 if (line > 0) ctxNum = getTextLine(line - 1)->getContext();
01918 do {
01919
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
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
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
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
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
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
02028 x = 0;
02029 z = 0;
02030 do {
02031 xc = x;
02032 zc = z;
02033 if (z == len) break;
02034 ch = s[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
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];
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;
02097
02098
02099 x = xc;
02100 z = zc;
02101 y += fontAscent;
02102 attr = -1;
02103 while (z < len) {
02104 ch = s[z];
02105 if (ch == '\t') {
02106 if (z > zc) {
02107
02108 QConstString str((QChar *) &s[zc], z - zc );
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
02143
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 );
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 );
02187 paint.drawText(x - xStart, y, str.string());
02188 }
02189 }
02190
02191
02192
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
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
02240 while (col < tlen) {
02241
02242 col = sc.search(text, col);
02243 if (col != -1) {
02244
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
02251 col++;
02252 }
02253 }
02254 else {
02255
02256 break;
02257 }
02258 }
02259 }
02260 else {
02261
02262 col = sc.search(text, col);
02263 if (col != -1)
02264 goto found;
02265 }
02266 col = 0;
02267 line++;
02268 }
02269 } else {
02270
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
02303 while (col >= 0) {
02304
02305 col = sc.search(text, col);
02306 if (col != -1) {
02307
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
02314 col--;
02315 }
02316 }
02317 else {
02318
02319 break;
02320 }
02321 }
02322 }
02323 else {
02324
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
02423
02424
02425
02426 }
02427 }
02428
02429 void KateDocument::doReplace(KateAction *a) {
02430 TextLine::Ptr textLine;
02431 int l;
02432
02433
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
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++;
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
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
02564
02565
02566
02567
02568
02569
02570 if (!keepModal) setPseudoModal(0L);
02571
02572
02573
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
02579
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
02594
02595
02596
02597
02598
02599
02600
02601
02602
02603
02604
02605
02606
02607
02608
02609
02610
02611
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
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
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
02676 a = new KateAction(KateAction::replace, cursor);
02677 undoList.getLast()->insertAction(a);
02678 }
02679
02680
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
02701
02702
02703 g = undoList.getLast();
02704 if (g->action == 0L) {
02705
02706 undoList.removeLast();
02707 return;
02708 }
02709
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
02722
02723
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737 if (undoCount == 0) newUndo();
02738 emit textChanged();
02739 }
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752
02753
02754
02755
02756
02757
02758
02759
02760
02761
02762
02763
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
02789
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
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;
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);
02841 needUpdate = true;
02842
02843
02844 }
02845
02846 if (needUpdate) {
02847
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;
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);
02866 needUpdate = true;
02867
02868
02869 }
02870
02871 if (needUpdate) {
02872
02873 c.view->updateCursor(g->end);
02874 setModified(true);
02875 newUndo();
02876 }
02877 }
02878
02879 void KateDocument::clearRedo() {
02880
02881
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
02899
02900
02901
02902
02903
02904
02905 if (pseudoModal && pseudoModal != (QWidget*)1L)
02906 delete pseudoModal;
02907
02908
02909
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;
02923 x = cursor.x -1;
02924 if (x < 0) return;
02925 line = cursor.y;
02926 count = 0;
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
02937 opposite = ')';
02938 if (bracket == '[') opposite = ']';
02939 if (bracket == '{') opposite = '}';
02940
02941 x++;
02942 while (line - cursor.y < 40) {
02943
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
02952 ch = textLine->getChar(x);
02953 if (ch == bracket) count++;
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
02991 bm.cursor.x = x;
02992 bm.cursor.y = line;
02993
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() {
03008
03009 if (m_singleSelection) {
03010 disconnect(QApplication::clipboard(), SIGNAL(dataChanged()),
03011 this, SLOT(clipboardChanged()));
03012 deselectAll();
03013 updateViews();
03014 }
03015
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 }