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 #include "katedocument.h"
00026 #include "katedocument.moc"
00027 #include "kateglobal.h"
00028 #include "katedialogs.h"
00029 #include "katehighlight.h"
00030 #include "kateview.h"
00031 #include "kateautoindent.h"
00032 #include "katetextline.h"
00033 #include "katedocumenthelpers.h"
00034 #include "kateprinter.h"
00035 #include "katesmartcursor.h"
00036 #include "katerenderer.h"
00037 #include "kateregexp.h"
00038 #include "kateplaintextsearch.h"
00039 #include "kateescapedtextsearch.h"
00040 #include "kateregexpsearch.h"
00041 #include <ktexteditor/attribute.h>
00042 #include "kateconfig.h"
00043 #include "katemodemanager.h"
00044 #include "kateschema.h"
00045 #include "katetemplatehandler.h"
00046 #include "katesmartmanager.h"
00047 #include <ktexteditor/plugin.h>
00048 #include <ktexteditor/loadsavefiltercheckplugin.h>
00049 #include <ktexteditor/rangefeedback.h>
00050 #include "kateedit.h"
00051 #include "katebuffer.h"
00052 #include "kateundomanager.h"
00053 #include "katepartpluginmanager.h"
00054 #include "katevireplacemode.h"
00055 #include "spellcheck/prefixstore.h"
00056 #include "spellcheck/ontheflycheck.h"
00057 #include "spellcheck/spellcheck.h"
00058
00059 #include <kio/job.h>
00060 #include <kio/jobuidelegate.h>
00061 #include <kio/netaccess.h>
00062 #include <kfileitem.h>
00063
00064 #include <kparts/event.h>
00065
00066 #include <klocale.h>
00067 #include <kglobal.h>
00068 #include <kapplication.h>
00069 #include <kmenu.h>
00070 #include <kconfig.h>
00071 #include <kfiledialog.h>
00072 #include <kmessagebox.h>
00073 #include <kstandardaction.h>
00074 #include <kxmlguifactory.h>
00075 #include <kdebug.h>
00076 #include <kglobalsettings.h>
00077 #include <klibloader.h>
00078 #include <kdirwatch.h>
00079 #include <kencodingfiledialog.h>
00080 #include <ktemporaryfile.h>
00081 #include <kcodecs.h>
00082 #include <kstandarddirs.h>
00083 #include <kstringhandler.h>
00084
00085 #include <kservicetypetrader.h>
00086
00087 #include <QtDBus/QtDBus>
00088 #include <QtCore/QTimer>
00089 #include <QtCore/QFile>
00090 #include <QtGui/QClipboard>
00091 #include <QtCore/QTextStream>
00092 #include <QtCore/QTextCodec>
00093 #include <QtCore/QMap>
00094 #include <QtCore/QMutex>
00095
00096
00097
00098 static int dummy = 0;
00099
00100
00101 class KateDocument::LoadSaveFilterCheckPlugins
00102 {
00103 public:
00104 LoadSaveFilterCheckPlugins() {
00105 KService::List traderList = KServiceTypeTrader::self()->query("KTextEditor/LoadSaveFilterCheckPlugin");
00106
00107 foreach(const KService::Ptr &ptr, traderList)
00108 {
00109 QString libname;
00110 libname=ptr->library();
00111 libname=libname.right(libname.length()-12);
00112 m_plugins[libname]=0;
00113 }
00114
00115 }
00116 ~LoadSaveFilterCheckPlugins() {
00117 if ( m_plugins.count()==0) return;
00118 QHashIterator<QString,KTextEditor::LoadSaveFilterCheckPlugin*>i(m_plugins);
00119 while (i.hasNext())
00120 i.next();
00121 delete i.value();
00122 m_plugins.clear();
00123 }
00124 bool preSavePostDialogFilterCheck(const QString& pluginName,KateDocument *document,QWidget *parentWidget) {
00125 KTextEditor::LoadSaveFilterCheckPlugin *plug=getPlugin(pluginName);
00126 if (!plug) {
00127 if (KMessageBox::warningContinueCancel (parentWidget
00128 , i18n ("The filter/check plugin '%1' could not be found, still continue saving of %2", pluginName,document->url().pathOrUrl())
00129 , i18n ("Saving problems")
00130 , KGuiItem(i18n("Save Nevertheless"))
00131 , KStandardGuiItem::cancel()) != KMessageBox::Continue)
00132 return false;
00133 else
00134 return true;
00135 }
00136 return plug->preSavePostDialogFilterCheck(document);
00137 }
00138 void postLoadFilter(const QString& pluginName,KateDocument *document) {
00139 KTextEditor::LoadSaveFilterCheckPlugin *plug=getPlugin(pluginName);
00140 if (!plug) return;
00141 plug->postLoadFilter(document);
00142 }
00143 bool postSaveFilterCheck(const QString& pluginName,KateDocument *document,bool saveas) {
00144 KTextEditor::LoadSaveFilterCheckPlugin *plug=getPlugin(pluginName);
00145 if (!plug) return false;
00146 return plug->postSaveFilterCheck(document,saveas);
00147 }
00148 private:
00149 KTextEditor::LoadSaveFilterCheckPlugin *getPlugin(const QString & pluginName)
00150 {
00151 if (!m_plugins.contains(pluginName)) return 0;
00152 if (!m_plugins[pluginName]) {
00153 m_plugins[pluginName]=KLibLoader::createInstance<KTextEditor::LoadSaveFilterCheckPlugin>( "ktexteditor_"+pluginName);
00154 }
00155 return m_plugins[pluginName];
00156 }
00157 QHash <QString,KTextEditor::LoadSaveFilterCheckPlugin*> m_plugins;
00158 };
00159
00160
00161
00162
00163
00164 KateDocument::KateDocument ( bool bSingleViewMode, bool bBrowserView,
00165 bool bReadOnly, QWidget *parentWidget,
00166 QObject *parent)
00167 : KTextEditor::Document (parent),
00168 m_activeView(0L),
00169 m_undoManager(new KateUndoManager(this)),
00170 m_annotationModel( 0 ),
00171 m_saveAs(false),
00172 m_indenter (new KateAutoIndent(this)),
00173 m_modOnHd (false),
00174 m_modOnHdReason (OnDiskUnmodified),
00175 s_fileChangedDialogsActivated (false),
00176 m_savingToUrl(false),
00177 m_onTheFlyChecker(NULL),
00178 m_dictionaryRangeNotifier(NULL)
00179 {
00180 setComponentData ( KateGlobal::self()->componentData () );
00181
00182 QString pathName ("/Kate/Document/%1");
00183 pathName = pathName.arg (++dummy);
00184
00185
00186 QDBusConnection::sessionBus().registerObject (pathName, this);
00187
00188
00189 KateGlobal::self()->registerDocument(this);
00190
00191 m_reloading = false;
00192
00193 m_editHistory = new KateEditHistory(this);
00194 m_smartManager = new KateSmartManager(this);
00195 m_buffer = new KateBuffer(this);
00196
00197
00198
00199 m_config = new KateDocumentConfig(this);
00200
00201
00202 setActiveView(0L);
00203
00204 hlSetByUser = false;
00205 m_bomSetByUser=false;
00206 m_fileTypeSetByUser = false;
00207
00208 editSessionNumber = 0;
00209 editIsRunning = false;
00210
00211 m_docNameNumber = 0;
00212 m_docName = "need init";
00213
00214 m_bSingleViewMode = bSingleViewMode;
00215 m_bBrowserView = bBrowserView;
00216 m_bReadOnly = bReadOnly;
00217
00218 setEditableMarks( markType01 );
00219
00220 clearMarks ();
00221 setModified (false);
00222
00223
00224 m_buffer->setHighlight (0);
00225
00226 m_blockRemoveTrailingSpaces = false;
00227 m_extension = new KateBrowserExtension( this );
00228
00229
00230 m_indenter->updateConfig ();
00231
00232
00233 connect(m_buffer, SIGNAL(tagLines(int,int)), this, SLOT(tagLines(int,int)));
00234 connect(m_buffer, SIGNAL(respellCheckBlock(int, int)), this , SLOT(respellCheckBlock(int, int)));
00235 connect(m_buffer, SIGNAL(codeFoldingUpdated()),this,SIGNAL(codeFoldingUpdated()));
00236
00237
00238 connect(KateHlManager::self(),SIGNAL(changed()),SLOT(internalHlChanged()));
00239
00240
00241 connect( KateGlobal::self()->dirWatch(), SIGNAL(dirty (const QString &)),
00242 this, SLOT(slotModOnHdDirty (const QString &)) );
00243
00244 connect( KateGlobal::self()->dirWatch(), SIGNAL(created (const QString &)),
00245 this, SLOT(slotModOnHdCreated (const QString &)) );
00246
00247 connect( KateGlobal::self()->dirWatch(), SIGNAL(deleted (const QString &)),
00248 this, SLOT(slotModOnHdDeleted (const QString &)) );
00249
00250 connect (this,SIGNAL(completed()),this,SLOT(slotCompleted()));
00251 connect (this,SIGNAL(canceled(const QString&)),this,SLOT(slotCanceled()));
00252
00253 setDocName (QString());
00254
00255
00256
00257
00258 if ( m_bSingleViewMode && parentWidget )
00259 {
00260 KTextEditor::View *view = (KTextEditor::View*)createView( parentWidget );
00261 insertChildClient( view );
00262 view->show();
00263 setWidget( view );
00264 }
00265
00266 connect(this,SIGNAL(sigQueryClose(bool *, bool*)),this,SLOT(slotQueryClose_save(bool *, bool*)));
00267
00268 m_isasking = 0;
00269
00270 onTheFlySpellCheckingEnabled(config()->onTheFlySpellCheck());
00271
00272
00273 KatePartPluginManager::self()->addDocument(this);
00274 }
00275
00276
00277
00278
00279 KateDocument::~KateDocument()
00280 {
00281
00282 delete m_onTheFlyChecker;
00283 m_onTheFlyChecker = NULL;
00284
00285 clearDictionaryRanges();
00286 deleteDiscardedSmartRanges();
00287
00288
00289
00290
00291 emit aboutToClose(this);
00292
00293
00294 deactivateDirWatch ();
00295
00296
00297 setAutoDeleteWidget(false);
00298 setAutoDeletePart(false);
00299
00300
00301 while (!m_views.isEmpty()) {
00302 delete m_views.takeFirst();
00303 }
00304
00305
00306 KatePartPluginManager::self()->removeDocument(this);
00307
00308
00309 for (QHash<int, KTextEditor::Mark*>::const_iterator i = m_marks.constBegin(); i != m_marks.constEnd(); ++i)
00310 delete i.value();
00311 m_marks.clear();
00312
00313 delete m_config;
00314 KateGlobal::self()->deregisterDocument (this);
00315 }
00316
00317
00318
00319 QWidget *KateDocument::widget()
00320 {
00321
00322 if (!singleViewMode())
00323 return 0;
00324
00325
00326 if (KTextEditor::Document::widget())
00327 return KTextEditor::Document::widget();
00328
00329
00330 KTextEditor::View *view = (KTextEditor::View*)createView(0);
00331 insertChildClient( view );
00332 setWidget( view );
00333 return view;
00334 }
00335
00336
00337
00338 KTextEditor::View *KateDocument::createView( QWidget *parent )
00339 {
00340 KateView* newView = new KateView( this, parent);
00341 if ( s_fileChangedDialogsActivated )
00342 connect( newView, SIGNAL(focusIn( KTextEditor::View * )), this, SLOT(slotModifiedOnDisk()) );
00343
00344 emit viewCreated (this, newView);
00345
00346 return newView;
00347 }
00348
00349 const QList<KTextEditor::View*> &KateDocument::views () const
00350 {
00351 return m_textEditViews;
00352 }
00353
00354 KTextEditor::Editor *KateDocument::editor ()
00355 {
00356 return KateGlobal::self();
00357 }
00358
00359
00360
00361 QString KateDocument::text() const
00362 {
00363 QString s;
00364
00365 for (int i = 0; i < m_buffer->count(); i++)
00366 {
00367 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00368
00369 if (textLine)
00370 {
00371 s.append (textLine->string());
00372
00373 if ((i+1) < m_buffer->count())
00374 s.append(QChar::fromAscii('\n'));
00375 }
00376 }
00377
00378 return s;
00379 }
00380
00381 QString KateDocument::text( const KTextEditor::Range& range, bool blockwise ) const
00382 {
00383 if (!range.isValid()) {
00384 kWarning() << k_funcinfo << "Text requested for invalid range" << range;
00385 return QString();
00386 }
00387
00388 if ( blockwise && (range.start().column() > range.end().column()) )
00389 return QString ();
00390
00391 QString s;
00392
00393 if (range.start().line() == range.end().line())
00394 {
00395 if (range.start().column() > range.end().column())
00396 return QString ();
00397
00398 KateTextLine::Ptr textLine = m_buffer->plainLine(range.start().line());
00399
00400 if ( !textLine )
00401 return QString ();
00402
00403 return textLine->string(range.start().column(), range.end().column()-range.start().column());
00404 }
00405 else
00406 {
00407
00408 for (int i = range.start().line(); (i <= range.end().line()) && (i < m_buffer->count()); ++i)
00409 {
00410 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00411
00412 if ( !blockwise )
00413 {
00414 if (i == range.start().line())
00415 s.append (textLine->string(range.start().column(), textLine->length()-range.start().column()));
00416 else if (i == range.end().line())
00417 s.append (textLine->string(0, range.end().column()));
00418 else
00419 s.append (textLine->string());
00420 }
00421 else
00422 {
00423 s.append( textLine->string( range.start().column(), range.end().column()-range.start().column()));
00424 }
00425
00426 if ( i < range.end().line() )
00427 s.append(QChar::fromAscii('\n'));
00428 }
00429 }
00430
00431 return s;
00432 }
00433
00434 QChar KateDocument::character( const KTextEditor::Cursor & position ) const
00435 {
00436 KateTextLine::Ptr textLine = m_buffer->plainLine(position.line());
00437
00438 if ( !textLine )
00439 return QChar();
00440
00441 if (position.column() >= 0 && position.column() < textLine->string().length())
00442 return textLine->string().at(position.column());
00443
00444 return QChar();
00445 }
00446
00447 QStringList KateDocument::textLines( const KTextEditor::Range & range, bool blockwise ) const
00448 {
00449 QStringList ret;
00450
00451 if (!range.isValid()) {
00452 kWarning() << k_funcinfo << "Text requested for invalid range" << range;
00453 return ret;
00454 }
00455
00456 if ( blockwise && (range.start().column() > range.end().column()) )
00457 return ret;
00458
00459 if (range.start().line() == range.end().line())
00460 {
00461 Q_ASSERT(range.start() <= range.end());
00462
00463 KateTextLine::Ptr textLine = m_buffer->plainLine(range.start().line());
00464
00465 if ( !textLine )
00466 return ret;
00467
00468 ret << textLine->string(range.start().column(), range.end().column() - range.start().column());
00469 }
00470 else
00471 {
00472 for (int i = range.start().line(); (i <= range.end().line()) && (i < m_buffer->count()); ++i)
00473 {
00474 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00475
00476 if ( !blockwise )
00477 {
00478 if (i == range.start().line())
00479 ret << textLine->string(range.start().column(), textLine->length() - range.start().column());
00480 else if (i == range.end().line())
00481 ret << textLine->string(0, range.end().column());
00482 else
00483 ret << textLine->string();
00484 }
00485 else
00486 {
00487 ret << textLine->string(range.start().column(), range.end().column() - range.start().column());
00488 }
00489 }
00490 }
00491
00492 return ret;
00493 }
00494
00495 QString KateDocument::line( int line ) const
00496 {
00497 KateTextLine::Ptr l = m_buffer->plainLine(line);
00498
00499 if (!l)
00500 return QString();
00501
00502 return l->string();
00503 }
00504
00505 bool KateDocument::setText(const QString &s)
00506 {
00507 if (!isReadWrite())
00508 return false;
00509
00510 QList<KTextEditor::Mark> msave;
00511
00512 foreach (KTextEditor::Mark* mark, m_marks)
00513 msave.append(*mark);
00514
00515 editStart ();
00516
00517
00518 clear();
00519
00520
00521 insertText (KTextEditor::Cursor(), s);
00522
00523 editEnd ();
00524
00525 foreach (const KTextEditor::Mark& mark, msave)
00526 setMark (mark.line, mark.type);
00527
00528 return true;
00529 }
00530
00531 bool KateDocument::setText( const QStringList & text )
00532 {
00533 if (!isReadWrite())
00534 return false;
00535
00536 QList<KTextEditor::Mark> msave;
00537
00538 foreach (KTextEditor::Mark* mark, m_marks)
00539 msave.append(*mark);
00540
00541 editStart ();
00542
00543
00544 clear();
00545
00546
00547 insertText (KTextEditor::Cursor::start(), text);
00548
00549 editEnd ();
00550
00551 foreach (const KTextEditor::Mark& mark, msave)
00552 setMark (mark.line, mark.type);
00553
00554 return true;
00555 }
00556
00557 bool KateDocument::clear()
00558 {
00559 if (!isReadWrite())
00560 return false;
00561
00562 foreach (KateView *view, m_views) {
00563 view->clear();
00564 view->tagAll();
00565 view->update();
00566 }
00567
00568 clearMarks ();
00569
00570 return removeText (KTextEditor::Range(KTextEditor::Cursor(), KTextEditor::Cursor(lastLine()+1, 0)));
00571 }
00572
00573 bool KateDocument::insertText( const KTextEditor::Cursor& position, const QString& text, bool block )
00574 {
00575 if (!isReadWrite())
00576 return false;
00577
00578 if (text.isEmpty())
00579 return true;
00580
00581 editStart();
00582
00583 int currentLine = position.line();
00584 int currentLineStart = 0;
00585 int totalLength = text.length();
00586 int insertColumn = position.column();
00587
00588 if (position.line() > lines())
00589 {
00590 int line = lines();
00591 while (line != position.line() + totalLength + 1)
00592 {
00593 editInsertLine(line,QString());
00594 line++;
00595 }
00596 }
00597
00598 bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn );
00599 int tabWidth = config()->tabWidth();
00600
00601 static const QChar newLineChar('\n');
00602 static const QChar tabChar('\t');
00603 static const QChar spaceChar(' ');
00604
00605 int insertColumnExpanded = insertColumn;
00606 KateTextLine::Ptr l = kateTextLine( currentLine );
00607 if (l)
00608 insertColumnExpanded = l->toVirtualColumn( insertColumn, tabWidth );
00609
00610 int pos = 0;
00611 for (; pos < totalLength; pos++)
00612 {
00613 const QChar& ch = text.at(pos);
00614
00615 if (ch == newLineChar)
00616 {
00617
00618 if (currentLineStart < pos)
00619 editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart));
00620
00621 if ( !block )
00622 {
00623 editWrapLine(currentLine, insertColumn + pos - currentLineStart);
00624 insertColumn = 0;
00625 }
00626 else
00627 {
00628 if ( currentLine == lastLine() )
00629 editWrapLine(currentLine , insertColumn + pos - currentLineStart);
00630 insertColumn = position.column();
00631 }
00632
00633 currentLine++;
00634 currentLineStart = pos + 1;
00635 l = kateTextLine( currentLine );
00636 if (l)
00637 insertColumnExpanded = l->toVirtualColumn( insertColumn, tabWidth );
00638 }
00639 else
00640 {
00641 if ( replacetabs && ch == tabChar )
00642 {
00643 int spacesRequired = tabWidth - ( (insertColumnExpanded + pos - currentLineStart) % tabWidth );
00644 editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart) + QString(spacesRequired, spaceChar));
00645
00646 insertColumn += pos - currentLineStart + spacesRequired;
00647 currentLineStart = pos + 1;
00648 l = kateTextLine( currentLine );
00649 if (l)
00650 insertColumnExpanded = l->toVirtualColumn( insertColumn, tabWidth );
00651 }
00652 }
00653 }
00654
00655
00656 if (currentLineStart < pos)
00657 editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart));
00658
00659 editEnd();
00660 return true;
00661 }
00662
00663 bool KateDocument::insertText( const KTextEditor::Cursor & position, const QStringList & textLines, bool block )
00664 {
00665 if (!isReadWrite())
00666 return false;
00667
00668 if (textLines.isEmpty() || (textLines.count() == 1 && textLines.first().isEmpty()))
00669 return true;
00670
00671
00672 if (position.line() > lines())
00673 return false;
00674
00675 editStart();
00676
00677 if (position.line() > lines())
00678 editInsertLine(position.line(),QString());
00679
00680 int currentLine = position.line();
00681 int currentLineStart = 0;
00682 int insertColumn = position.column();
00683
00684 bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn );
00685 int tabWidth = config()->tabWidth();
00686
00687 static const QChar newLineChar('\n');
00688 static const QChar tabChar('\t');
00689 static const QChar spaceChar(' ');
00690
00691 int insertColumnExpanded = insertColumn;
00692 KateTextLine::Ptr l = kateTextLine( currentLine );
00693 if (l)
00694 insertColumnExpanded = l->toVirtualColumn( insertColumn, tabWidth );
00695
00696 foreach (const QString &text, textLines)
00697 {
00698 int pos = 0;
00699 for (; pos < text.length(); pos++)
00700 {
00701 const QChar& ch = text.at(pos);
00702
00703 if (ch == newLineChar)
00704 {
00705
00706 if (currentLineStart < pos)
00707 editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart));
00708
00709 if ( !block )
00710 {
00711 editWrapLine(currentLine, pos + insertColumn);
00712 insertColumn = 0;
00713 }
00714 else
00715 {
00716 if ( currentLine == lastLine() )
00717 editWrapLine(currentLine , insertColumn + pos - currentLineStart);
00718 insertColumn = position.column();
00719 }
00720
00721 currentLine++;
00722 currentLineStart = pos + 1;
00723 l = kateTextLine( currentLine );
00724 if (l)
00725 insertColumnExpanded = l->toVirtualColumn( insertColumn, tabWidth );
00726 }
00727 else
00728 {
00729 if ( replacetabs && ch == tabChar )
00730 {
00731 int spacesRequired = tabWidth - ( (insertColumnExpanded + pos - currentLineStart) % tabWidth );
00732 editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart) + QString(spacesRequired, spaceChar));
00733
00734 insertColumn += pos - currentLineStart + spacesRequired;
00735 l = kateTextLine( currentLine );
00736 if (l)
00737 insertColumnExpanded = l->toVirtualColumn( insertColumn, tabWidth );
00738 currentLineStart = pos + 1;
00739 }
00740 }
00741 }
00742
00743
00744 if (currentLineStart < pos - currentLineStart)
00745 editInsertText(currentLine, insertColumn, text.mid(currentLineStart, pos - currentLineStart));
00746 }
00747
00748 editEnd();
00749 return true;
00750 }
00751
00752
00753 bool KateDocument::removeText ( const KTextEditor::Range &_range, bool block )
00754 {
00755 KTextEditor::Range range = _range;
00756
00757 if (!isReadWrite())
00758 return false;
00759
00760 if ( block && (range.start().column() > range.end().column()) )
00761 return false;
00762
00763
00764 Q_ASSERT( range.start().line() <= range.end().line() );
00765
00766 if ( range.start().line() > lastLine() )
00767 return false;
00768
00769 if (!block)
00770 emit aboutToRemoveText(range);
00771
00772 editStart();
00773
00774 if ( !block )
00775 {
00776 if ( range.end().line() > lastLine() )
00777 {
00778 range.end().setPosition(lastLine()+1, 0);
00779 }
00780
00781 if (range.onSingleLine())
00782 {
00783 editRemoveText(range.start().line(), range.start().column(), range.columnWidth());
00784 }
00785 else
00786 {
00787 int from = range.start().line();
00788 int to = range.end().line();
00789
00790 if (to <= lastLine())
00791 editRemoveText(to, 0, range.end().column());
00792
00793 if (range.start().column() == 0)
00794 --from;
00795
00796 editRemoveLines(from+1, to-1);
00797
00798 if (range.start().column() > 0) {
00799 editRemoveText(from, range.start().column(), m_buffer->plainLine(from)->length() - range.start().column());
00800 editUnWrapLine(from);
00801 }
00802 }
00803 }
00804 else
00805 {
00806 int startLine = qMax(0, range.start().line());
00807 for (int line = qMin(range.end().line(), lastLine()); line >= startLine; --line)
00808 editRemoveText(line, range.start().column(), range.end().column() - range.start().column());
00809 }
00810
00811 editEnd ();
00812 emit textRemoved();
00813 return true;
00814 }
00815
00816 bool KateDocument::insertLine( int l, const QString &str )
00817 {
00818 if (!isReadWrite())
00819 return false;
00820
00821 if (l < 0 || l > lines())
00822 return false;
00823
00824 return editInsertLine (l, str);
00825 }
00826
00827 bool KateDocument::insertLines( int line, const QStringList & text )
00828 {
00829 if (!isReadWrite())
00830 return false;
00831
00832 if (line < 0 || line > lines())
00833 return false;
00834
00835 bool success = true;
00836 foreach (const QString &string, text)
00837
00838 success &= editInsertLine (line++, string);
00839
00840 return success;
00841 }
00842
00843 bool KateDocument::removeLine( int line )
00844 {
00845 if (!isReadWrite())
00846 return false;
00847
00848 if (line < 0 || line > lastLine())
00849 return false;
00850
00851 return editRemoveLine (line);
00852 }
00853
00854 int KateDocument::totalCharacters() const
00855 {
00856 int l = 0;
00857
00858 for (int i = 0; i < m_buffer->count(); ++i)
00859 {
00860 KateTextLine::Ptr line = m_buffer->plainLine(i);
00861
00862 if (line)
00863 l += line->length();
00864 }
00865
00866 return l;
00867 }
00868
00869 int KateDocument::lines() const
00870 {
00871 return m_buffer->count();
00872 }
00873
00874 int KateDocument::numVisLines() const
00875 {
00876 return m_buffer->countVisible ();
00877 }
00878
00879 int KateDocument::lineLength ( int line ) const
00880 {
00881 if (line < 0 || line > lastLine())
00882 return -1;
00883
00884 KateTextLine::Ptr l = m_buffer->plainLine(line);
00885
00886 if (!l)
00887 return -1;
00888
00889 return l->length();
00890 }
00891
00892
00893
00894
00895
00896
00897 void KateDocument::editStart (Kate::EditSource editSource)
00898 {
00899 editSessionNumber++;
00900
00901 if (editSource == Kate::NoEditSource)
00902 m_editSources.push(m_editSources.isEmpty() ? Kate::UserInputEdit : m_editSources.top());
00903 else
00904 m_editSources.push(editSource);
00905
00906
00907 smartMutex()->lock();
00908
00909 if (editSessionNumber > 1)
00910 return;
00911
00912 editIsRunning = true;
00913
00914 m_undoManager->editStart();
00915
00916 foreach(KateView *view,m_views)
00917 {
00918 view->editStart ();
00919 }
00920
00921 m_buffer->editStart ();
00922 }
00923
00924 void KateDocument::undoSafePoint() {
00925 m_undoManager->undoSafePoint();
00926 }
00927
00928
00929
00930
00931 void KateDocument::editEnd ()
00932 {
00933 if (editSessionNumber == 0) {
00934
00935
00936 Q_ASSERT(0);
00937 return;
00938 }
00939
00940
00941 if (m_buffer->editChanged() && (editSessionNumber == 1))
00942 if (m_undoManager->isUndoTrackingEnabled() && config()->wordWrap())
00943 wrapText (m_buffer->editTagStart(), m_buffer->editTagEnd());
00944
00945 editSessionNumber--;
00946
00947 m_editSources.pop();
00948
00949
00950 smartMutex()->unlock();
00951
00952 if (editSessionNumber > 0)
00953 return;
00954
00955
00956
00957 m_buffer->editEnd ();
00958
00959 m_undoManager->editEnd();
00960
00961
00962 foreach(KateView *view, m_views)
00963 view->editEnd (m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
00964
00965 if (m_buffer->editChanged())
00966 {
00967 setModified(true);
00968 emit textChanged (this);
00969 }
00970
00971 editIsRunning = false;
00972 }
00973
00974 void KateDocument::pushEditState ()
00975 {
00976 editStateStack.push(editSessionNumber);
00977 }
00978
00979 void KateDocument::popEditState ()
00980 {
00981 if (editStateStack.isEmpty()) return;
00982
00983 int count = editStateStack.pop() - editSessionNumber;
00984 while (count < 0) { ++count; editEnd(); }
00985 while (count > 0) { --count; editStart(); }
00986 }
00987
00988 void KateDocument::inputMethodStart()
00989 {
00990 m_undoManager->inputMethodStart();
00991 }
00992
00993 void KateDocument::inputMethodEnd()
00994 {
00995 m_undoManager->inputMethodEnd();
00996 }
00997
00998 bool KateDocument::wrapText(int startLine, int endLine)
00999 {
01000 if (startLine < 0 || endLine < 0)
01001 return false;
01002
01003 if (!isReadWrite())
01004 return false;
01005
01006 int col = config()->wordWrapAt();
01007
01008 if (col == 0)
01009 return false;
01010
01011 editStart ();
01012
01013 for (int line = startLine; (line <= endLine) && (line < lines()); line++)
01014 {
01015 KateTextLine::Ptr l = kateTextLine(line);
01016
01017 if (!l)
01018 return false;
01019
01020 kDebug (13020) << "try wrap line: " << line;
01021
01022 if (l->virtualLength(m_buffer->tabWidth()) > col)
01023 {
01024 KateTextLine::Ptr nextl = kateTextLine(line+1);
01025
01026 kDebug (13020) << "do wrap line: " << line;
01027
01028 int eolPosition = l->length()-1;
01029
01030
01031 int x = 0;
01032 const QString & t = l->string();
01033 int z2 = 0;
01034 for ( ; z2 < l->length(); z2++)
01035 {
01036 static const QChar tabChar('\t');
01037 if (t.at(z2) == tabChar)
01038 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
01039 else
01040 x++;
01041
01042 if (x > col)
01043 break;
01044 }
01045
01046 int searchStart = qMin (z2, l->length()-1);
01047
01048
01049
01050 if (searchStart == eolPosition && t.at(searchStart).isSpace())
01051 searchStart--;
01052
01053
01054
01055
01056
01057
01058
01059 int z = 0;
01060 int nw = 0;
01061 for (z=searchStart; z > 0; z--)
01062 {
01063 if (t.at(z).isSpace()) break;
01064 if ( ! nw && highlight()->canBreakAt( t.at(z) , l->attribute(z) ) )
01065 nw = z;
01066 }
01067
01068 bool removeTrailingSpace = false;
01069 if (z > 0)
01070 {
01071
01072
01073
01074
01075
01076 z++;
01077 removeTrailingSpace = true;
01078 }
01079 else
01080 {
01081
01082
01083
01084 if ( nw && nw < col ) nw++;
01085 z = nw ? nw : col;
01086 }
01087
01088 if (nextl && !nextl->isAutoWrapped())
01089 {
01090 editWrapLine (line, z, true);
01091 editMarkLineAutoWrapped (line+1, true);
01092
01093 endLine++;
01094 }
01095 else
01096 {
01097 if (nextl && (nextl->length() > 0) && !nextl->at(0).isSpace() && ((l->length() < 1) || !l->at(l->length()-1).isSpace()))
01098 editInsertText (line+1, 0, QString (" "));
01099
01100 bool newLineAdded = false;
01101 editWrapLine (line, z, false, &newLineAdded);
01102
01103 editMarkLineAutoWrapped (line+1, true);
01104
01105 endLine++;
01106 }
01107
01108 if (removeTrailingSpace) {
01109
01110 editRemoveText (line, z - 1, 1);
01111 }
01112 }
01113 }
01114
01115 editEnd ();
01116
01117 return true;
01118 }
01119
01120 bool KateDocument::editInsertText ( int line, int col, const QString &s, Kate::EditSource editSource )
01121 {
01122 if (line < 0 || col < 0)
01123 return false;
01124
01125 if (!isReadWrite())
01126 return false;
01127
01128 KateTextLine::Ptr l = kateTextLine(line);
01129
01130 if (!l)
01131 return false;
01132
01133 editStart (editSource);
01134
01135 QString s2 = s;
01136 int col2 = col;
01137 if (col2 > l->length()) {
01138 s2 = QString(col2 - l->length(), QLatin1Char(' ')) + s;
01139 col2 = l->length();
01140 }
01141
01142 m_undoManager->slotTextInserted(line, col2, s2);
01143
01144 l->insertText (col2, s2);
01145
01146 m_buffer->changeLine(line);
01147
01148 history()->doEdit( new KateEditInfo(m_editSources.top(), KTextEditor::Range(line, col2, line, col),
01149 QStringList(), KTextEditor::Range(line, col2, line, col2 + s2.length()), QStringList(s2)) );
01150 emit KTextEditor::Document::textInserted(this, KTextEditor::Range(line, col2, line, col2 + s2.length()));
01151
01152 editEnd();
01153
01154 return true;
01155 }
01156
01157 bool KateDocument::editRemoveText ( int line, int col, int len, Kate::EditSource editSource )
01158 {
01159 if (line < 0 || col < 0 || len < 0)
01160 return false;
01161
01162 if (!isReadWrite())
01163 return false;
01164
01165 KateTextLine::Ptr l = kateTextLine(line);
01166
01167 if (!l)
01168 return false;
01169
01170 editStart (editSource);
01171
01172 m_undoManager->slotTextRemoved(line, col, l->string().mid(col, len));
01173
01174 l->removeText (col, len);
01175 removeTrailingSpace( line );
01176
01177 m_buffer->changeLine(line);
01178
01179 history()->doEdit( new KateEditInfo(m_editSources.top(), KTextEditor::Range(line, col, line, col + len), QStringList(l->string().mid(col, len)), KTextEditor::Range(line, col, line, col), QStringList()) );
01180 emit KTextEditor::Document::textRemoved(this, KTextEditor::Range(line, col, line, col + len));
01181
01182 editEnd ();
01183
01184 return true;
01185 }
01186
01187 bool KateDocument::editMarkLineAutoWrapped ( int line, bool autowrapped )
01188 {
01189 if (line < 0)
01190 return false;
01191
01192 if (!isReadWrite())
01193 return false;
01194
01195 KateTextLine::Ptr l = kateTextLine(line);
01196
01197 if (!l)
01198 return false;
01199
01200 editStart ();
01201
01202 m_undoManager->slotMarkLineAutoWrapped(line, autowrapped);
01203
01204 l->setAutoWrapped (autowrapped);
01205
01206 m_buffer->changeLine(line);
01207
01208 editEnd ();
01209
01210 return true;
01211 }
01212
01213 bool KateDocument::editWrapLine ( int line, int col, bool newLine, bool *newLineAdded)
01214 {
01215 if (line < 0 || col < 0)
01216 return false;
01217
01218 if (!isReadWrite())
01219 return false;
01220
01221 KateTextLine::Ptr l = kateTextLine(line);
01222
01223 if (!l)
01224 return false;
01225
01226 editStart ();
01227
01228 KateTextLine::Ptr nextLine = kateTextLine(line+1);
01229
01230 int pos = l->length() - col;
01231
01232 if (pos < 0)
01233 pos = 0;
01234
01235 m_undoManager->slotLineWrapped(line, col, pos, (!nextLine || newLine));
01236
01237 if (!nextLine || newLine)
01238 {
01239 KateTextLine::Ptr textLine(new KateTextLine());
01240
01241 textLine->insertText (0, l->string().mid(col, pos));
01242 l->truncate(col);
01243
01244 m_buffer->insertLine (line+1, textLine);
01245 m_buffer->changeLine(line);
01246
01247 QList<KTextEditor::Mark*> list;
01248 for (QHash<int, KTextEditor::Mark*>::const_iterator i = m_marks.constBegin(); i != m_marks.constEnd(); ++i)
01249 {
01250 if( i.value()->line >= line )
01251 {
01252 if ((col == 0) || (i.value()->line > line))
01253 list.append( i.value() );
01254 }
01255 }
01256
01257 for( int i=0; i < list.size(); ++i )
01258 m_marks.take( list[i]->line );
01259
01260 for( int i=0; i < list.size(); ++i )
01261 {
01262 list[i]->line++;
01263 m_marks.insert( list[i]->line, list[i] );
01264 }
01265
01266 if( !list.isEmpty() )
01267 emit marksChanged( this );
01268
01269
01270 if (newLineAdded)
01271 (*newLineAdded) = true;
01272
01273 history()->doEdit( new KateEditInfo(m_editSources.top(), KTextEditor::Range(line, col, line, col), QStringList(), KTextEditor::Range(line, col, line+1, 0), QStringList()) );
01274 }
01275 else
01276 {
01277 nextLine->insertText (0, l->string().mid(col, pos));
01278 l->truncate(col);
01279
01280 m_buffer->changeLine(line);
01281 m_buffer->changeLine(line+1);
01282
01283
01284 if (newLineAdded)
01285 (*newLineAdded) = false;
01286
01287 history()->doEdit( new KateEditInfo(m_editSources.top(), KTextEditor::Range(line, col, line+1, 0), QStringList(), KTextEditor::Range(line, col, line+1, pos), QStringList()) );
01288 }
01289
01290 emit KTextEditor::Document::textInserted(this, KTextEditor::Range(line, col, line+1, pos));
01291
01292 editEnd ();
01293
01294 return true;
01295 }
01296
01297 bool KateDocument::editUnWrapLine ( int line, bool removeLine, int length )
01298 {
01299 if (line < 0 || length < 0)
01300 return false;
01301
01302 if (!isReadWrite())
01303 return false;
01304
01305 KateTextLine::Ptr l = kateTextLine(line);
01306 KateTextLine::Ptr nextLine = kateTextLine(line+1);
01307
01308 if (!l || !nextLine)
01309 return false;
01310
01311 editStart ();
01312
01313 int col = l->length ();
01314
01315 m_undoManager->slotLineUnWrapped(line, col, length, removeLine);
01316
01317 if (removeLine)
01318 {
01319 l->insertText (col, nextLine->string());
01320
01321 m_buffer->changeLine(line);
01322 m_buffer->removeLine(line+1);
01323 }
01324 else
01325 {
01326 l->insertText (col, nextLine->string().left((nextLine->length() < length) ? nextLine->length() : length));
01327 nextLine->removeText (0, (nextLine->length() < length) ? nextLine->length() : length);
01328
01329 m_buffer->changeLine(line);
01330 m_buffer->changeLine(line+1);
01331 }
01332
01333 QList<KTextEditor::Mark*> list;
01334 for (QHash<int, KTextEditor::Mark*>::const_iterator i = m_marks.constBegin(); i != m_marks.constEnd(); ++i)
01335 {
01336 if( i.value()->line >= line+1 )
01337 list.append( i.value() );
01338
01339 if ( i.value()->line == line+1 )
01340 {
01341 KTextEditor::Mark* mark = m_marks.take( line );
01342
01343 if (mark)
01344 {
01345 i.value()->type |= mark->type;
01346 }
01347 }
01348 }
01349
01350 for( int i=0; i < list.size(); ++i )
01351 m_marks.take( list[i]->line );
01352
01353 for( int i=0; i < list.size(); ++i )
01354 {
01355 list[i]->line--;
01356 m_marks.insert( list[i]->line, list[i] );
01357 }
01358
01359 if( !list.isEmpty() )
01360 emit marksChanged( this );
01361
01362 history()->doEdit( new KateEditInfo(m_editSources.top(), KTextEditor::Range(line, col, line+1, 0), QStringList(QString()), KTextEditor::Range(line, col, line, col), QStringList()) );
01363 emit KTextEditor::Document::textRemoved(this, KTextEditor::Range(line, col, line+1, 0));
01364
01365 editEnd ();
01366
01367 return true;
01368 }
01369
01370 bool KateDocument::editInsertLine ( int line, const QString &s, Kate::EditSource editSource )
01371 {
01372 if (line < 0)
01373 return false;
01374
01375 if (!isReadWrite())
01376 return false;
01377
01378 if ( line > lines() )
01379 return false;
01380
01381 editStart (editSource);
01382
01383 m_undoManager->slotLineInserted(line, s);
01384
01385 removeTrailingSpace( line );
01386
01387 KateTextLine::Ptr tl(new KateTextLine());
01388 tl->insertText (0, s);
01389 m_buffer->insertLine(line, tl);
01390 m_buffer->changeLine(line);
01391
01392 removeTrailingSpace( line );
01393
01394 QList<KTextEditor::Mark*> list;
01395 for (QHash<int, KTextEditor::Mark*>::const_iterator i = m_marks.constBegin(); i != m_marks.constEnd(); ++i)
01396 {
01397 if( i.value()->line >= line )
01398 list.append( i.value() );
01399 }
01400
01401 for( int i=0; i < list.size(); ++i )
01402 m_marks.take( list[i]->line );
01403
01404 for( int i=0; i < list.size(); ++i )
01405 {
01406 list[i]->line++;
01407 m_marks.insert( list[i]->line, list[i] );
01408 }
01409
01410 if( !list.isEmpty() )
01411 emit marksChanged( this );
01412
01413 KTextEditor::Range rangeInserted(line, 0, line, tl->length());
01414
01415 if (line) {
01416 KateTextLine::Ptr prevLine = plainKateTextLine(line - 1);
01417 rangeInserted.start().setPosition(line - 1, prevLine->length());
01418 } else {
01419 rangeInserted.end().setPosition(line + 1, 0);
01420 }
01421
01422 history()->doEdit( new KateEditInfo(m_editSources.top(), KTextEditor::Range(rangeInserted.start(), rangeInserted.start()), QStringList(), rangeInserted, QStringList(s)) );
01423 emit KTextEditor::Document::textInserted(this, rangeInserted);
01424
01425 editEnd ();
01426
01427 return true;
01428 }
01429
01430 bool KateDocument::editRemoveLine ( int line, Kate::EditSource editSource )
01431 {
01432 return editRemoveLines(line, line, editSource);
01433 }
01434
01435 bool KateDocument::editRemoveLines ( int from, int to, Kate::EditSource editSource )
01436 {
01437 if (to < from || from < 0 || to > lastLine())
01438 return false;
01439
01440 if (!isReadWrite())
01441 return false;
01442
01443 editStart(editSource);
01444 QStringList oldText;
01445
01446 if (lines() == 1)
01447 return editRemoveText(0, 0, kateTextLine(0)->length());
01448
01449 for (int line = to; line >= from; line--) {
01450 KateLineInfo info;
01451 lineInfo(&info, line);
01452 if (info.startsInVisibleBlock)
01453 foldingTree()->toggleRegionVisibility(line);
01454 }
01455
01456 for (int line = to; line >= from; line--) {
01457 oldText << this->line(line);
01458 m_undoManager->slotLineRemoved(line, this->line(line));
01459
01460 m_buffer->removeLine(line);
01461 }
01462
01463 QList<int> rmark;
01464 QList<int> list;
01465
01466 foreach (KTextEditor::Mark* mark, m_marks) {
01467 int line = mark->line;
01468 if (line > to)
01469 list << line;
01470 else if (line >= from)
01471 rmark << line;
01472 }
01473
01474 foreach (int line, rmark)
01475 delete m_marks.take(line);
01476
01477 foreach (int line, list)
01478 {
01479 KTextEditor::Mark* mark = m_marks.take(line);
01480 mark->line -= to - from + 1;
01481 m_marks.insert(mark->line, mark);
01482 }
01483
01484 if (!list.isEmpty())
01485 emit marksChanged(this);
01486
01487 KTextEditor::Range rangeRemoved(from, 0, to + 1, 0);
01488
01489 if (to == lastLine()) {
01490 rangeRemoved.end().setPosition(to, oldText.first().length());
01491 if (from > 0) {
01492 KateTextLine::Ptr prevLine = plainKateTextLine(from - 1);
01493 rangeRemoved.start().setPosition(from - 1, prevLine->length());
01494 }
01495 }
01496
01497 history()->doEdit(new KateEditInfo(m_editSources.top(), rangeRemoved, oldText, KTextEditor::Range(rangeRemoved.start(), rangeRemoved.start()), QStringList()));
01498 emit KTextEditor::Document::textRemoved(this, rangeRemoved);
01499
01500 editEnd();
01501
01502 return true;
01503 }
01504
01505
01506
01507
01508 uint KateDocument::undoCount () const
01509 {
01510 return m_undoManager->undoCount ();
01511 }
01512
01513 uint KateDocument::redoCount () const
01514 {
01515 return m_undoManager->redoCount ();
01516 }
01517
01518 void KateDocument::undo()
01519 {
01520 m_undoManager->undo();
01521 }
01522
01523 void KateDocument::redo()
01524 {
01525 m_undoManager->redo();
01526 }
01527
01528
01529
01530 QVector<KTextEditor::Range> KateDocument::searchText(
01531 const KTextEditor::Range & range,
01532 const QString & pattern,
01533 const KTextEditor::Search::SearchOptions options)
01534 {
01535
01536
01537
01538
01539 const bool escapeSequences = options.testFlag(KTextEditor::Search::EscapeSequences);
01540 const bool regexMode = options.testFlag(KTextEditor::Search::Regex);
01541 const bool caseSensitive = !options.testFlag(KTextEditor::Search::CaseInsensitive);
01542 const bool backwards = options.testFlag(KTextEditor::Search::Backwards);
01543 const bool wholeWords = options.testFlag(KTextEditor::Search::WholeWords);
01544
01545 if (regexMode)
01546 {
01547
01548
01549 KateRegExpSearch searcher(this, caseSensitive);
01550 return searcher.search(range, pattern, backwards);
01551 }
01552
01553 if (escapeSequences)
01554 {
01555
01556 KateEscapedTextSearch searcher(this, caseSensitive, wholeWords);
01557 return searcher.search(range, pattern, backwards);
01558 }
01559
01560
01561 KatePlainTextSearch searcher(this, caseSensitive, wholeWords);
01562 return searcher.search(range, pattern, backwards);
01563 }
01564
01565
01566
01567 KTextEditor::Search::SearchOptions KateDocument::supportedSearchOptions() const
01568 {
01569 KTextEditor::Search::SearchOptions supported(KTextEditor::Search::Default);
01570 supported |= KTextEditor::Search::Regex;
01571 supported |= KTextEditor::Search::CaseInsensitive;
01572 supported |= KTextEditor::Search::Backwards;
01573
01574 supported |= KTextEditor::Search::EscapeSequences;
01575 supported |= KTextEditor::Search::WholeWords;
01576
01577 return supported;
01578 }
01579
01580
01581 QWidget * KateDocument::dialogParent()
01582 {
01583 QWidget *w=widget();
01584
01585 if(!w)
01586 {
01587 w=activeView();
01588
01589 if(!w)
01590 w=QApplication::activeWindow();
01591 }
01592
01593 return w;
01594 }
01595
01596
01597 bool KateDocument::setMode (const QString &name)
01598 {
01599 updateFileType (name);
01600 return true;
01601 }
01602
01603 QString KateDocument::mode () const
01604 {
01605 return m_fileType;
01606 }
01607
01608 QStringList KateDocument::modes () const
01609 {
01610 QStringList m;
01611
01612 const QList<KateFileType *> &modeList = KateGlobal::self()->modeManager()->list();
01613 for (int i = 0; i < modeList.size(); ++i)
01614 m << modeList[i]->name;
01615
01616 return m;
01617 }
01618
01619 bool KateDocument::setHighlightingMode (const QString &name)
01620 {
01621 m_buffer->setHighlight (KateHlManager::self()->nameFind(name));
01622 return true;
01623 }
01624
01625 QString KateDocument::highlightingMode () const
01626 {
01627 return highlight()->name ();
01628 }
01629
01630 QStringList KateDocument::highlightingModes () const
01631 {
01632 QStringList hls;
01633
01634 for (int i = 0; i < KateHlManager::self()->highlights(); ++i)
01635 hls << KateHlManager::self()->hlName (i);
01636
01637 return hls;
01638 }
01639
01640 QString KateDocument::highlightingModeSection( int index ) const
01641 {
01642 return KateHlManager::self()->hlSection( index );
01643 }
01644
01645 QString KateDocument::modeSection( int index ) const
01646 {
01647 return KateGlobal::self()->modeManager()->list()[ index ]->section;
01648 }
01649
01650 void KateDocument::bufferHlChanged ()
01651 {
01652
01653 makeAttribs(false);
01654
01655
01656 m_indenter->checkRequiredStyle();
01657
01658 emit highlightingModeChanged(this);
01659 }
01660
01661
01662 void KateDocument::setDontChangeHlOnSave()
01663 {
01664 hlSetByUser = true;
01665 }
01666
01667 void KateDocument::bomSetByUser()
01668 {
01669 m_bomSetByUser=true;
01670 }
01671
01672
01673
01674 void KateDocument::readSessionConfig(const KConfigGroup &kconfig)
01675 {
01676 readParameterizedSessionConfig(kconfig, SkipNone);
01677 }
01678
01679 void KateDocument::readParameterizedSessionConfig(const KConfigGroup &kconfig,
01680 unsigned long configParameters)
01681 {
01682 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipEncoding)) {
01683
01684 QString tmpenc=kconfig.readEntry("Encoding");
01685 if (!tmpenc.isEmpty() && (tmpenc != encoding()))
01686 setEncoding(tmpenc);
01687 }
01688
01689 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipUrl)) {
01690
01691 KUrl url (kconfig.readEntry("URL"));
01692
01693
01694 if (!url.isEmpty() && url.isValid())
01695 openUrl (url);
01696 else completed();
01697 }
01698 else {
01699 completed();
01700 }
01701
01702 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipMode)) {
01703
01704 updateFileType (kconfig.readEntry("Mode", "Normal"));
01705 }
01706
01707 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipHighlighting)) {
01708
01709 m_buffer->setHighlight(KateHlManager::self()->nameFind(kconfig.readEntry("Highlighting")));
01710 }
01711
01712
01713
01714 setReadWrite(kconfig.readEntry("ReadWrite", true));
01715
01716
01717 config()->setIndentationMode( kconfig.readEntry("Indentation Mode", config()->indentationMode() ) );
01718
01719
01720 const QList<int> marks = kconfig.readEntry("Bookmarks", QList<int>());
01721 for( int i = 0; i < marks.count(); i++ )
01722 addMark( marks[i], KateDocument::markType01 );
01723 }
01724
01725 void KateDocument::writeSessionConfig(KConfigGroup &kconfig)
01726 {
01727 writeParameterizedSessionConfig(kconfig, SkipNone);
01728 }
01729
01730 void KateDocument::writeParameterizedSessionConfig(KConfigGroup &kconfig,
01731 unsigned long configParameters)
01732 {
01733 if ( this->url().isLocalFile() ) {
01734 const QString path = this->url().toLocalFile();
01735 if ( KGlobal::dirs()->relativeLocation( "tmp", path ) != path ) {
01736 return;
01737 }
01738 }
01739
01740 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipUrl)) {
01741
01742 kconfig.writeEntry("URL", this->url().prettyUrl() );
01743 }
01744
01745 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipEncoding)) {
01746
01747 kconfig.writeEntry("Encoding",encoding());
01748 }
01749
01750 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipMode)) {
01751
01752 kconfig.writeEntry("Mode", m_fileType);
01753 }
01754
01755 if(!(configParameters & KTextEditor::ParameterizedSessionConfigInterface::SkipHighlighting)) {
01756
01757 kconfig.writeEntry("Highlighting", highlight()->name());
01758 }
01759
01760
01761 kconfig.writeEntry("ReadWrite", isReadWrite());
01762
01763
01764 kconfig.writeEntry("Indentation Mode", config()->indentationMode() );
01765
01766
01767 QList<int> marks;
01768 for (QHash<int, KTextEditor::Mark*>::const_iterator i = m_marks.constBegin(); i != m_marks.constEnd(); ++i)
01769 if (i.value()->type & KTextEditor::MarkInterface::markType01)
01770 marks << i.value()->line;
01771
01772 kconfig.writeEntry( "Bookmarks", marks );
01773 }
01774
01775
01776
01777 uint KateDocument::mark( int line )
01778 {
01779 if( !m_marks.value(line) )
01780 return 0;
01781
01782 return m_marks[line]->type;
01783 }
01784
01785 void KateDocument::setMark( int line, uint markType )
01786 {
01787 clearMark( line );
01788 addMark( line, markType );
01789 }
01790
01791 void KateDocument::clearMark( int line )
01792 {
01793 if( line > lastLine() )
01794 return;
01795
01796 if( !m_marks.value(line) )
01797 return;
01798
01799 KTextEditor::Mark* mark = m_marks.take( line );
01800 emit markChanged( this, *mark, MarkRemoved );
01801 emit marksChanged( this );
01802 delete mark;
01803 tagLines( line, line );
01804 repaintViews(true);
01805 }
01806
01807 void KateDocument::addMark( int line, uint markType )
01808 {
01809 if( line > lastLine())
01810 return;
01811
01812 if( markType == 0 )
01813 return;
01814
01815 if( m_marks.value(line) ) {
01816 KTextEditor::Mark* mark = m_marks[line];
01817
01818
01819 markType &= ~mark->type;
01820
01821 if( markType == 0 )
01822 return;
01823
01824
01825 mark->type |= markType;
01826 } else {
01827 KTextEditor::Mark *mark = new KTextEditor::Mark;
01828 mark->line = line;
01829 mark->type = markType;
01830 m_marks.insert( line, mark );
01831 }
01832
01833
01834 KTextEditor::Mark temp;
01835 temp.line = line;
01836 temp.type = markType;
01837 emit markChanged( this, temp, MarkAdded );
01838
01839 emit marksChanged( this );
01840 tagLines( line, line );
01841 repaintViews(true);
01842 }
01843
01844 void KateDocument::removeMark( int line, uint markType )
01845 {
01846 if( line > lastLine() )
01847 return;
01848
01849 if( !m_marks.value(line) )
01850 return;
01851
01852 KTextEditor::Mark* mark = m_marks[line];
01853
01854
01855 markType &= mark->type;
01856
01857 if( markType == 0 )
01858 return;
01859
01860
01861 mark->type &= ~markType;
01862
01863
01864 KTextEditor::Mark temp;
01865 temp.line = line;
01866 temp.type = markType;
01867 emit markChanged( this, temp, MarkRemoved );
01868
01869 if( mark->type == 0 )
01870 m_marks.remove( line );
01871
01872 emit marksChanged( this );
01873 tagLines( line, line );
01874 repaintViews(true);
01875 }
01876
01877 const QHash<int, KTextEditor::Mark*> &KateDocument::marks()
01878 {
01879 return m_marks;
01880 }
01881
01882 void KateDocument::requestMarkTooltip( int line, QPoint position )
01883 {
01884 if(!mark(line))
01885 return;
01886
01887 bool handled = false;
01888 emit markToolTipRequested( this, *marks()[line], position, handled );
01889 }
01890
01891 bool KateDocument::handleMarkClick( int line )
01892 {
01893 bool handled = false;
01894
01895 if(!mark(line))
01896 return false;
01897
01898 emit markClicked( this, *marks()[line], handled );
01899
01900 return handled;
01901 }
01902
01903 bool KateDocument::handleMarkContextMenu( int line, QPoint position )
01904 {
01905 bool handled = false;
01906
01907 if(!mark(line))
01908 return false;
01909
01910 emit markContextMenuRequested( this, *marks()[line], position, handled );
01911
01912 return handled;
01913 }
01914
01915 void KateDocument::clearMarks()
01916 {
01917 while (!m_marks.isEmpty())
01918 {
01919 QHash<int, KTextEditor::Mark*>::iterator it = m_marks.begin();
01920 KTextEditor::Mark mark = *it.value();
01921 delete it.value();
01922 m_marks.erase (it);
01923
01924 emit markChanged( this, mark, MarkRemoved );
01925 tagLines( mark.line, mark.line );
01926 }
01927
01928 m_marks.clear();
01929
01930 emit marksChanged( this );
01931 repaintViews(true);
01932 }
01933
01934 void KateDocument::setMarkPixmap( MarkInterface::MarkTypes type, const QPixmap& pixmap )
01935 {
01936 m_markPixmaps.insert( type, pixmap );
01937 }
01938
01939 void KateDocument::setMarkDescription( MarkInterface::MarkTypes type, const QString& description )
01940 {
01941 m_markDescriptions.insert( type, description );
01942 }
01943
01944 QPixmap KateDocument::markPixmap( MarkInterface::MarkTypes type ) const
01945 {
01946 return m_markPixmaps.contains(type) ?
01947 m_markPixmaps[type] : QPixmap();
01948 }
01949
01950 QColor KateDocument::markColor( MarkInterface::MarkTypes type ) const
01951 {
01952 uint reserved = (0x1 << KTextEditor::MarkInterface::reservedMarkersCount()) - 1;
01953 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
01954 return KateRendererConfig::global()->lineMarkerColor(type);
01955 } else {
01956 return QColor();
01957 }
01958 }
01959
01960 QString KateDocument::markDescription( MarkInterface::MarkTypes type ) const
01961 {
01962 return m_markDescriptions.contains(type) ?
01963 m_markDescriptions[type] : QString();
01964 }
01965
01966 void KateDocument::setEditableMarks( uint markMask )
01967 {
01968 m_editableMarks = markMask;
01969 }
01970
01971 uint KateDocument::editableMarks() const
01972 {
01973 return m_editableMarks;
01974 }
01975
01976
01977
01978 bool KateDocument::printDialog ()
01979 {
01980 return KatePrinter::print (this);
01981 }
01982
01983 bool KateDocument::print ()
01984 {
01985 return KatePrinter::print (this);
01986 }
01987
01988
01989
01990 QString KateDocument::mimeType()
01991 {
01992 KMimeType::Ptr result = KMimeType::defaultMimeTypePtr();
01993
01994
01995 if ( ! this->url().isEmpty() )
01996 result = KMimeType::findByUrl( this->url() );
01997
01998 else if ( this->url().isEmpty() || ! this->url().isLocalFile() )
01999 result = mimeTypeForContent();
02000
02001 return result->name();
02002 }
02003
02004 KMimeType::Ptr KateDocument::mimeTypeForContent()
02005 {
02006 QByteArray buf (1024,'\0');
02007 uint bufpos = 0;
02008
02009 for (int i=0; i < lines(); ++i)
02010 {
02011 QString line = this->line( i );
02012 uint len = line.length() + 1;
02013
02014 if (bufpos + len > 1024)
02015 len = 1024 - bufpos;
02016
02017 QString ld (line + QChar::fromAscii('\n'));
02018 buf.replace(bufpos,len,ld.toLatin1());
02019
02020 bufpos += len;
02021
02022 if (bufpos >= 1024)
02023 break;
02024 }
02025 buf.resize( bufpos );
02026
02027 int accuracy = 0;
02028 KMimeType::Ptr mt = KMimeType::findByContent(buf, &accuracy);
02029 return mt ? mt : KMimeType::defaultMimeTypePtr();
02030 }
02031
02032
02033
02034
02035 bool KateDocument::openFile()
02036 {
02037
02038 setOpeningError(false);
02039
02040
02041 activateDirWatch ();
02042
02043
02044
02045
02046 QString mimeType = arguments().mimeType();
02047 int pos = mimeType.indexOf(';');
02048 if (pos != -1)
02049 setEncoding (mimeType.mid(pos+1));
02050
02051
02052 history()->doEdit( new KateEditInfo(Kate::CloseFileEdit, documentRange(), QStringList(), KTextEditor::Range(0,0,0,0), QStringList()) );
02053 emit KTextEditor::Document::textRemoved(this, documentRange());
02054
02055 bool success = m_buffer->openFile (localFilePath());
02056
02057 history()->doEdit( new KateEditInfo(Kate::OpenFileEdit, KTextEditor::Range(0,0,0,0), QStringList(), documentRange(), QStringList()) );
02058 emit KTextEditor::Document::textInserted(this, documentRange());
02059
02060
02061
02062
02063 if (success)
02064 {
02065
02066 updateFileType (KateGlobal::self()->modeManager()->fileType (this));
02067
02068
02069 readDirConfig ();
02070
02071
02072 readVariables();
02073
02074
02075 createDigest( m_digest );
02076
02077 if (!m_postLoadFilterChecks.isEmpty())
02078 {
02079 LoadSaveFilterCheckPlugins *lscps=loadSaveFilterCheckPlugins();
02080 foreach(const QString& checkplugin, m_postLoadFilterChecks)
02081 {
02082 lscps->postLoadFilter(checkplugin,this);
02083 }
02084 }
02085 }
02086
02087
02088 emit textChanged (this);
02089
02090
02091
02092
02093 foreach (KateView * view, m_views)
02094 {
02095
02096 view->setCursorPosition(KTextEditor::Cursor());
02097 view->updateView(true);
02098 }
02099
02100 if (!m_reloading)
02101 {
02102
02103
02104
02105 emit documentUrlChanged (this);
02106
02107
02108
02109
02110 setDocName (QString());
02111 }
02112
02113
02114
02115 if (m_modOnHd)
02116 {
02117 m_modOnHd = false;
02118 m_modOnHdReason = OnDiskUnmodified;
02119 emit modifiedOnDisk (this, m_modOnHd, m_modOnHdReason);
02120 }
02121
02122
02123
02124
02125 QWidget *parentWidget(dialogParent());
02126
02127 if (!suppressOpeningErrorDialogs())
02128 {
02129 if (!success)
02130 KMessageBox::error (parentWidget, i18n ("The file %1 could not be loaded, as it was not possible to read from it.\n\nCheck if you have read access to this file.", this->url().pathOrUrl()));
02131 }
02132
02133 if (!success) {
02134 setOpeningError(true);
02135 setOpeningErrorMessage(i18n ("The file %1 could not be loaded, as it was not possible to read from it.\n\nCheck if you have read access to this file.",this->url().pathOrUrl()));
02136 }
02137
02138
02139 if (m_buffer->binary())
02140 {
02141
02142 setReadWrite( false );
02143
02144 if(!suppressOpeningErrorDialogs())
02145 KMessageBox::information (parentWidget
02146 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.", this->url().pathOrUrl())
02147 , i18n ("Binary File Opened")
02148 , "Binary File Opened Warning");
02149
02150 setOpeningError(true);
02151 setOpeningErrorMessage(i18n ("The file %1 is a binary, saving it will result in a corrupt file.", this->url().pathOrUrl()));
02152 }
02153
02154
02155
02156 else if (m_buffer->brokenUTF8())
02157 {
02158
02159 setReadWrite( false );
02160
02161 if (!suppressOpeningErrorDialogs())
02162 KMessageBox::information (parentWidget
02163 , i18n ("The file %1 was opened with UTF-8 encoding but contained invalid characters."
02164 " It is set to read-only mode, as saving might destroy its content."
02165 " Either reopen the file with the correct encoding chosen or enable the read-write mode again in the menu to be able to edit it.", this->url().pathOrUrl())
02166 , i18n ("Broken UTF-8 File Opened")
02167 , "Broken UTF-8 File Opened Warning");
02168 setOpeningError(true);
02169 setOpeningErrorMessage(i18n ("The file %1 was opened with UTF-8 encoding but contained invalid characters."
02170 " It is set to read-only mode, as saving might destroy its content."
02171 " Either reopen the file with the correct encoding chosen or enable the read-write mode again in the menu to be able to edit it.", this->url().pathOrUrl()));
02172 }
02173
02174
02175
02176
02177 return success;
02178 }
02179
02180 bool KateDocument::saveFile()
02181 {
02182 QWidget *parentWidget(dialogParent());
02183
02184
02185
02186
02187 if (m_buffer->binary() && (KMessageBox::warningContinueCancel (parentWidget
02188 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.", url().pathOrUrl())
02189 , i18n ("Trying to Save Binary File")
02190 , KGuiItem(i18n("Save Nevertheless"))
02191 , KStandardGuiItem::cancel(), "Binary File Save Warning") != KMessageBox::Continue))
02192 return false;
02193
02194
02195 if ( !url().isEmpty() )
02196 {
02197 if (s_fileChangedDialogsActivated && m_modOnHd)
02198 {
02199 QString str = reasonedMOHString() + "\n\n";
02200
02201 if (!isModified())
02202 {
02203 if (KMessageBox::warningContinueCancel(parentWidget,
02204 str + i18n("Do you really want to save this unmodified file? You could overwrite changed data in the file on disk."),i18n("Trying to Save Unmodified File"),KGuiItem(i18n("Save Nevertheless"))) != KMessageBox::Continue)
02205 return false;
02206 }
02207 else
02208 {
02209 if (KMessageBox::warningContinueCancel(parentWidget,
02210 str + i18n("Do you really want to save this file? Both your open file and the file on disk were changed. There could be some data lost."),i18n("Possible Data Loss"),KGuiItem(i18n("Save Nevertheless"))) != KMessageBox::Continue)
02211 return false;
02212 }
02213 }
02214 }
02215
02216
02217
02218
02219 if (!m_buffer->canEncode ()
02220 && (KMessageBox::warningContinueCancel(parentWidget,
02221 i18n("The selected encoding cannot encode every unicode character in this document. Do you really want to save it? There could be some data lost."),i18n("Possible Data Loss"),KGuiItem(i18n("Save Nevertheless"))) != KMessageBox::Continue))
02222 {
02223 return false;
02224 }
02225
02226
02227
02228
02229
02230
02231 bool l ( url().isLocalFile() );
02232
02233
02234 if ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles )
02235 || ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
02236 {
02237 KUrl u( url() );
02238 u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
02239
02240 kDebug( 13020 ) << "backup src file name: " << url();
02241 kDebug( 13020 ) << "backup dst file name: " << u;
02242
02243
02244 bool backupSuccess = false;
02245
02246
02247 if (u.isLocalFile ())
02248 {
02249 if (QFile::exists (url().toLocalFile ()))
02250 {
02251
02252 QFile backupFile (u.toLocalFile ());
02253 if (backupFile.exists()) backupFile.remove ();
02254
02255 backupSuccess = QFile::copy (url().toLocalFile (), u.toLocalFile ());
02256 }
02257 else
02258 backupSuccess = true;
02259 }
02260 else
02261 {
02262 QWidget *w = widget ();
02263 if (!w && !m_views.isEmpty ())
02264 w = m_views.first();
02265
02266
02267 mode_t perms = 0600;
02268 KIO::UDSEntry fentry;
02269 if (KIO::NetAccess::stat (url(), fentry, kapp->activeWindow()))
02270 {
02271 kDebug( 13020 ) << "stating succesfull: " << url();
02272 KFileItem item (fentry, url());
02273 perms = item.permissions();
02274
02275
02276 KIO::FileCopyJob *job = KIO::file_copy ( url(), u, -1, KIO::Overwrite );
02277 backupSuccess = KIO::NetAccess::synchronousRun(job, w);
02278 }
02279 else
02280 backupSuccess = true;
02281 }
02282
02283
02284 if (!backupSuccess && (KMessageBox::warningContinueCancel (parentWidget
02285 , i18n ("For file %1 no backup copy could be created before saving."
02286 " If an error occurs while saving, you might lose the data of this file."
02287 " A reason could be that the media you write to is full or the directory of the file is read-only for you.", url().pathOrUrl())
02288 , i18n ("Failed to create backup copy.")
02289 , KGuiItem(i18n("Try to Save Nevertheless"))
02290 , KStandardGuiItem::cancel(), "Backup Failed Warning") != KMessageBox::Continue))
02291 {
02292 return false;
02293 }
02294 }
02295
02296
02297 updateFileType (KateGlobal::self()->modeManager()->fileType (this));
02298
02299 if (!m_preSavePostDialogFilterChecks.isEmpty())
02300 {
02301 LoadSaveFilterCheckPlugins *lscps=loadSaveFilterCheckPlugins();
02302 foreach(const QString& checkplugin, m_preSavePostDialogFilterChecks)
02303 {
02304 if (lscps->preSavePostDialogFilterCheck(checkplugin,this,parentWidget)==false)
02305 return false;
02306 }
02307 }
02308
02309
02310 QString oldPath = m_dirWatchFile;
02311
02312
02313 deactivateDirWatch ();
02314
02315
02316
02317
02318 if (!m_buffer->saveFile (localFilePath()))
02319 {
02320
02321 activateDirWatch (oldPath);
02322
02323 KMessageBox::error (parentWidget, i18n ("The document could not be saved, as it was not possible to write to %1.\n\nCheck that you have write access to this file or that enough disk space is available.", this->url().pathOrUrl()));
02324
02325 return false;
02326 }
02327
02328
02329 createDigest( m_digest );
02330
02331
02332 activateDirWatch ();
02333
02334
02335
02336
02337
02338 if ( url().isLocalFile())
02339 {
02340 QFileInfo fo (oldPath), fn (m_dirWatchFile);
02341
02342 if (fo.path() != fn.path())
02343 readDirConfig();
02344 }
02345
02346
02347 readVariables();
02348
02349
02350
02351
02352 if (m_modOnHd)
02353 {
02354 m_modOnHd = false;
02355 m_modOnHdReason = OnDiskUnmodified;
02356 emit modifiedOnDisk (this, m_modOnHd, m_modOnHdReason);
02357 }
02358
02359
02360 setDocName( QString() );
02361
02362
02363 emit documentUrlChanged (this);
02364
02365 m_savingToUrl=true;
02366
02367
02368
02369 setUndoDontMerge(true);
02370
02371
02372
02373
02374 return true;
02375 }
02376
02377 void KateDocument::readDirConfig ()
02378 {
02379 int depth = config()->searchDirConfigDepth ();
02380
02381 if (this->url().isLocalFile() && (depth > -1))
02382 {
02383 QString currentDir = QFileInfo (localFilePath()).absolutePath();
02384
02385
02386 while (depth > -1)
02387 {
02388
02389
02390
02391 QFile f (currentDir + "/.kateconfig");
02392
02393 if (f.open (QIODevice::ReadOnly))
02394 {
02395 QTextStream stream (&f);
02396
02397 uint linesRead = 0;
02398 QString line = stream.readLine();
02399 while ((linesRead < 32) && !line.isNull())
02400 {
02401 readVariableLine( line );
02402
02403 line = stream.readLine();
02404
02405 linesRead++;
02406 }
02407
02408 break;
02409 }
02410
02411 QString newDir = QFileInfo (currentDir).absolutePath();
02412
02413
02414 if (currentDir == newDir)
02415 break;
02416
02417 currentDir = newDir;
02418 --depth;
02419 }
02420 }
02421 }
02422
02423 void KateDocument::activateDirWatch (const QString &useFileName)
02424 {
02425 QString fileToUse = useFileName;
02426 if (fileToUse.isEmpty())
02427 fileToUse = localFilePath();
02428
02429
02430 if (fileToUse == m_dirWatchFile)
02431 return;
02432
02433
02434 deactivateDirWatch ();
02435
02436
02437 if (url().isLocalFile() && !fileToUse.isEmpty())
02438 {
02439 KateGlobal::self()->dirWatch ()->addFile (fileToUse);
02440 m_dirWatchFile = fileToUse;
02441 }
02442 }
02443
02444 void KateDocument::deactivateDirWatch ()
02445 {
02446 if (!m_dirWatchFile.isEmpty())
02447 KateGlobal::self()->dirWatch ()->removeFile (m_dirWatchFile);
02448
02449 m_dirWatchFile.clear();
02450 }
02451
02452 bool KateDocument::closeUrl()
02453 {
02454
02455
02456
02457 if ( !m_reloading && !url().isEmpty() )
02458 {
02459 if (s_fileChangedDialogsActivated && m_modOnHd)
02460 {
02461 QWidget *parentWidget(dialogParent());
02462
02463 if (!(KMessageBox::warningContinueCancel(
02464 parentWidget,
02465 reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur."),
02466 i18n("Possible Data Loss"), KGuiItem(i18n("Close Nevertheless")), KStandardGuiItem::cancel(),
02467 QString("kate_close_modonhd_%1").arg( m_modOnHdReason ) ) == KMessageBox::Continue))
02468 return false;
02469 }
02470 }
02471
02472
02473
02474
02475 if (!KParts::ReadWritePart::closeUrl ())
02476 return false;
02477
02478
02479 if (!m_reloading)
02480 emit aboutToClose(this);
02481
02482
02483 deactivateDirWatch ();
02484
02485
02486
02487
02488 setUrl(KUrl());
02489 setLocalFilePath(QString());
02490
02491
02492 if (m_modOnHd)
02493 {
02494 m_modOnHd = false;
02495 m_modOnHdReason = OnDiskUnmodified;
02496 emit modifiedOnDisk (this, m_modOnHd, m_modOnHdReason);
02497 }
02498
02499 emit KTextEditor::Document::textRemoved(this, documentRange());
02500
02501 {
02502 QMutexLocker l(smartMutex());
02503 history()->doEdit( new KateEditInfo(Kate::CloseFileEdit, documentRange(), QStringList(), KTextEditor::Range(0,0,0,0), QStringList()) );
02504
02505
02506 m_buffer->clear();
02507
02508
02509 clearMarks ();
02510
02511
02512 m_undoManager->clearUndo();
02513 m_undoManager->clearRedo();
02514 }
02515
02516
02517 setModified(false);
02518
02519
02520 m_buffer->setHighlight(0);
02521
02522
02523 foreach (KateView * view, m_views )
02524 {
02525 view->clearSelection();
02526 view->clear();
02527 }
02528
02529 if (!m_reloading)
02530 {
02531
02532
02533 emit documentUrlChanged (this);
02534
02535
02536 setDocName (QString());
02537 }
02538
02539 return true;
02540 }
02541
02542 void KateDocument::setReadWrite( bool rw )
02543 {
02544 if (isReadWrite() != rw)
02545 {
02546 KParts::ReadWritePart::setReadWrite (rw);
02547
02548 foreach( KateView* view, m_views)
02549 {
02550 view->slotUpdateUndo();
02551 view->slotReadWriteChanged ();
02552 }
02553 }
02554 }
02555
02556 void KateDocument::setModified(bool m) {
02557
02558 if (isModified() != m) {
02559 KParts::ReadWritePart::setModified (m);
02560
02561 foreach( KateView* view,m_views)
02562 {
02563 view->slotUpdateUndo();
02564 }
02565
02566 emit modifiedChanged (this);
02567 }
02568
02569 m_undoManager->setModified (m);
02570 }
02571
02572
02573
02574
02575 void KateDocument::makeAttribs(bool needInvalidate)
02576 {
02577 foreach(KateView *view,m_views)
02578 view->renderer()->updateAttributes ();
02579
02580 if (needInvalidate)
02581 m_buffer->invalidateHighlighting();
02582
02583 foreach(KateView *view,m_views)
02584 {
02585 view->tagAll();
02586 view->updateView (true);
02587 }
02588 }
02589
02590
02591 void KateDocument::internalHlChanged()
02592 {
02593 makeAttribs();
02594 }
02595
02596 void KateDocument::addView(KTextEditor::View *view) {
02597 if (!view)
02598 return;
02599
02600 m_views.append( static_cast<KateView*>(view) );
02601 m_textEditViews.append( view );
02602
02603 foreach(KTextEditor::SmartRange* highlight, m_documentHighlights) {
02604 Q_ASSERT(dynamic_cast<KateView*>(view));
02605 static_cast<KateView*>(view)->addExternalHighlight(highlight, m_documentDynamicHighlights.contains(highlight));
02606 }
02607
02608
02609 if (!m_fileType.isEmpty())
02610 readVariableLine(KateGlobal::self()->modeManager()->fileType(m_fileType).varLine, true);
02611
02612
02613 readVariables (true);
02614
02615 setActiveView(view);
02616 }
02617
02618 void KateDocument::removeView(KTextEditor::View *view) {
02619 if (!view)
02620 return;
02621
02622 if (activeView() == view)
02623 setActiveView(0L);
02624
02625 m_views.removeAll( (KateView *) view );
02626 m_textEditViews.removeAll( view );
02627 }
02628
02629 void KateDocument::setActiveView(KTextEditor::View* view)
02630 {
02631 if ( m_activeView == view ) return;
02632
02633 if (m_activeView) {
02634 disconnect(m_activeView, SIGNAL(selectionChanged(KTextEditor::View*)), this, SIGNAL(activeViewSelectionChanged(KTextEditor::View*)));
02635 }
02636
02637 m_activeView = (KateView*)view;
02638
02639 if (m_activeView) {
02640 connect(m_activeView, SIGNAL(selectionChanged(KTextEditor::View*)), SIGNAL(activeViewSelectionChanged(KTextEditor::View*)));
02641 }
02642 }
02643
02644 bool KateDocument::ownedView(KateView *view) {
02645
02646 return (m_views.contains(view));
02647 }
02648
02649 uint KateDocument::toVirtualColumn( const KTextEditor::Cursor& cursor )
02650 {
02651 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
02652
02653 if (textLine)
02654 return textLine->toVirtualColumn(cursor.column(), config()->tabWidth());
02655 else
02656 return 0;
02657 }
02658
02659 bool KateDocument::typeChars ( KateView *view, const QString &chars )
02660 {
02661
02662 QMutexLocker l(smartMutex());
02663
02664 KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorPosition().line ());
02665
02666 if (!textLine)
02667 return false;
02668
02669 bool bracketInserted = false;
02670 QString buf;
02671 QChar c;
02672 for( int z = 0; z < chars.length(); z++ )
02673 {
02674 QChar ch = c = chars[z];
02675
02676 if (ch.isPrint() || ch == QChar::fromAscii('\t'))
02677 {
02678 buf.append (ch);
02679
02680 if (!bracketInserted && (config()->configFlags() & KateDocumentConfig::cfAutoBrackets))
02681 {
02682 QChar end_ch;
02683 bool complete = true;
02684 QChar prevChar = textLine->at(view->cursorPosition().column()-1);
02685 QChar nextChar = textLine->at(view->cursorPosition().column());
02686 switch(ch.toAscii()) {
02687 case '(': end_ch = ')'; break;
02688 case '[': end_ch = ']'; break;
02689 case '{': end_ch = '}'; break;
02690 case '\'':end_ch = '\'';break;
02691 case '"': end_ch = '"'; break;
02692 default: complete = false;
02693 }
02694 if (complete)
02695 {
02696 if (view->selection())
02697 {
02698 buf.append (view->selectionText());
02699 buf.append (end_ch);
02700 bracketInserted = true;
02701 }
02702 else
02703 {
02704 if ( ( (ch == '\'' || ch == '"') &&
02705 (prevChar.isLetterOrNumber() || prevChar == ch) )
02706 || nextChar.isLetterOrNumber()
02707 || (nextChar == end_ch && prevChar != ch) )
02708 {
02709 kDebug(13020) << "AutoBracket refused before: " << nextChar << "\n";
02710 }
02711 else
02712 {
02713 buf.append (end_ch);
02714 bracketInserted = true;
02715 }
02716 }
02717 }
02718 }
02719 }
02720 }
02721
02722 if (buf.isEmpty())
02723 return false;
02724
02725 l.unlock();
02726
02727 editStart ();
02728
02729 if (!view->config()->persistentSelection() && view->selection() )
02730 view->removeSelectedText();
02731
02732 KTextEditor::Cursor oldCur (view->cursorPosition());
02733
02734 if (config()->configFlags() & KateDocumentConfig::cfOvr
02735 || (view->viInputMode() && view->getViInputModeManager()->getCurrentViMode() == ReplaceMode)) {
02736
02737 KTextEditor::Range r = KTextEditor::Range(view->cursorPosition(), qMin(buf.length(),
02738 textLine->length() - view->cursorPosition().column()));
02739
02740
02741 if (view->viInputMode() && view->getViInputModeManager()->getCurrentViMode() == ReplaceMode) {
02742 QChar removed = line( view->cursorPosition().line() ).at( r.start().column() );
02743 view->getViInputModeManager()->getViReplaceMode()->overwrittenChar( removed );
02744 }
02745
02746 removeText(r);
02747 }
02748
02749 insertText(view->cursorPosition(), buf);
02750 if (bracketInserted)
02751 view->setCursorPositionInternal (view->cursorPosition() - KTextEditor::Cursor(0,1));
02752
02753 KTextEditor::Cursor b(view->cursorPosition());
02754 m_indenter->userTypedChar (view, b, c);
02755
02756 editEnd ();
02757
02758 view->slotTextInserted (view, oldCur, chars);
02759 return true;
02760 }
02761
02762 void KateDocument::newLine( KateView *v )
02763 {
02764 editStart();
02765
02766 if( !v->config()->persistentSelection() && v->selection() )
02767 v->removeSelectedText();
02768
02769
02770 KTextEditor::Cursor c = v->cursorPosition();
02771
02772 if (c.line() > (int)lastLine())
02773 c.setLine(lastLine());
02774
02775 if (c.line() < 0)
02776 c.setLine(0);
02777
02778 uint ln = c.line();
02779
02780 KateTextLine::Ptr textLine = plainKateTextLine(ln);
02781
02782 if (c.column() > (int)textLine->length())
02783 c.setColumn(textLine->length());
02784
02785
02786 editWrapLine (c.line(), c.column());
02787
02788
02789 m_indenter->userTypedChar(v, v->cursorPosition(), '\n');
02790
02791 removeTrailingSpace( ln );
02792
02793 editEnd();
02794 }
02795
02796 void KateDocument::transpose( const KTextEditor::Cursor& cursor)
02797 {
02798 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
02799
02800 if (!textLine || (textLine->length() < 2))
02801 return;
02802
02803 uint col = cursor.column();
02804
02805 if (col > 0)
02806 col--;
02807
02808 if ((textLine->length() - col) < 2)
02809 return;
02810
02811 uint line = cursor.line();
02812 QString s;
02813
02814
02815
02816 s.append (textLine->at(col+1));
02817 s.append (textLine->at(col));
02818
02819
02820
02821 editStart ();
02822 editRemoveText (line, col, 2);
02823 editInsertText (line, col, s);
02824 editEnd ();
02825 }
02826
02827 void KateDocument::backspace( KateView *view, const KTextEditor::Cursor& c )
02828 {
02829 if ( !view->config()->persistentSelection() && view->selection() ) {
02830 view->removeSelectedText();
02831 return;
02832 }
02833
02834 uint col = qMax( c.column(), 0 );
02835 uint line = qMax( c.line(), 0 );
02836
02837 if ((col == 0) && (line == 0))
02838 return;
02839
02840 int complement = 0;
02841 if (col > 0)
02842 {
02843 if (config()->configFlags() & KateDocumentConfig::cfAutoBrackets)
02844 {
02845
02846 KateTextLine::Ptr tl = m_buffer->plainLine(line);
02847 if(!tl) return;
02848 QChar prevChar = tl->at(col-1);
02849 QChar nextChar = tl->at(col);
02850
02851 if ( (prevChar == '"' && nextChar == '"') ||
02852 (prevChar == '\'' && nextChar == '\'') ||
02853 (prevChar == '(' && nextChar == ')') ||
02854 (prevChar == '[' && nextChar == ']') ||
02855 (prevChar == '{' && nextChar == '}') )
02856 {
02857 complement = 1;
02858 }
02859 }
02860 if (!(config()->configFlags() & KateDocumentConfig::cfBackspaceIndents))
02861 {
02862
02863
02864 removeText(KTextEditor::Range(line, col-1, line, col+complement));
02865 }
02866 else
02867 {
02868
02869 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
02870
02871
02872 if (!textLine)
02873 return;
02874
02875 int colX = textLine->toVirtualColumn(col, config()->tabWidth());
02876 int pos = textLine->firstChar();
02877 if (pos > 0)
02878 pos = textLine->toVirtualColumn(pos, config()->tabWidth());
02879
02880 if (pos < 0 || pos >= (int)colX)
02881 {
02882
02883 indent( view, line, -1);
02884 }
02885 else
02886 removeText(KTextEditor::Range(line, col-1, line, col+complement));
02887 }
02888 }
02889 else
02890 {
02891
02892 if (line >= 1)
02893 {
02894 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
02895
02896
02897 if (!textLine)
02898 return;
02899
02900 if (config()->wordWrap() && textLine->endsWith(QLatin1String(" ")))
02901 {
02902
02903 removeText (KTextEditor::Range(line-1, textLine->length()-1, line, 0));
02904 }
02905 else
02906 removeText (KTextEditor::Range(line-1, textLine->length(), line, 0));
02907 }
02908 }
02909 }
02910
02911 void KateDocument::del( KateView *view, const KTextEditor::Cursor& c )
02912 {
02913 if ( !view->config()->persistentSelection() && view->selection() ) {
02914 view->removeSelectedText();
02915 return;
02916 }
02917
02918 if( c.column() < (int) m_buffer->plainLine(c.line())->length())
02919 {
02920 removeText(KTextEditor::Range(c, 1));
02921 }
02922 else if ( c.line() < lastLine() )
02923 {
02924 removeText(KTextEditor::Range(c.line(), c.column(), c.line()+1, 0));
02925 }
02926 }
02927
02928 void KateDocument::paste ( KateView* view, QClipboard::Mode mode )
02929 {
02930 QString s = QApplication::clipboard()->text(mode);
02931
02932 if (s.isEmpty())
02933 return;
02934
02935 int lines = s.count (QChar::fromAscii ('\n'));
02936
02937 m_undoManager->setUndoDontMerge (true);
02938
02939 editStart (Kate::CutCopyPasteEdit);
02940
02941 KTextEditor::Cursor pos = view->cursorPosition();
02942 if (!view->config()->persistentSelection() && view->selection()) {
02943 pos = view->selectionRange().start();
02944 view->removeSelectedText();
02945 }
02946
02947 if (config()->configFlags() & KateDocumentConfig::cfOvr) {
02948 QStringList pasteLines = s.split(QLatin1Char('\n'));
02949
02950 if (!view->blockSelectionMode()) {
02951 int endColumn = (pasteLines.count() == 1 ? pos.column() : 0) + pasteLines.last().length();
02952 removeText(KTextEditor::Range(pos,
02953 pos.line()+pasteLines.count()-1, endColumn));
02954 } else {
02955 int maxi = qMin(pos.line() + pasteLines.count(), this->lines());
02956
02957 for (int i = pos.line(); i < maxi; ++i) {
02958 int pasteLength = pasteLines[i-pos.line()].length();
02959 removeText(KTextEditor::Range(i, pos.column(),
02960 i, qMin(pasteLength + pos.column(), lineLength(i))));
02961 }
02962 }
02963 }
02964
02965
02966 blockRemoveTrailingSpaces(true);
02967 insertText(pos, s, view->blockSelectionMode());
02968 blockRemoveTrailingSpaces(false);
02969
02970 for (int i = pos.line(); i < pos.line() + lines; ++i)
02971 removeTrailingSpace(i);
02972
02973 editEnd();
02974
02975
02976
02977
02978 if (view->blockSelectionMode())
02979 view->setCursorPositionInternal(view->cursorPosition() + KTextEditor::Cursor(lines, 0));
02980
02981 if (config()->configFlags() & KateDocumentConfig::cfIndentPastedText)
02982 {
02983 KTextEditor::Range range = KTextEditor::Range(KTextEditor::Cursor(pos.line(), 0),
02984 KTextEditor::Cursor(pos.line() + lines, 0));
02985
02986 int start = view->selectionRange().start().line();
02987 const int end = view->selectionRange().end().line();
02988
02989 editStart();
02990
02991 blockRemoveTrailingSpaces(true);
02992 m_indenter->indent(view, range);
02993 blockRemoveTrailingSpaces(false);
02994
02995 for (; start <= end; ++start)
02996 removeTrailingSpace(start);
02997
02998 editEnd();
02999 }
03000
03001 if (!view->blockSelectionMode())
03002 emit charactersSemiInteractivelyInserted (pos, s);
03003 m_undoManager->setUndoDontMerge (true);
03004 }
03005
03006 void KateDocument::indent ( KateView *v, uint line, int change)
03007 {
03008
03009
03010 const bool hasSelection = v->selection();
03011 int start = v->selectionRange().start().line();
03012 const int end = v->selectionRange().end().line();
03013
03014 KTextEditor::Range range = hasSelection ? v->selectionRange() : KTextEditor::Range (KTextEditor::Cursor (line,0), KTextEditor::Cursor (line,0));
03015
03016 editStart();
03017 blockRemoveTrailingSpaces(true);
03018 m_indenter->changeIndent(range, change);
03019 blockRemoveTrailingSpaces(false);
03020
03021 if (hasSelection) {
03022 for (; start <= end; ++start)
03023 removeTrailingSpace(start);
03024 }
03025 editEnd();
03026 }
03027
03028 void KateDocument::align(KateView *view, const KTextEditor::Range &range)
03029 {
03030 editStart();
03031
03032 blockRemoveTrailingSpaces(true);
03033 m_indenter->indent(view, range);
03034 blockRemoveTrailingSpaces(false);
03035
03036 for (int start = range.start().line(); start <= range.end().line(); ++start) {
03037 removeTrailingSpace(start);
03038 }
03039
03040 editEnd();
03041 }
03042
03043
03044
03045
03046
03047 bool KateDocument::removeStringFromBeginning(int line, const QString &str)
03048 {
03049 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03050
03051 KTextEditor::Cursor cursor (line, 0);
03052 bool there = textline->startsWith(str);
03053
03054 if (!there)
03055 {
03056 cursor.setColumn(textline->firstChar());
03057 there = textline->matchesAt(cursor.column(), str);
03058 }
03059
03060 if (there)
03061 {
03062
03063 removeText (KTextEditor::Range(cursor, str.length()));
03064 }
03065
03066 return there;
03067 }
03068
03069
03070
03071
03072
03073 bool KateDocument::removeStringFromEnd(int line, const QString &str)
03074 {
03075 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03076
03077 KTextEditor::Cursor cursor (line, 0);
03078 bool there = textline->endsWith(str);
03079
03080 if (there)
03081 {
03082 cursor.setColumn(textline->length() - str.length());
03083 }
03084 else
03085 {
03086 cursor.setColumn(textline->lastChar() - str.length() + 1);
03087 there = textline->matchesAt(cursor.column(), str);
03088 }
03089
03090 if (there)
03091 {
03092
03093 removeText (KTextEditor::Range(cursor, str.length()));
03094 }
03095
03096 return there;
03097 }
03098
03099
03100
03101
03102 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
03103 {
03104 QString commentLineMark = highlight()->getCommentSingleLineStart(attrib);
03105 int pos = -1;
03106
03107 if (highlight()->getCommentSingleLinePosition(attrib) == KateHighlighting::CSLPosColumn0)
03108 {
03109 pos = 0;
03110 commentLineMark += ' ';
03111 } else {
03112 const KateTextLine::Ptr l = kateTextLine(line);
03113 pos = l->firstChar();
03114 }
03115
03116 if (pos >= 0)
03117 insertText (KTextEditor::Cursor(line, pos), commentLineMark);
03118 }
03119
03120
03121
03122
03123
03124 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
03125 {
03126 const QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03127 const QString longCommentMark = shortCommentMark + ' ';
03128
03129 editStart();
03130
03131
03132 bool removed = (removeStringFromBeginning(line, longCommentMark)
03133 || removeStringFromBeginning(line, shortCommentMark));
03134
03135 editEnd();
03136
03137 return removed;
03138 }
03139
03140
03141
03142
03143
03144 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
03145 {
03146 const QString startCommentMark = highlight()->getCommentStart( attrib ) + ' ';
03147 const QString stopCommentMark = ' ' + highlight()->getCommentEnd( attrib );
03148
03149 editStart();
03150
03151
03152 insertText (KTextEditor::Cursor(line, 0), startCommentMark);
03153
03154
03155 const int col = m_buffer->plainLine(line)->length();
03156
03157
03158 insertText (KTextEditor::Cursor(line, col), stopCommentMark);
03159
03160 editEnd();
03161 }
03162
03163
03164
03165
03166
03167 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
03168 {
03169 QString shortStartCommentMark = highlight()->getCommentStart( attrib );
03170 QString longStartCommentMark = shortStartCommentMark + ' ';
03171 QString shortStopCommentMark = highlight()->getCommentEnd( attrib );
03172 QString longStopCommentMark = ' ' + shortStopCommentMark;
03173
03174 editStart();
03175
03176 #ifdef __GNUC__
03177 #warning "that's a bad idea, can lead to stray endings, FIXME"
03178 #endif
03179
03180 bool removedStart = (removeStringFromBeginning(line, longStartCommentMark)
03181 || removeStringFromBeginning(line, shortStartCommentMark));
03182
03183 bool removedStop = false;
03184 if (removedStart)
03185 {
03186
03187 removedStop = (removeStringFromEnd(line, longStopCommentMark)
03188 || removeStringFromEnd(line, shortStopCommentMark));
03189 }
03190
03191 editEnd();
03192
03193 return (removedStart || removedStop);
03194 }
03195
03196
03197
03198
03199
03200 void KateDocument::addStartStopCommentToSelection( KateView *view, int attrib )
03201 {
03202 const QString startComment = highlight()->getCommentStart( attrib );
03203 const QString endComment = highlight()->getCommentEnd( attrib );
03204
03205 KTextEditor::Range range = view->selectionRange();
03206
03207 if ((range.end().column() == 0) && (range.end().line() > 0))
03208 range.end().setPosition(range.end().line() - 1, lineLength(range.end().line() - 1));
03209
03210 editStart();
03211
03212 insertText (range.end(), endComment);
03213 insertText (range.start(), startComment);
03214
03215 editEnd ();
03216
03217 }
03218
03219
03220
03221
03222 void KateDocument::addStartLineCommentToSelection( KateView *view, int attrib )
03223 {
03224 const QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + ' ';
03225
03226 int sl = view->selectionRange().start().line();
03227 int el = view->selectionRange().end().line();
03228
03229
03230 if ((view->selectionRange().end().column() == 0) && (el > 0))
03231 {
03232 el--;
03233 }
03234
03235 editStart();
03236
03237
03238 for (int z = el; z >= sl; z--) {
03239
03240 addStartLineCommentToSingleLine(z, attrib );
03241 }
03242
03243 editEnd ();
03244
03245 }
03246
03247 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
03248 {
03249 for(; line < (int)m_buffer->count(); line++) {
03250 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03251
03252 if (!textLine)
03253 break;
03254
03255 col = textLine->nextNonSpaceChar(col);
03256 if(col != -1)
03257 return true;
03258 col = 0;
03259 }
03260
03261 line = -1;
03262 col = -1;
03263 return false;
03264 }
03265
03266 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
03267 {
03268 while(true)
03269 {
03270 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03271
03272 if (!textLine)
03273 break;
03274
03275 col = textLine->previousNonSpaceChar(col);
03276 if(col != -1) return true;
03277 if(line == 0) return false;
03278 --line;
03279 col = textLine->length();
03280 }
03281
03282 line = -1;
03283 col = -1;
03284 return false;
03285 }
03286
03287
03288
03289
03290
03291 bool KateDocument::removeStartStopCommentFromSelection( KateView *view, int attrib )
03292 {
03293 const QString startComment = highlight()->getCommentStart( attrib );
03294 const QString endComment = highlight()->getCommentEnd( attrib );
03295
03296 int sl = qMax<int> (0, view->selectionRange().start().line());
03297 int el = qMin<int> (view->selectionRange().end().line(), lastLine());
03298 int sc = view->selectionRange().start().column();
03299 int ec = view->selectionRange().end().column();
03300
03301
03302 if (ec != 0) {
03303 --ec;
03304 } else if (el > 0) {
03305 --el;
03306 ec = m_buffer->plainLine(el)->length() - 1;
03307 }
03308
03309 const int startCommentLen = startComment.length();
03310 const int endCommentLen = endComment.length();
03311
03312
03313
03314 bool remove = nextNonSpaceCharPos(sl, sc)
03315 && m_buffer->plainLine(sl)->matchesAt(sc, startComment)
03316 && previousNonSpaceCharPos(el, ec)
03317 && ( (ec - endCommentLen + 1) >= 0 )
03318 && m_buffer->plainLine(el)->matchesAt(ec - endCommentLen + 1, endComment);
03319
03320 if (remove) {
03321 editStart();
03322
03323 removeText (KTextEditor::Range(el, ec - endCommentLen + 1, el, ec + 1));
03324 removeText (KTextEditor::Range(sl, sc, sl, sc + startCommentLen));
03325
03326 editEnd ();
03327
03328 }
03329
03330 return remove;
03331 }
03332
03333 bool KateDocument::removeStartStopCommentFromRegion(const KTextEditor::Cursor &start,const KTextEditor::Cursor &end,int attrib)
03334 {
03335 const QString startComment = highlight()->getCommentStart( attrib );
03336 const QString endComment = highlight()->getCommentEnd( attrib );
03337 const int startCommentLen = startComment.length();
03338 const int endCommentLen = endComment.length();
03339
03340 const bool remove = m_buffer->plainLine(start.line())->matchesAt(start.column(), startComment)
03341 && m_buffer->plainLine(end.line())->matchesAt(end.column() - endCommentLen , endComment);
03342 if (remove) {
03343 editStart();
03344 removeText(KTextEditor::Range(end.line(), end.column() - endCommentLen, end.line(), end.column()));
03345 removeText(KTextEditor::Range(start, startCommentLen));
03346 editEnd();
03347 }
03348 return remove;
03349 }
03350
03351
03352
03353
03354
03355 bool KateDocument::removeStartLineCommentFromSelection( KateView *view, int attrib )
03356 {
03357 const QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03358 const QString longCommentMark = shortCommentMark + ' ';
03359
03360 int sl = view->selectionRange().start().line();
03361 int el = view->selectionRange().end().line();
03362
03363 if ((view->selectionRange().end().column() == 0) && (el > 0))
03364 {
03365 el--;
03366 }
03367
03368 bool removed = false;
03369
03370 editStart();
03371
03372
03373 for (int z = el; z >= sl; z--)
03374 {
03375
03376 removed = (removeStringFromBeginning(z, longCommentMark)
03377 || removeStringFromBeginning(z, shortCommentMark)
03378 || removed);
03379 }
03380
03381 editEnd();
03382
03383
03384 return removed;
03385 }
03386
03387
03388
03389
03390
03391 void KateDocument::comment( KateView *v, uint line,uint column, int change)
03392 {
03393
03394
03395
03396
03397 bool hassel = v->selection();
03398 int startAttrib, endAttrib;
03399 if ( hassel )
03400 {
03401 KateTextLine::Ptr ln = kateTextLine( v->selectionRange().start().line() );
03402 int l = v->selectionRange().start().line(), c = v->selectionRange().start().column();
03403 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03404
03405 ln = kateTextLine( v->selectionRange().end().line() );
03406 l = v->selectionRange().end().line(), c = v->selectionRange().end().column();
03407 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03408 }
03409 else
03410 {
03411 KateTextLine::Ptr ln = kateTextLine( line );
03412 if ( ln->length() )
03413 {
03414 startAttrib = ln->attribute( ln->firstChar() );
03415 endAttrib = ln->attribute( ln->lastChar() );
03416 }
03417 else
03418 {
03419 int l = line, c = 0;
03420 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
03421 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
03422 else
03423 startAttrib = endAttrib = 0;
03424 }
03425 }
03426
03427 if ( ! highlight()->canComment( startAttrib, endAttrib ) )
03428 {
03429 kDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!";
03430 return;
03431 }
03432
03433 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
03434 bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
03435 && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
03436
03437 bool removed = false;
03438
03439 if (change > 0)
03440 {
03441 if ( !hassel )
03442 {
03443 if ( hasStartLineCommentMark )
03444 addStartLineCommentToSingleLine( line, startAttrib );
03445 else if ( hasStartStopCommentMark )
03446 addStartStopCommentToSingleLine( line, startAttrib );
03447 }
03448 else
03449 {
03450
03451
03452
03453
03454
03455
03456
03457 if ( hasStartStopCommentMark &&
03458 ( !hasStartLineCommentMark || (
03459 ( v->selectionRange().start().column() > m_buffer->plainLine( v->selectionRange().start().line() )->firstChar() ) ||
03460 ( v->selectionRange().end().column() < ((int)m_buffer->plainLine( v->selectionRange().end().line() )->length()) )
03461 ) ) )
03462 addStartStopCommentToSelection( v, startAttrib );
03463 else if ( hasStartLineCommentMark )
03464 addStartLineCommentToSelection( v, startAttrib );
03465 }
03466 }
03467 else
03468 {
03469 if ( !hassel )
03470 {
03471 removed = ( hasStartLineCommentMark
03472 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
03473 || ( hasStartStopCommentMark
03474 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
03475 if ((!removed) && foldingTree()) {
03476 kDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)";
03477 int commentRegion=(highlight()->commentRegion(startAttrib));
03478 if (commentRegion){
03479 KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
03480 if (n) {
03481 KTextEditor::Cursor start,end;
03482 if ((n->nodeType()==(int)commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
03483 kDebug(13020)<<"Enclosing region found:"<<start.column()<<"/"<<start.line()<<"-"<<end.column()<<"/"<<end.line();
03484 removeStartStopCommentFromRegion(start,end,startAttrib);
03485 } else {
03486 kDebug(13020)<<"Enclosing region found, but not valid";
03487 kDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion;
03488 }
03489
03490 } else kDebug(13020)<<"No enclosing region found";
03491 } else kDebug(13020)<<"No comment region specified for current hl";
03492 }
03493 }
03494 else
03495 {
03496
03497 removed = ( hasStartLineCommentMark
03498 && removeStartLineCommentFromSelection( v, startAttrib ) )
03499 || ( hasStartStopCommentMark
03500 && removeStartStopCommentFromSelection( v, startAttrib ) );
03501 }
03502 }
03503 }
03504
03505 void KateDocument::transform( KateView *v, const KTextEditor::Cursor &c,
03506 KateDocument::TextTransform t )
03507 {
03508 editStart();
03509 KTextEditor::Cursor cursor = c;
03510
03511 if ( v->selection() )
03512 {
03513
03514 KTextEditor::Range selection = v->selectionRange();
03515
03516 KTextEditor::Range range(selection.start(), 0);
03517 while ( range.start().line() <= selection.end().line() )
03518 {
03519 int start = 0;
03520 int end = lineLength( range.start().line() );
03521
03522 if (range.start().line() == selection.start().line() || v->blockSelectionMode())
03523 start = selection.start().column();
03524
03525 if (range.start().line() == selection.end().line() || v->blockSelectionMode())
03526 end = selection.end().column();
03527
03528 if ( start > end )
03529 {
03530 int swapCol = start;
03531 start = end;
03532 end = swapCol;
03533 }
03534 range.start().setColumn( start );
03535 range.end().setColumn( end );
03536
03537 QString s = text( range );
03538 QString old = s;
03539
03540 if ( t == Uppercase )
03541 s = s.toUpper();
03542 else if ( t == Lowercase )
03543 s = s.toLower();
03544 else
03545 {
03546 KateTextLine::Ptr l = m_buffer->plainLine( range.start().line() );
03547 int p ( 0 );
03548 while( p < s.length() )
03549 {
03550
03551
03552
03553
03554 if ( ( ! range.start().column() && ! p ) ||
03555 ( ( range.start().line() == selection.start().line() || v->blockSelectionMode() ) &&
03556 ! p && ! highlight()->isInWord( l->at( range.start().column() - 1 )) ) ||
03557 ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
03558 )
03559 s[p] = s.at(p).toUpper();
03560 p++;
03561 }
03562 }
03563
03564 if ( s != old )
03565 {
03566 removeText( range );
03567 insertText( range.start(), s );
03568 }
03569
03570 range.setBothLines(range.start().line() + 1);
03571 }
03572
03573
03574 v->setSelection( selection );
03575
03576 } else {
03577 QString old = text( KTextEditor::Range(cursor, 1) );
03578 QString s;
03579 switch ( t ) {
03580 case Uppercase:
03581 s = old.toUpper();
03582 break;
03583 case Lowercase:
03584 s = old.toLower();
03585 break;
03586 case Capitalize:
03587 {
03588 KateTextLine::Ptr l = m_buffer->