00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "katedocument.h"
00023 #include "katedocument.moc"
00024 #include "katekeyinterceptorfunctor.h"
00025 #include "katefactory.h"
00026 #include "katedialogs.h"
00027 #include "katehighlight.h"
00028 #include "kateview.h"
00029 #include "katesearch.h"
00030 #include "kateautoindent.h"
00031 #include "katetextline.h"
00032 #include "katedocumenthelpers.h"
00033 #include "kateprinter.h"
00034 #include "katelinerange.h"
00035 #include "katesupercursor.h"
00036 #include "katearbitraryhighlight.h"
00037 #include "katerenderer.h"
00038 #include "kateattribute.h"
00039 #include "kateconfig.h"
00040 #include "katefiletype.h"
00041 #include "kateschema.h"
00042 #include "katetemplatehandler.h"
00043 #include <ktexteditor/plugin.h>
00044
00045 #include <kio/job.h>
00046 #include <kio/netaccess.h>
00047 #include <kio/kfileitem.h>
00048
00049
00050 #include <kparts/event.h>
00051
00052 #include <klocale.h>
00053 #include <kglobal.h>
00054 #include <kapplication.h>
00055 #include <kpopupmenu.h>
00056 #include <kconfig.h>
00057 #include <kfiledialog.h>
00058 #include <kmessagebox.h>
00059 #include <kstdaction.h>
00060 #include <kiconloader.h>
00061 #include <kxmlguifactory.h>
00062 #include <kdialogbase.h>
00063 #include <kdebug.h>
00064 #include <kglobalsettings.h>
00065 #include <klibloader.h>
00066 #include <kdirwatch.h>
00067 #include <kwin.h>
00068 #include <kencodingfiledialog.h>
00069 #include <ktempfile.h>
00070 #include <kmdcodec.h>
00071 #include <kstandarddirs.h>
00072
00073 #include <qtimer.h>
00074 #include <qfile.h>
00075 #include <qclipboard.h>
00076 #include <qtextstream.h>
00077 #include <qtextcodec.h>
00078 #include <qmap.h>
00079
00080
00081
00082 class KatePartPluginItem
00083 {
00084 public:
00085 KTextEditor::Plugin *plugin;
00086 };
00087
00088
00089
00090
00091
00092
00093 KateDocument::KateDocument ( bool bSingleViewMode, bool bBrowserView,
00094 bool bReadOnly, QWidget *parentWidget,
00095 const char *widgetName, QObject *parent, const char *name)
00096 : Kate::Document(parent, name),
00097 m_plugins (KateFactory::self()->plugins().count()),
00098 m_undoDontMerge(false),
00099 m_undoIgnoreCancel(false),
00100 lastUndoGroupWhenSaved( 0 ),
00101 docWasSavedWhenUndoWasEmpty( true ),
00102 m_modOnHd (false),
00103 m_modOnHdReason (0),
00104 m_job (0),
00105 m_tempFile (0),
00106 m_tabInterceptor(0)
00107 {
00108 m_undoComplexMerge=false;
00109 m_isInUndo = false;
00110
00111 setObjId ("KateDocument#"+documentDCOPSuffix());
00112
00113
00114 setBlockSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
00115 setConfigInterfaceDCOPSuffix (documentDCOPSuffix());
00116 setConfigInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
00117 setCursorInterfaceDCOPSuffix (documentDCOPSuffix());
00118 setEditInterfaceDCOPSuffix (documentDCOPSuffix());
00119 setEncodingInterfaceDCOPSuffix (documentDCOPSuffix());
00120 setHighlightingInterfaceDCOPSuffix (documentDCOPSuffix());
00121 setMarkInterfaceDCOPSuffix (documentDCOPSuffix());
00122 setMarkInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
00123 setPrintInterfaceDCOPSuffix (documentDCOPSuffix());
00124 setSearchInterfaceDCOPSuffix (documentDCOPSuffix());
00125 setSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
00126 setSelectionInterfaceExtDCOPSuffix (documentDCOPSuffix());
00127 setSessionConfigInterfaceDCOPSuffix (documentDCOPSuffix());
00128 setUndoInterfaceDCOPSuffix (documentDCOPSuffix());
00129 setWordWrapInterfaceDCOPSuffix (documentDCOPSuffix());
00130
00131
00132 m_plugins.fill (0);
00133
00134
00135 KateFactory::self()->registerDocument (this);
00136
00137 m_reloading = false;
00138 m_loading = false;
00139 m_encodingSticky = false;
00140
00141 m_buffer = new KateBuffer (this);
00142
00143
00144
00145 m_config = new KateDocumentConfig (this);
00146
00147
00148 m_activeView = 0L;
00149
00150 hlSetByUser = false;
00151 m_fileType = -1;
00152 m_fileTypeSetByUser = false;
00153 setInstance( KateFactory::self()->instance() );
00154
00155 editSessionNumber = 0;
00156 editIsRunning = false;
00157 m_editCurrentUndo = 0L;
00158 editWithUndo = false;
00159
00160 m_docNameNumber = 0;
00161
00162 m_bSingleViewMode = bSingleViewMode;
00163 m_bBrowserView = bBrowserView;
00164 m_bReadOnly = bReadOnly;
00165
00166 m_marks.setAutoDelete( true );
00167 m_markPixmaps.setAutoDelete( true );
00168 m_markDescriptions.setAutoDelete( true );
00169 setMarksUserChangable( markType01 );
00170
00171 m_undoMergeTimer = new QTimer(this);
00172 connect(m_undoMergeTimer, SIGNAL(timeout()), SLOT(undoCancel()));
00173
00174 clearMarks ();
00175 clearUndo ();
00176 clearRedo ();
00177 setModified (false);
00178 docWasSavedWhenUndoWasEmpty = true;
00179
00180
00181 m_buffer->setHighlight (0);
00182
00183 m_extension = new KateBrowserExtension( this );
00184 m_arbitraryHL = new KateArbitraryHighlight();
00185 m_indenter = KateAutoIndent::createIndenter ( this, 0 );
00186
00187 m_indenter->updateConfig ();
00188
00189
00190 connect(m_buffer, SIGNAL(tagLines(int,int)), this, SLOT(tagLines(int,int)));
00191 connect(m_buffer, SIGNAL(codeFoldingUpdated()),this,SIGNAL(codeFoldingUpdated()));
00192
00193
00194 connect(KateHlManager::self(),SIGNAL(changed()),SLOT(internalHlChanged()));
00195
00196
00197 connect(m_arbitraryHL, SIGNAL(tagLines(KateView*, KateSuperRange*)), SLOT(tagArbitraryLines(KateView*, KateSuperRange*)));
00198
00199
00200 connect( KateFactory::self()->dirWatch(), SIGNAL(dirty (const QString &)),
00201 this, SLOT(slotModOnHdDirty (const QString &)) );
00202
00203 connect( KateFactory::self()->dirWatch(), SIGNAL(created (const QString &)),
00204 this, SLOT(slotModOnHdCreated (const QString &)) );
00205
00206 connect( KateFactory::self()->dirWatch(), SIGNAL(deleted (const QString &)),
00207 this, SLOT(slotModOnHdDeleted (const QString &)) );
00208
00209
00210 setDocName ("");
00211
00212
00213 if ( m_bSingleViewMode )
00214 {
00215 KTextEditor::View *view = createView( parentWidget, widgetName );
00216 insertChildClient( view );
00217 view->show();
00218 setWidget( view );
00219 }
00220
00221 connect(this,SIGNAL(sigQueryClose(bool *, bool*)),this,SLOT(slotQueryClose_save(bool *, bool*)));
00222
00223 m_isasking = 0;
00224
00225
00226 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
00227 {
00228 if (config()->plugin (i))
00229 loadPlugin (i);
00230 }
00231 }
00232
00233
00234
00235
00236 KateDocument::~KateDocument()
00237 {
00238
00239 deactivateDirWatch ();
00240
00241 if (!singleViewMode())
00242 {
00243
00244 m_views.setAutoDelete( true );
00245 m_views.clear();
00246 }
00247
00248 delete m_editCurrentUndo;
00249
00250 delete m_arbitraryHL;
00251
00252
00253 undoItems.setAutoDelete(true);
00254 undoItems.clear();
00255
00256
00257 unloadAllPlugins ();
00258
00259 delete m_config;
00260 delete m_indenter;
00261 KateFactory::self()->deregisterDocument (this);
00262 }
00263
00264
00265
00266 void KateDocument::unloadAllPlugins ()
00267 {
00268 for (uint i=0; i<m_plugins.count(); i++)
00269 unloadPlugin (i);
00270 }
00271
00272 void KateDocument::enableAllPluginsGUI (KateView *view)
00273 {
00274 for (uint i=0; i<m_plugins.count(); i++)
00275 enablePluginGUI (m_plugins[i], view);
00276 }
00277
00278 void KateDocument::disableAllPluginsGUI (KateView *view)
00279 {
00280 for (uint i=0; i<m_plugins.count(); i++)
00281 disablePluginGUI (m_plugins[i], view);
00282 }
00283
00284 void KateDocument::loadPlugin (uint pluginIndex)
00285 {
00286 if (m_plugins[pluginIndex]) return;
00287
00288 m_plugins[pluginIndex] = KTextEditor::createPlugin (QFile::encodeName((KateFactory::self()->plugins())[pluginIndex]->library()), this);
00289
00290 enablePluginGUI (m_plugins[pluginIndex]);
00291 }
00292
00293 void KateDocument::unloadPlugin (uint pluginIndex)
00294 {
00295 if (!m_plugins[pluginIndex]) return;
00296
00297 disablePluginGUI (m_plugins[pluginIndex]);
00298
00299 delete m_plugins[pluginIndex];
00300 m_plugins[pluginIndex] = 0L;
00301 }
00302
00303 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
00304 {
00305 if (!plugin) return;
00306 if (!KTextEditor::pluginViewInterface(plugin)) return;
00307
00308 KXMLGUIFactory *factory = view->factory();
00309 if ( factory )
00310 factory->removeClient( view );
00311
00312 KTextEditor::pluginViewInterface(plugin)->addView(view);
00313
00314 if ( factory )
00315 factory->addClient( view );
00316 }
00317
00318 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin)
00319 {
00320 if (!plugin) return;
00321 if (!KTextEditor::pluginViewInterface(plugin)) return;
00322
00323 for (uint i=0; i< m_views.count(); i++)
00324 enablePluginGUI (plugin, m_views.at(i));
00325 }
00326
00327 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
00328 {
00329 if (!plugin) return;
00330 if (!KTextEditor::pluginViewInterface(plugin)) return;
00331
00332 KXMLGUIFactory *factory = view->factory();
00333 if ( factory )
00334 factory->removeClient( view );
00335
00336 KTextEditor::pluginViewInterface( plugin )->removeView( view );
00337
00338 if ( factory )
00339 factory->addClient( view );
00340 }
00341
00342 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin)
00343 {
00344 if (!plugin) return;
00345 if (!KTextEditor::pluginViewInterface(plugin)) return;
00346
00347 for (uint i=0; i< m_views.count(); i++)
00348 disablePluginGUI (plugin, m_views.at(i));
00349 }
00350
00351
00352
00353
00354 KTextEditor::View *KateDocument::createView( QWidget *parent, const char *name )
00355 {
00356 KateView* newView = new KateView( this, parent, name);
00357 connect(newView, SIGNAL(cursorPositionChanged()), SLOT(undoCancel()));
00358 if ( s_fileChangedDialogsActivated )
00359 connect( newView, SIGNAL(gotFocus( Kate::View * )), this, SLOT(slotModifiedOnDisk()) );
00360 return newView;
00361 }
00362
00363 QPtrList<KTextEditor::View> KateDocument::views () const
00364 {
00365 return m_textEditViews;
00366 }
00367
00368 void KateDocument::setActiveView( KateView *view )
00369 {
00370 if ( m_activeView == view ) return;
00371
00372 m_activeView = view;
00373 }
00374
00375
00376
00377
00378 uint KateDocument::configPages () const
00379 {
00380 return 10;
00381 }
00382
00383 KTextEditor::ConfigPage *KateDocument::configPage (uint number, QWidget *parent, const char * )
00384 {
00385 switch( number )
00386 {
00387 case 0:
00388 return new KateViewDefaultsConfig (parent);
00389
00390 case 1:
00391 return new KateSchemaConfigPage (parent, this);
00392
00393 case 2:
00394 return new KateSelectConfigTab (parent);
00395
00396 case 3:
00397 return new KateEditConfigTab (parent);
00398
00399 case 4:
00400 return new KateIndentConfigTab (parent);
00401
00402 case 5:
00403 return new KateSaveConfigTab (parent);
00404
00405 case 6:
00406 return new KateHlConfigPage (parent, this);
00407
00408 case 7:
00409 return new KateFileTypeConfigTab (parent);
00410
00411 case 8:
00412 return new KateEditKeyConfiguration (parent, this);
00413
00414 case 9:
00415 return new KatePartPluginConfigPage (parent);
00416
00417 default:
00418 return 0;
00419 }
00420
00421 return 0;
00422 }
00423
00424 QString KateDocument::configPageName (uint number) const
00425 {
00426 switch( number )
00427 {
00428 case 0:
00429 return i18n ("Appearance");
00430
00431 case 1:
00432 return i18n ("Fonts & Colors");
00433
00434 case 2:
00435 return i18n ("Cursor & Selection");
00436
00437 case 3:
00438 return i18n ("Editing");
00439
00440 case 4:
00441 return i18n ("Indentation");
00442
00443 case 5:
00444 return i18n("Open/Save");
00445
00446 case 6:
00447 return i18n ("Highlighting");
00448
00449 case 7:
00450 return i18n("Filetypes");
00451
00452 case 8:
00453 return i18n ("Shortcuts");
00454
00455 case 9:
00456 return i18n ("Plugins");
00457
00458 default:
00459 return QString ("");
00460 }
00461
00462 return QString ("");
00463 }
00464
00465 QString KateDocument::configPageFullName (uint number) const
00466 {
00467 switch( number )
00468 {
00469 case 0:
00470 return i18n("Appearance");
00471
00472 case 1:
00473 return i18n ("Font & Color Schemas");
00474
00475 case 2:
00476 return i18n ("Cursor & Selection Behavior");
00477
00478 case 3:
00479 return i18n ("Editing Options");
00480
00481 case 4:
00482 return i18n ("Indentation Rules");
00483
00484 case 5:
00485 return i18n("File Opening & Saving");
00486
00487 case 6:
00488 return i18n ("Highlighting Rules");
00489
00490 case 7:
00491 return i18n("Filetype Specific Settings");
00492
00493 case 8:
00494 return i18n ("Shortcuts Configuration");
00495
00496 case 9:
00497 return i18n ("Plugin Manager");
00498
00499 default:
00500 return QString ("");
00501 }
00502
00503 return QString ("");
00504 }
00505
00506 QPixmap KateDocument::configPagePixmap (uint number, int size) const
00507 {
00508 switch( number )
00509 {
00510 case 0:
00511 return BarIcon("view_text",size);
00512
00513 case 1:
00514 return BarIcon("colorize", size);
00515
00516 case 2:
00517 return BarIcon("frame_edit", size);
00518
00519 case 3:
00520 return BarIcon("edit", size);
00521
00522 case 4:
00523 return BarIcon("rightjust", size);
00524
00525 case 5:
00526 return BarIcon("filesave", size);
00527
00528 case 6:
00529 return BarIcon("source", size);
00530
00531 case 7:
00532 return BarIcon("edit", size);
00533
00534 case 8:
00535 return BarIcon("key_enter", size);
00536
00537 case 9:
00538 return BarIcon("connect_established", size);
00539
00540 default:
00541 return BarIcon("edit", size);
00542 }
00543
00544 return BarIcon("edit", size);
00545 }
00546
00547
00548
00549
00550 QString KateDocument::text() const
00551 {
00552 QString s;
00553
00554 for (uint i = 0; i < m_buffer->count(); i++)
00555 {
00556 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00557
00558 if (textLine)
00559 {
00560 s.append (textLine->string());
00561
00562 if ((i+1) < m_buffer->count())
00563 s.append('\n');
00564 }
00565 }
00566
00567 return s;
00568 }
00569
00570 QString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol ) const
00571 {
00572 return text(startLine, startCol, endLine, endCol, false);
00573 }
00574
00575 QString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise) const
00576 {
00577 if ( blockwise && (startCol > endCol) )
00578 return QString ();
00579
00580 QString s;
00581
00582 if (startLine == endLine)
00583 {
00584 if (startCol > endCol)
00585 return QString ();
00586
00587 KateTextLine::Ptr textLine = m_buffer->plainLine(startLine);
00588
00589 if ( !textLine )
00590 return QString ();
00591
00592 return textLine->string(startCol, endCol-startCol);
00593 }
00594 else
00595 {
00596
00597 for (uint i = startLine; (i <= endLine) && (i < m_buffer->count()); i++)
00598 {
00599 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00600
00601 if ( !blockwise )
00602 {
00603 if (i == startLine)
00604 s.append (textLine->string(startCol, textLine->length()-startCol));
00605 else if (i == endLine)
00606 s.append (textLine->string(0, endCol));
00607 else
00608 s.append (textLine->string());
00609 }
00610 else
00611 {
00612 s.append( textLine->string( startCol, endCol-startCol));
00613 }
00614
00615 if ( i < endLine )
00616 s.append('\n');
00617 }
00618 }
00619
00620 return s;
00621 }
00622
00623 QString KateDocument::textLine( uint line ) const
00624 {
00625 KateTextLine::Ptr l = m_buffer->plainLine(line);
00626
00627 if (!l)
00628 return QString();
00629
00630 return l->string();
00631 }
00632
00633 bool KateDocument::setText(const QString &s)
00634 {
00635 if (!isReadWrite())
00636 return false;
00637
00638 QPtrList<KTextEditor::Mark> m = marks ();
00639 QValueList<KTextEditor::Mark> msave;
00640
00641 for (uint i=0; i < m.count(); i++)
00642 msave.append (*m.at(i));
00643
00644 editStart ();
00645
00646
00647 clear();
00648
00649
00650 insertText (0, 0, s);
00651
00652 editEnd ();
00653
00654 for (uint i=0; i < msave.count(); i++)
00655 setMark (msave[i].line, msave[i].type);
00656
00657 return true;
00658 }
00659
00660 bool KateDocument::clear()
00661 {
00662 if (!isReadWrite())
00663 return false;
00664
00665 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() ) {
00666 view->clear();
00667 view->tagAll();
00668 view->update();
00669 }
00670
00671 clearMarks ();
00672
00673 return removeText (0,0,lastLine()+1, 0);
00674 }
00675
00676 bool KateDocument::insertText( uint line, uint col, const QString &s)
00677 {
00678 return insertText (line, col, s, false);
00679 }
00680
00681 bool KateDocument::insertText( uint line, uint col, const QString &s, bool blockwise )
00682 {
00683 if (!isReadWrite())
00684 return false;
00685
00686 if (s.isEmpty())
00687 return true;
00688
00689 if (line == numLines())
00690 editInsertLine(line,"");
00691 else if (line > lastLine())
00692 return false;
00693
00694 editStart ();
00695
00696 uint insertPos = col;
00697 uint len = s.length();
00698
00699 QString buf;
00700
00701 bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo );
00702 uint tw = config()->tabWidth();
00703 uint insertPosExpanded = insertPos;
00704 KateTextLine::Ptr l = m_buffer->line( line );
00705 if (l != 0)
00706 insertPosExpanded = l->cursorX( insertPos, tw );
00707
00708 for (uint pos = 0; pos < len; pos++)
00709 {
00710 QChar ch = s[pos];
00711
00712 if (ch == '\n')
00713 {
00714 editInsertText (line, insertPos, buf);
00715
00716 if ( !blockwise )
00717 {
00718 editWrapLine (line, insertPos + buf.length());
00719 insertPos = insertPosExpanded = 0;
00720 }
00721 else
00722 {
00723 if ( line == lastLine() )
00724 editWrapLine (line, insertPos + buf.length());
00725 }
00726
00727 line++;
00728 buf.truncate(0);
00729 l = m_buffer->line( line );
00730 if (l)
00731 insertPosExpanded = l->cursorX( insertPos, tw );
00732 }
00733 else
00734 {
00735 if ( replacetabs && ch == '\t' )
00736 {
00737 uint tr = tw - ( insertPosExpanded+buf.length() )%tw;
00738 for ( uint i=0; i < tr; i++ )
00739 buf += ' ';
00740 }
00741 else
00742 buf += ch;
00743 }
00744 }
00745
00746 editInsertText (line, insertPos, buf);
00747
00748 editEnd ();
00749 emit textInserted(line,insertPos);
00750 return true;
00751 }
00752
00753 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol )
00754 {
00755 return removeText (startLine, startCol, endLine, endCol, false);
00756 }
00757
00758 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise)
00759 {
00760 if (!isReadWrite())
00761 return false;
00762
00763 if ( blockwise && (startCol > endCol) )
00764 return false;
00765
00766 if ( startLine > endLine )
00767 return false;
00768
00769 if ( startLine > lastLine() )
00770 return false;
00771
00772 if (!blockwise) {
00773 emit aboutToRemoveText(KateTextRange(startLine,startCol,endLine,endCol));
00774 }
00775 editStart ();
00776
00777 if ( !blockwise )
00778 {
00779 if ( endLine > lastLine() )
00780 {
00781 endLine = lastLine()+1;
00782 endCol = 0;
00783 }
00784
00785 if (startLine == endLine)
00786 {
00787 editRemoveText (startLine, startCol, endCol-startCol);
00788 }
00789 else if ((startLine+1) == endLine)
00790 {
00791 if ( (m_buffer->plainLine(startLine)->length()-startCol) > 0 )
00792 editRemoveText (startLine, startCol, m_buffer->plainLine(startLine)->length()-startCol);
00793
00794 editRemoveText (startLine+1, 0, endCol);
00795 editUnWrapLine (startLine);
00796 }
00797 else
00798 {
00799 for (uint line = endLine; line >= startLine; line--)
00800 {
00801 if ((line > startLine) && (line < endLine))
00802 {
00803 editRemoveLine (line);
00804 }
00805 else
00806 {
00807 if (line == endLine)
00808 {
00809 if ( endLine <= lastLine() )
00810 editRemoveText (line, 0, endCol);
00811 }
00812 else
00813 {
00814 if ( (m_buffer->plainLine(line)->length()-startCol) > 0 )
00815 editRemoveText (line, startCol, m_buffer->plainLine(line)->length()-startCol);
00816
00817 editUnWrapLine (startLine);
00818 }
00819 }
00820
00821 if ( line == 0 )
00822 break;
00823 }
00824 }
00825 }
00826 else
00827 {
00828 if ( endLine > lastLine() )
00829 endLine = lastLine ();
00830
00831 for (uint line = endLine; line >= startLine; line--)
00832 {
00833
00834 editRemoveText (line, startCol, endCol-startCol);
00835
00836 if ( line == 0 )
00837 break;
00838 }
00839 }
00840
00841 editEnd ();
00842 emit textRemoved();
00843 return true;
00844 }
00845
00846 bool KateDocument::insertLine( uint l, const QString &str )
00847 {
00848 if (!isReadWrite())
00849 return false;
00850
00851 if (l > numLines())
00852 return false;
00853
00854 return editInsertLine (l, str);
00855 }
00856
00857 bool KateDocument::removeLine( uint line )
00858 {
00859 if (!isReadWrite())
00860 return false;
00861
00862 if (line > lastLine())
00863 return false;
00864
00865 return editRemoveLine (line);
00866 }
00867
00868 uint KateDocument::length() const
00869 {
00870 uint l = 0;
00871
00872 for (uint i = 0; i < m_buffer->count(); i++)
00873 {
00874 KateTextLine::Ptr line = m_buffer->plainLine(i);
00875
00876 if (line)
00877 l += line->length();
00878 }
00879
00880 return l;
00881 }
00882
00883 uint KateDocument::numLines() const
00884 {
00885 return m_buffer->count();
00886 }
00887
00888 uint KateDocument::numVisLines() const
00889 {
00890 return m_buffer->countVisible ();
00891 }
00892
00893 int KateDocument::lineLength ( uint line ) const
00894 {
00895 KateTextLine::Ptr l = m_buffer->plainLine(line);
00896
00897 if (!l)
00898 return -1;
00899
00900 return l->length();
00901 }
00902
00903
00904
00905
00906
00907
00908 void KateDocument::editStart (bool withUndo)
00909 {
00910 editSessionNumber++;
00911
00912 if (editSessionNumber > 1)
00913 return;
00914
00915 editIsRunning = true;
00916 editWithUndo = withUndo;
00917
00918 if (editWithUndo)
00919 undoStart();
00920 else
00921 undoCancel();
00922
00923 for (uint z = 0; z < m_views.count(); z++)
00924 {
00925 m_views.at(z)->editStart ();
00926 }
00927
00928 m_buffer->editStart ();
00929 }
00930
00931 void KateDocument::undoStart()
00932 {
00933 if (m_editCurrentUndo || (m_activeView && m_activeView->imComposeEvent())) return;
00934
00935
00936 if ((config()->undoSteps() > 0) && (undoItems.count() > config()->undoSteps()))
00937 {
00938 undoItems.setAutoDelete(true);
00939 undoItems.removeFirst();
00940 undoItems.setAutoDelete(false);
00941 docWasSavedWhenUndoWasEmpty = false;
00942 }
00943
00944
00945 m_editCurrentUndo = new KateUndoGroup(this);
00946 }
00947
00948 void KateDocument::undoEnd()
00949 {
00950 if (m_activeView && m_activeView->imComposeEvent())
00951 return;
00952
00953 if (m_editCurrentUndo)
00954 {
00955 bool changedUndo = false;
00956
00957 if (m_editCurrentUndo->isEmpty())
00958 delete m_editCurrentUndo;
00959 else if (!m_undoDontMerge && undoItems.last() && undoItems.last()->merge(m_editCurrentUndo,m_undoComplexMerge))
00960 delete m_editCurrentUndo;
00961 else
00962 {
00963 undoItems.append(m_editCurrentUndo);
00964 changedUndo = true;
00965 }
00966
00967 m_undoDontMerge = false;
00968 m_undoIgnoreCancel = true;
00969
00970 m_editCurrentUndo = 0L;
00971
00972
00973
00974 m_undoMergeTimer->start(5000, true);
00975
00976 if (changedUndo)
00977 emit undoChanged();
00978 }
00979 }
00980
00981 void KateDocument::undoCancel()
00982 {
00983 if (m_undoIgnoreCancel) {
00984 m_undoIgnoreCancel = false;
00985 return;
00986 }
00987
00988 m_undoDontMerge = true;
00989
00990 Q_ASSERT(!m_editCurrentUndo);
00991
00992
00993 delete m_editCurrentUndo;
00994 m_editCurrentUndo = 0L;
00995 }
00996
00997 void KateDocument::undoSafePoint() {
00998 Q_ASSERT(m_editCurrentUndo);
00999 if (!m_editCurrentUndo) return;
01000 m_editCurrentUndo->safePoint();
01001 }
01002
01003
01004
01005
01006 void KateDocument::editEnd ()
01007 {
01008 if (editSessionNumber == 0)
01009 return;
01010
01011
01012 if (m_buffer->editChanged() && (editSessionNumber == 1))
01013 if (editWithUndo && config()->wordWrap())
01014 wrapText (m_buffer->editTagStart(), m_buffer->editTagEnd());
01015
01016 editSessionNumber--;
01017
01018 if (editSessionNumber > 0)
01019 return;
01020
01021
01022
01023 m_buffer->editEnd ();
01024
01025 if (editWithUndo)
01026 undoEnd();
01027
01028
01029 for (uint z = 0; z < m_views.count(); z++)
01030 m_views.at(z)->editEnd (m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
01031
01032 if (m_buffer->editChanged())
01033 {
01034 setModified(true);
01035 emit textChanged ();
01036 }
01037
01038 editIsRunning = false;
01039 }
01040
01041 bool KateDocument::wrapText (uint startLine, uint endLine)
01042 {
01043 uint col = config()->wordWrapAt();
01044
01045 if (col == 0)
01046 return false;
01047
01048 editStart ();
01049
01050 for (uint line = startLine; (line <= endLine) && (line < numLines()); line++)
01051 {
01052 KateTextLine::Ptr l = m_buffer->line(line);
01053
01054 if (!l)
01055 return false;
01056
01057 kdDebug (13020) << "try wrap line: " << line << endl;
01058
01059 if (l->lengthWithTabs(m_buffer->tabWidth()) > col)
01060 {
01061 KateTextLine::Ptr nextl = m_buffer->line(line+1);
01062
01063 kdDebug (13020) << "do wrap line: " << line << endl;
01064
01065 const QChar *text = l->text();
01066 uint eolPosition = l->length()-1;
01067
01068
01069 uint x = 0;
01070 const QString & t = l->string();
01071 uint z2 = 0;
01072 for ( ; z2 < l->length(); z2++)
01073 {
01074 if (t[z2] == QChar('\t'))
01075 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
01076 else
01077 x++;
01078
01079 if (x > col)
01080 break;
01081 }
01082
01083 uint searchStart = kMin (z2, l->length()-1);
01084
01085
01086
01087 if (searchStart == eolPosition && text[searchStart].isSpace())
01088 searchStart--;
01089
01090
01091
01092
01093
01094
01095
01096 int z = 0;
01097 uint nw = 0;
01098 for (z=searchStart; z > 0; z--)
01099 {
01100 if (text[z].isSpace()) break;
01101 if ( ! nw && highlight()->canBreakAt( text[z] , l->attribute(z) ) )
01102 nw = z;
01103 }
01104
01105 if (z > 0)
01106 {
01107
01108 editRemoveText (line, z, 1);
01109 }
01110 else
01111 {
01112
01113
01114
01115 if ( nw && nw < col ) nw++;
01116 z = nw ? nw : col;
01117 }
01118
01119 if (nextl && !nextl->isAutoWrapped())
01120 {
01121 editWrapLine (line, z, true);
01122 editMarkLineAutoWrapped (line+1, true);
01123
01124 endLine++;
01125 }
01126 else
01127 {
01128 if (nextl && (nextl->length() > 0) && !nextl->getChar(0).isSpace() && ((l->length() < 1) || !l->getChar(l->length()-1).isSpace()))
01129 editInsertText (line+1, 0, QString (" "));
01130
01131 bool newLineAdded = false;
01132 editWrapLine (line, z, false, &newLineAdded);
01133
01134 editMarkLineAutoWrapped (line+1, true);
01135
01136 endLine++;
01137 }
01138 }
01139 }
01140
01141 editEnd ();
01142
01143 return true;
01144 }
01145
01146 void KateDocument::editAddUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const QString &text)
01147 {
01148 if (editIsRunning && editWithUndo && m_editCurrentUndo) {
01149 m_editCurrentUndo->addItem(type, line, col, len, text);
01150
01151
01152 if (redoItems.count()) {
01153 redoItems.setAutoDelete(true);
01154 redoItems.clear();
01155 redoItems.setAutoDelete(false);
01156 }
01157 }
01158 }
01159
01160 bool KateDocument::editInsertText ( uint line, uint col, const QString &str )
01161 {
01162 if (!isReadWrite())
01163 return false;
01164
01165 QString s = str;
01166
01167 KateTextLine::Ptr l = m_buffer->line(line);
01168
01169 if (!l)
01170 return false;
01171
01172 if ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo )
01173 {
01174 uint tw = config()->tabWidth();
01175 int pos = 0;
01176 uint l = 0;
01177 while ( (pos = s.find('\t')) > -1 )
01178 {
01179 l = tw - ( (col + pos)%tw );
01180 s.replace( pos, 1, QString().fill( ' ', l ) );
01181 }
01182 }
01183
01184 editStart ();
01185
01186 editAddUndo (KateUndoGroup::editInsertText, line, col, s.length(), s);
01187
01188 l->insertText (col, s.length(), s.unicode());
01189
01190
01191 m_buffer->changeLine(line);
01192
01193 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01194 it.current()->editTextInserted (line, col, s.length());
01195
01196 editEnd ();
01197
01198 return true;
01199 }
01200
01201 bool KateDocument::editRemoveText ( uint line, uint col, uint len )
01202 {
01203 if (!isReadWrite())
01204 return false;
01205
01206 KateTextLine::Ptr l = m_buffer->line(line);
01207
01208 if (!l)
01209 return false;
01210
01211 editStart ();
01212
01213 editAddUndo (KateUndoGroup::editRemoveText, line, col, len, l->string().mid(col, len));
01214
01215 l->removeText (col, len);
01216 removeTrailingSpace( line );
01217
01218 m_buffer->changeLine(line);
01219
01220 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01221 it.current()->editTextRemoved (line, col, len);
01222
01223 editEnd ();
01224
01225 return true;
01226 }
01227
01228 bool KateDocument::editMarkLineAutoWrapped ( uint line, bool autowrapped )
01229 {
01230 if (!isReadWrite())
01231 return false;
01232
01233 KateTextLine::Ptr l = m_buffer->line(line);
01234
01235 if (!l)
01236 return false;
01237
01238 editStart ();
01239
01240 editAddUndo (KateUndoGroup::editMarkLineAutoWrapped, line, autowrapped ? 1 : 0, 0, QString::null);
01241
01242 l->setAutoWrapped (autowrapped);
01243
01244 m_buffer->changeLine(line);
01245
01246 editEnd ();
01247
01248 return true;
01249 }
01250
01251 bool KateDocument::editWrapLine ( uint line, uint col, bool newLine, bool *newLineAdded)
01252 {
01253 if (!isReadWrite())
01254 return false;
01255
01256 KateTextLine::Ptr l = m_buffer->line(line);
01257
01258 if (!l)
01259 return false;
01260
01261 editStart ();
01262
01263 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
01264
01265 int pos = l->length() - col;
01266
01267 if (pos < 0)
01268 pos = 0;
01269
01270 editAddUndo (KateUndoGroup::editWrapLine, line, col, pos, (!nextLine || newLine) ? "1" : "0");
01271
01272 if (!nextLine || newLine)
01273 {
01274 KateTextLine::Ptr textLine = new KateTextLine();
01275
01276 textLine->insertText (0, pos, l->text()+col, l->attributes()+col);
01277 l->truncate(col);
01278
01279 m_buffer->insertLine (line+1, textLine);
01280 m_buffer->changeLine(line);
01281
01282 QPtrList<KTextEditor::Mark> list;
01283 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01284 {
01285 if( it.current()->line >= line )
01286 {
01287 if ((col == 0) || (it.current()->line > line))
01288 list.append( it.current() );
01289 }
01290 }
01291
01292 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01293 {
01294 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01295 mark->line++;
01296 m_marks.insert( mark->line, mark );
01297 }
01298
01299 if( !list.isEmpty() )
01300 emit marksChanged();
01301
01302
01303 if (newLineAdded)
01304 (*newLineAdded) = true;
01305 }
01306 else
01307 {
01308 nextLine->insertText (0, pos, l->text()+col, l->attributes()+col);
01309 l->truncate(col);
01310
01311 m_buffer->changeLine(line);
01312 m_buffer->changeLine(line+1);
01313
01314
01315 if (newLineAdded)
01316 (*newLineAdded) = false;
01317 }
01318
01319 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01320 it.current()->editLineWrapped (line, col, !nextLine || newLine);
01321
01322 editEnd ();
01323
01324 return true;
01325 }
01326
01327 bool KateDocument::editUnWrapLine ( uint line, bool removeLine, uint length )
01328 {
01329 if (!isReadWrite())
01330 return false;
01331
01332 KateTextLine::Ptr l = m_buffer->line(line);
01333 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
01334
01335 if (!l || !nextLine)
01336 return false;
01337
01338 editStart ();
01339
01340 uint col = l->length ();
01341
01342 editAddUndo (KateUndoGroup::editUnWrapLine, line, col, length, removeLine ? "1" : "0");
01343
01344 if (removeLine)
01345 {
01346 l->insertText (col, nextLine->length(), nextLine->text(), nextLine->attributes());
01347
01348 m_buffer->changeLine(line);
01349 m_buffer->removeLine(line+1);
01350 }
01351 else
01352 {
01353 l->insertText (col, (nextLine->length() < length) ? nextLine->length() : length,
01354 nextLine->text(), nextLine->attributes());
01355 nextLine->removeText (0, (nextLine->length() < length) ? nextLine->length() : length);
01356
01357 m_buffer->changeLine(line);
01358 m_buffer->changeLine(line+1);
01359 }
01360
01361 QPtrList<KTextEditor::Mark> list;
01362 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01363 {
01364 if( it.current()->line >= line+1 )
01365 list.append( it.current() );
01366
01367 if ( it.current()->line == line+1 )
01368 {
01369 KTextEditor::Mark* mark = m_marks.take( line );
01370
01371 if (mark)
01372 {
01373 it.current()->type |= mark->type;
01374 }
01375 }
01376 }
01377
01378 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01379 {
01380 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01381 mark->line--;
01382 m_marks.insert( mark->line, mark );
01383 }
01384
01385 if( !list.isEmpty() )
01386 emit marksChanged();
01387
01388 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01389 it.current()->editLineUnWrapped (line, col, removeLine, length);
01390
01391 editEnd ();
01392
01393 return true;
01394 }
01395
01396 bool KateDocument::editInsertLine ( uint line, const QString &s )
01397 {
01398 if (!isReadWrite())
01399 return false;
01400
01401 if ( line > numLines() )
01402 return false;
01403
01404 editStart ();
01405
01406 editAddUndo (KateUndoGroup::editInsertLine, line, 0, s.length(), s);
01407
01408 removeTrailingSpace( line );
01409
01410 KateTextLine::Ptr tl = new KateTextLine();
01411 tl->insertText (0, s.length(), s.unicode(), 0);
01412 m_buffer->insertLine(line, tl);
01413 m_buffer->changeLine(line);
01414
01415 removeTrailingSpace( line );
01416
01417 QPtrList<KTextEditor::Mark> list;
01418 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01419 {
01420 if( it.current()->line >= line )
01421 list.append( it.current() );
01422 }
01423
01424 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01425 {
01426 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01427 mark->line++;
01428 m_marks.insert( mark->line, mark );
01429 }
01430
01431 if( !list.isEmpty() )
01432 emit marksChanged();
01433
01434 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01435 it.current()->editLineInserted (line);
01436
01437 editEnd ();
01438
01439 return true;
01440 }
01441
01442 bool KateDocument::editRemoveLine ( uint line )
01443 {
01444 if (!isReadWrite())
01445 return false;
01446
01447 if ( line > lastLine() )
01448 return false;
01449
01450 if ( numLines() == 1 )
01451 return editRemoveText (0, 0, m_buffer->line(0)->length());
01452
01453 editStart ();
01454
01455 editAddUndo (KateUndoGroup::editRemoveLine, line, 0, lineLength(line), textLine(line));
01456
01457 m_buffer->removeLine(line);
01458
01459 QPtrList<KTextEditor::Mark> list;
01460 KTextEditor::Mark* rmark = 0;
01461 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01462 {
01463 if ( (it.current()->line > line) )
01464 list.append( it.current() );
01465 else if ( (it.current()->line == line) )
01466 rmark = it.current();
01467 }
01468
01469 if (rmark)
01470 delete (m_marks.take (rmark->line));
01471
01472 for( QPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
01473 {
01474 KTextEditor::Mark* mark = m_marks.take( it.current()->line );
01475 mark->line--;
01476 m_marks.insert( mark->line, mark );
01477 }
01478
01479 if( !list.isEmpty() )
01480 emit marksChanged();
01481
01482 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01483 it.current()->editLineRemoved (line);
01484
01485 editEnd();
01486
01487 return true;
01488 }
01489
01490
01491
01492
01493 uint KateDocument::undoCount () const
01494 {
01495 return undoItems.count ();
01496 }
01497
01498 uint KateDocument::redoCount () const
01499 {
01500 return redoItems.count ();
01501 }
01502
01503 uint KateDocument::undoSteps () const
01504 {
01505 return m_config->undoSteps();
01506 }
01507
01508 void KateDocument::setUndoSteps(uint steps)
01509 {
01510 m_config->setUndoSteps (steps);
01511 }
01512
01513 void KateDocument::undo()
01514 {
01515 m_isInUndo = true;
01516 if ((undoItems.count() > 0) && undoItems.last())
01517 {
01518 clearSelection ();
01519
01520 undoItems.last()->undo();
01521 redoItems.append (undoItems.last());
01522 undoItems.removeLast ();
01523 updateModified();
01524
01525 emit undoChanged ();
01526 }
01527 m_isInUndo = false;
01528 }
01529
01530 void KateDocument::redo()
01531 {
01532 m_isInUndo = true;
01533 if ((redoItems.count() > 0) && redoItems.last())
01534 {
01535 clearSelection ();
01536
01537 redoItems.last()->redo();
01538 undoItems.append (redoItems.last());
01539 redoItems.removeLast ();
01540 updateModified();
01541
01542 emit undoChanged ();
01543 }
01544 m_isInUndo = false;
01545 }
01546
01547 void KateDocument::updateModified()
01548 {
01549 if ( ( lastUndoGroupWhenSaved &&
01550 !undoItems.isEmpty() &&
01551 undoItems.last() == lastUndoGroupWhenSaved )
01552 || ( undoItems.isEmpty() && docWasSavedWhenUndoWasEmpty ) )
01553 {
01554 setModified( false );
01555 kdDebug(13020) << k_funcinfo << "setting modified to false!" << endl;
01556 };
01557 }
01558
01559 void KateDocument::clearUndo()
01560 {
01561 undoItems.setAutoDelete (true);
01562 undoItems.clear ();
01563 undoItems.setAutoDelete (false);
01564
01565 lastUndoGroupWhenSaved = 0;
01566 docWasSavedWhenUndoWasEmpty = false;
01567
01568 emit undoChanged ();
01569 }
01570
01571 void KateDocument::clearRedo()
01572 {
01573 redoItems.setAutoDelete (true);
01574 redoItems.clear ();
01575 redoItems.setAutoDelete (false);
01576
01577 emit undoChanged ();
01578 }
01579
01580 QPtrList<KTextEditor::Cursor> KateDocument::cursors () const
01581 {
01582 return myCursors;
01583 }
01584
01585
01586
01587
01588 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const QString &text, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool casesensitive, bool backwards)
01589 {
01590 if (text.isEmpty())
01591 return false;
01592
01593 int line = startLine;
01594 int col = startCol;
01595
01596 if (!backwards)
01597 {
01598 int searchEnd = lastLine();
01599
01600 while (line <= searchEnd)
01601 {
01602 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01603
01604 if (!textLine)
01605 return false;
01606
01607 uint foundAt, myMatchLen;
01608 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, false);
01609
01610 if (found)
01611 {
01612 (*foundAtLine) = line;
01613 (*foundAtCol) = foundAt;
01614 (*matchLen) = myMatchLen;
01615 return true;
01616 }
01617
01618 col = 0;
01619 line++;
01620 }
01621 }
01622 else
01623 {
01624
01625 int searchEnd = 0;
01626
01627 while (line >= searchEnd)
01628 {
01629 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01630
01631 if (!textLine)
01632 return false;
01633
01634 uint foundAt, myMatchLen;
01635 bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, true);
01636
01637 if (found)
01638 {
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654 (*foundAtLine) = line;
01655 (*foundAtCol) = foundAt;
01656 (*matchLen) = myMatchLen;
01657 return true;
01658 }
01659
01660 if (line >= 1)
01661 col = lineLength(line-1);
01662
01663 line--;
01664 }
01665 }
01666
01667 return false;
01668 }
01669
01670 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const QRegExp ®exp, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool backwards)
01671 {
01672 kdDebug(13020)<<"KateDocument::searchText( "<<startLine<<", "<<startCol<<", "<<regexp.pattern()<<", "<<backwards<<" )"<<endl;
01673 if (regexp.isEmpty() || !regexp.isValid())
01674 return false;
01675
01676 int line = startLine;
01677 int col = startCol;
01678
01679 if (!backwards)
01680 {
01681 int searchEnd = lastLine();
01682
01683 while (line <= searchEnd)
01684 {
01685 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01686
01687 if (!textLine)
01688 return false;
01689
01690 uint foundAt, myMatchLen;
01691 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, false);
01692
01693 if (found)
01694 {
01695
01696
01697 if (myMatchLen == 0 && (uint) line == startLine && foundAt == (uint) col)
01698 {
01699 if (col < lineLength(line))
01700 col++;
01701 else {
01702 line++;
01703 col = 0;
01704 }
01705 continue;
01706 }
01707
01708 (*foundAtLine) = line;
01709 (*foundAtCol) = foundAt;
01710 (*matchLen) = myMatchLen;
01711 return true;
01712 }
01713
01714 col = 0;
01715 line++;
01716 }
01717 }
01718 else
01719 {
01720
01721 int searchEnd = 0;
01722
01723 while (line >= searchEnd)
01724 {
01725 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
01726
01727 if (!textLine)
01728 return false;
01729
01730 uint foundAt, myMatchLen;
01731 bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, true);
01732
01733 if (found)
01734 {
01735
01736
01737
01738
01739
01740
01741
01742
01743
01744
01745
01746
01747
01748
01749
01750 (*foundAtLine) = line;
01751 (*foundAtCol) = foundAt;
01752 (*matchLen) = myMatchLen;
01753 return true;
01754 }
01755
01756 if (line >= 1)
01757 col = lineLength(line-1);
01758
01759 line--;
01760 }
01761 }
01762
01763 return false;
01764 }
01765
01766
01767
01768
01769 uint KateDocument::hlMode ()
01770 {
01771 return KateHlManager::self()->findHl(highlight());
01772 }
01773
01774 bool KateDocument::setHlMode (uint mode)
01775 {
01776 m_buffer->setHighlight (mode);
01777
01778 if (true)
01779 {
01780 setDontChangeHlOnSave();
01781 return true;
01782 }
01783
01784 return false;
01785 }
01786
01787 void KateDocument::bufferHlChanged ()
01788 {
01789
01790 makeAttribs(false);
01791
01792 emit hlChanged();
01793 }
01794
01795 uint KateDocument::hlModeCount ()
01796 {
01797 return KateHlManager::self()->highlights();
01798 }
01799
01800 QString KateDocument::hlModeName (uint mode)
01801 {
01802 return KateHlManager::self()->hlName (mode);
01803 }
01804
01805 QString KateDocument::hlModeSectionName (uint mode)
01806 {
01807 return KateHlManager::self()->hlSection (mode);
01808 }
01809
01810 void KateDocument::setDontChangeHlOnSave()
01811 {
01812 hlSetByUser = true;
01813 }
01814
01815
01816
01817 void KateDocument::readConfig(KConfig *config)
01818 {
01819 config->setGroup("Kate Document Defaults");
01820
01821
01822 KateBuffer::setMaxLoadedBlocks (config->readNumEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks()));
01823
01824 KateDocumentConfig::global()->readConfig (config);
01825
01826 config->setGroup("Kate View Defaults");
01827 KateViewConfig::global()->readConfig (config);
01828
01829 config->setGroup("Kate Renderer Defaults");
01830 KateRendererConfig::global()->readConfig (config);
01831 }
01832
01833 void KateDocument::writeConfig(KConfig *config)
01834 {
01835 config->setGroup("Kate Document Defaults");
01836
01837
01838 config->writeEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks());
01839
01840 KateDocumentConfig::global()->writeConfig (config);
01841
01842 config->setGroup("Kate View Defaults");
01843 KateViewConfig::global()->writeConfig (config);
01844
01845 config->setGroup("Kate Renderer Defaults");
01846 KateRendererConfig::global()->writeConfig (config);
01847 }
01848
01849 void KateDocument::readConfig()
01850 {
01851 KConfig *config = kapp->config();
01852 readConfig (config);
01853 }
01854
01855 void KateDocument::writeConfig()
01856 {
01857 KConfig *config = kapp->config();
01858 writeConfig (config);
01859 config->sync();
01860 }
01861
01862 void KateDocument::readSessionConfig(KConfig *kconfig)
01863 {
01864
01865 KURL url (kconfig->readEntry("URL"));
01866
01867
01868 QString tmpenc=kconfig->readEntry("Encoding");
01869 if (!tmpenc.isEmpty() && (tmpenc != encoding()))
01870 setEncoding(tmpenc);
01871
01872
01873 if (!url.isEmpty() && url.isValid())
01874 openURL (url);
01875
01876
01877 m_buffer->setHighlight(KateHlManager::self()->nameFind(kconfig->readEntry("Highlighting")));
01878
01879 if (hlMode() > 0)
01880 hlSetByUser = true;
01881
01882
01883 config()->setIndentationMode( (uint)kconfig->readNumEntry("Indentation Mode", config()->indentationMode() ) );
01884
01885
01886 QValueList<int> marks = kconfig->readIntListEntry("Bookmarks");
01887 for( uint i = 0; i < marks.count(); i++ )
01888 addMark( marks[i], KateDocument::markType01 );
01889 }
01890
01891 void KateDocument::writeSessionConfig(KConfig *kconfig)
01892 {
01893 if ( m_url.isLocalFile() && !KGlobal::dirs()->relativeLocation("tmp", m_url.path()).startsWith("/"))
01894 return;
01895
01896 kconfig->writeEntry("URL", m_url.prettyURL() );
01897
01898
01899 kconfig->writeEntry("Encoding",encoding());
01900
01901
01902 kconfig->writeEntry("Highlighting", highlight()->name());
01903
01904 kconfig->writeEntry("Indentation Mode", config()->indentationMode() );
01905
01906
01907 QValueList<int> marks;
01908 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
01909 it.current() && it.current()->type & KTextEditor::MarkInterface::markType01;
01910 ++it )
01911 marks << it.current()->line;
01912
01913 kconfig->writeEntry( "Bookmarks", marks );
01914 }
01915
01916 void KateDocument::configDialog()
01917 {
01918 KDialogBase *kd = new KDialogBase ( KDialogBase::IconList,
01919 i18n("Configure"),
01920 KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help,
01921 KDialogBase::Ok,
01922 kapp->mainWidget() );
01923
01924 #ifndef Q_WS_WIN //TODO: reenable
01925 KWin::setIcons( kd->winId(), kapp->icon(), kapp->miniIcon() );
01926 #endif
01927
01928 QPtrList<KTextEditor::ConfigPage> editorPages;
01929
01930 for (uint i = 0; i < KTextEditor::configInterfaceExtension (this)->configPages (); i++)
01931 {
01932 QStringList path;
01933 path.clear();
01934 path << KTextEditor::configInterfaceExtension (this)->configPageName (i);
01935 QVBox *page = kd->addVBoxPage(path, KTextEditor::configInterfaceExtension (this)->configPageFullName (i),
01936 KTextEditor::configInterfaceExtension (this)->configPagePixmap(i, KIcon::SizeMedium) );
01937
01938 editorPages.append (KTextEditor::configInterfaceExtension (this)->configPage(i, page));
01939 }
01940
01941 if (kd->exec())
01942 {
01943 KateDocumentConfig::global()->configStart ();
01944 KateViewConfig::global()->configStart ();
01945 KateRendererConfig::global()->configStart ();
01946
01947 for (uint i=0; i<editorPages.count(); i++)
01948 {
01949 editorPages.at(i)->apply();
01950 }
01951
01952 KateDocumentConfig::global()->configEnd ();
01953 KateViewConfig::global()->configEnd ();
01954 KateRendererConfig::global()->configEnd ();
01955
01956 writeConfig ();
01957 }
01958
01959 delete kd;
01960 }
01961
01962 uint KateDocument::mark( uint line )
01963 {
01964 if( !m_marks[line] )
01965 return 0;
01966 return m_marks[line]->type;
01967 }
01968
01969 void KateDocument::setMark( uint line, uint markType )
01970 {
01971 clearMark( line );
01972 addMark( line, markType );
01973 }
01974
01975 void KateDocument::clearMark( uint line )
01976 {
01977 if( line > lastLine() )
01978 return;
01979
01980 if( !m_marks[line] )
01981 return;
01982
01983 KTextEditor::Mark* mark = m_marks.take( line );
01984 emit markChanged( *mark, MarkRemoved );
01985 emit marksChanged();
01986 delete mark;
01987 tagLines( line, line );
01988 repaintViews(true);
01989 }
01990
01991 void KateDocument::addMark( uint line, uint markType )
01992 {
01993 if( line > lastLine())
01994 return;
01995
01996 if( markType == 0 )
01997 return;
01998
01999 if( m_marks[line] ) {
02000 KTextEditor::Mark* mark = m_marks[line];
02001
02002
02003 markType &= ~mark->type;
02004
02005 if( markType == 0 )
02006 return;
02007
02008
02009 mark->type |= markType;
02010 } else {
02011 KTextEditor::Mark *mark = new KTextEditor::Mark;
02012 mark->line = line;
02013 mark->type = markType;
02014 m_marks.insert( line, mark );
02015 }
02016
02017
02018 KTextEditor::Mark temp;
02019 temp.line = line;
02020 temp.type = markType;
02021 emit markChanged( temp, MarkAdded );
02022
02023 emit marksChanged();
02024 tagLines( line, line );
02025 repaintViews(true);
02026 }
02027
02028 void KateDocument::removeMark( uint line, uint markType )
02029 {
02030 if( line > lastLine() )
02031 return;
02032 if( !m_marks[line] )
02033 return;
02034
02035 KTextEditor::Mark* mark = m_marks[line];
02036
02037
02038 markType &= mark->type;
02039
02040 if( markType == 0 )
02041 return;
02042
02043
02044 mark->type &= ~markType;
02045
02046
02047 KTextEditor::Mark temp;
02048 temp.line = line;
02049 temp.type = markType;
02050 emit markChanged( temp, MarkRemoved );
02051
02052 if( mark->type == 0 )
02053 m_marks.remove( line );
02054
02055 emit marksChanged();
02056 tagLines( line, line );
02057 repaintViews(true);
02058 }
02059
02060 QPtrList<KTextEditor::Mark> KateDocument::marks()
02061 {
02062 QPtrList<KTextEditor::Mark> list;
02063
02064 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02065 it.current(); ++it ) {
02066 list.append( it.current() );
02067 }
02068
02069 return list;
02070 }
02071
02072 void KateDocument::clearMarks()
02073 {
02074 for( QIntDictIterator<KTextEditor::Mark> it( m_marks );
02075 it.current(); ++it ) {
02076 KTextEditor::Mark* mark = it.current();
02077 emit markChanged( *mark, MarkRemoved );
02078 tagLines( mark->line, mark->line );
02079 }
02080
02081 m_marks.clear();
02082
02083 emit marksChanged();
02084 repaintViews(true);
02085 }
02086
02087 void KateDocument::setPixmap( MarkInterface::MarkTypes type, const QPixmap& pixmap )
02088 {
02089 m_markPixmaps.replace( type, new QPixmap( pixmap ) );
02090 }
02091
02092 void KateDocument::setDescription( MarkInterface::MarkTypes type, const QString& description )
02093 {
02094 m_markDescriptions.replace( type, new QString( description ) );
02095 }
02096
02097 QPixmap *KateDocument::markPixmap( MarkInterface::MarkTypes type )
02098 {
02099 return m_markPixmaps[type];
02100 }
02101
02102 QColor KateDocument::markColor( MarkInterface::MarkTypes type )
02103 {
02104 uint reserved = (0x1 << KTextEditor::MarkInterface::reservedMarkersCount()) - 1;
02105 if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
02106 return KateRendererConfig::global()->lineMarkerColor(type);
02107 } else {
02108 return QColor();
02109 }
02110 }
02111
02112 QString KateDocument::markDescription( MarkInterface::MarkTypes type )
02113 {
02114 if( m_markDescriptions[type] )
02115 return *m_markDescriptions[type];
02116 return QString::null;
02117 }
02118
02119 void KateDocument::setMarksUserChangable( uint markMask )
02120 {
02121 m_editableMarks = markMask;
02122 }
02123
02124 uint KateDocument::editableMarks()
02125 {
02126 return m_editableMarks;
02127 }
02128
02129
02130
02131 bool KateDocument::printDialog ()
02132 {
02133 return KatePrinter::print (this);
02134 }
02135
02136 bool KateDocument::print ()
02137 {
02138 return KatePrinter::print (this);
02139 }
02140
02141
02142
02143 QString KateDocument::mimeType()
02144 {
02145 KMimeType::Ptr result = KMimeType::defaultMimeTypePtr();
02146
02147
02148 if ( ! m_url.isEmpty() )
02149 result = KMimeType::findByURL( m_url );
02150
02151 else if ( m_url.isEmpty() || ! m_url.isLocalFile() )
02152 result = mimeTypeForContent();
02153
02154 return result->name();
02155 }
02156
02157
02158 long KateDocument::fileSize()
02159 {
02160 return 0;
02161 }
02162
02163
02164 QString KateDocument::niceFileSize()
02165 {
02166 return "UNKNOWN";
02167 }
02168
02169 KMimeType::Ptr KateDocument::mimeTypeForContent()
02170 {
02171 QByteArray buf (1024);
02172 uint bufpos = 0;
02173
02174 for (uint i=0; i < numLines(); i++)
02175 {
02176 QString line = textLine( i );
02177 uint len = line.length() + 1;
02178
02179 if (bufpos + len > 1024)
02180 len = 1024 - bufpos;
02181
02182 memcpy(&buf[bufpos], (line + "\n").latin1(), len);
02183
02184 bufpos += len;
02185
02186 if (bufpos >= 1024)
02187 break;
02188 }
02189 buf.resize( bufpos );
02190
02191 int accuracy = 0;
02192 return KMimeType::findByContent( buf, &accuracy );
02193 }
02194
02195
02196
02197
02198
02199 bool KateDocument::openURL( const KURL &url )
02200 {
02201
02202
02203 if ( !url.isValid() )
02204 return false;
02205
02206
02207 if ( !closeURL() )
02208 return false;
02209
02210
02211 m_url = url;
02212
02213 if ( m_url.isLocalFile() )
02214 {
02215
02216
02217 m_file = m_url.path();
02218
02219 emit started( 0 );
02220
02221 if (openFile())
02222 {
02223 emit completed();
02224 emit setWindowCaption( m_url.prettyURL() );
02225
02226 return true;
02227 }
02228
02229 return false;
02230 }
02231 else
02232 {
02233
02234
02235 m_bTemp = true;
02236
02237 m_tempFile = new KTempFile ();
02238 m_file = m_tempFile->name();
02239
02240 m_job = KIO::get ( url, false, isProgressInfoEnabled() );
02241
02242
02243 connect( m_job, SIGNAL( data( KIO::Job*, const QByteArray& ) ),
02244 SLOT( slotDataKate( KIO::Job*, const QByteArray& ) ) );
02245
02246 connect( m_job, SIGNAL( result( KIO::Job* ) ),
02247 SLOT( slotFinishedKate( KIO::Job* ) ) );
02248
02249 QWidget *w = widget ();
02250 if (!w && !m_views.isEmpty ())
02251 w = m_views.first();
02252
02253 if (w)
02254 m_job->setWindow (w->topLevelWidget());
02255
02256 emit started( m_job );
02257
02258 return true;
02259 }
02260 }
02261
02262 void KateDocument::slotDataKate ( KIO::Job *, const QByteArray &data )
02263 {
02264
02265
02266 if (!m_tempFile || !m_tempFile->file())
02267 return;
02268
02269 m_tempFile->file()->writeBlock (data);
02270 }
02271
02272 void KateDocument::slotFinishedKate ( KIO::Job * job )
02273 {
02274
02275
02276 if (!m_tempFile)
02277 return;
02278
02279 delete m_tempFile;
02280 m_tempFile = 0;
02281 m_job = 0;
02282
02283 if (job->error())
02284 emit canceled( job->errorString() );
02285 else
02286 {
02287 if ( openFile(job) )
02288 emit setWindowCaption( m_url.prettyURL() );
02289 emit completed();
02290 }
02291 }
02292
02293 void KateDocument::abortLoadKate()
02294 {
02295 if ( m_job )
02296 {
02297 kdDebug(13020) << "Aborting job " << m_job << endl;
02298 m_job->kill();
02299 m_job = 0;
02300 }
02301
02302 delete m_tempFile;
02303 m_tempFile = 0;
02304 }
02305
02306 bool KateDocument::openFile()
02307 {
02308 return openFile (0);
02309 }
02310
02311 bool KateDocument::openFile(KIO::Job * job)
02312 {
02313 m_loading = true;
02314
02315 activateDirWatch ();
02316
02317
02318
02319
02320 if (job)
02321 {
02322 QString metaDataCharset = job->queryMetaData("charset");
02323
02324
02325 if (!metaDataCharset.isEmpty () && (!m_config->isSetEncoding() || m_config->encoding().isEmpty()))
02326 setEncoding (metaDataCharset);
02327 }
02328
02329
02330
02331
02332 QString serviceType = m_extension->urlArgs().serviceType.simplifyWhiteSpace();
02333 int pos = serviceType.find(';');
02334 if (pos != -1)
02335 setEncoding (serviceType.mid(pos+1));
02336
02337
02338
02339 bool encodingSticky = m_encodingSticky;
02340 m_encodingSticky = m_config->isSetEncoding();
02341
02342
02343 int fileTypeFound = KateFactory::self()->fileTypeManager()->fileType (this);
02344 if ( fileTypeFound > -1 )
02345 updateFileType( fileTypeFound );
02346
02347
02348 bool success = m_buffer->openFile (m_file);
02349
02350
02351
02352 m_loading = false;
02353 if (success)
02354 {
02355
02356
02357
02358
02359
02360
02361 if (!hlSetByUser)
02362 {
02363 int hl (KateHlManager::self()->detectHighlighting (this));
02364
02365 if (hl >= 0)
02366 m_buffer->setHighlight(hl);
02367 }
02368
02369
02370 if ( fileTypeFound < 0 )
02371 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
02372
02373
02374 readDirConfig ();
02375
02376
02377 readVariables();
02378
02379
02380 createDigest( m_digest );
02381 }
02382
02383
02384
02385
02386 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
02387 {
02388 view->updateView(true);
02389 }
02390
02391
02392
02393
02394 emit fileNameChanged ();
02395
02396
02397
02398
02399 setDocName (QString::null);
02400
02401
02402
02403
02404 if (m_modOnHd)
02405 {
02406 m_modOnHd = false;
02407 m_modOnHdReason = 0;
02408 emit modifiedOnDisc (this, m_modOnHd, 0);
02409 }
02410
02411
02412
02413
02414 if (s_openErrorDialogsActivated)
02415 {
02416 if (!success && m_buffer->loadingBorked())
02417 KMessageBox::error (widget(), i18n ("The file %1 could not be loaded completely, as there is not enough temporary disk storage for it.").arg(m_url.url()));
02418 else if (!success)
02419 KMessageBox::error (widget(), 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.").arg(m_url.url()));
02420 }
02421
02422
02423 if (m_buffer->binary())
02424 {
02425
02426 setReadWrite( false );
02427
02428 KMessageBox::information (widget()
02429 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
02430 , i18n ("Binary File Opened")
02431 , "Binary File Opened Warning");
02432 }
02433
02434 m_encodingSticky = encodingSticky;
02435
02436
02437
02438
02439 return success;
02440 }
02441
02442 bool KateDocument::save()
02443 {
02444 bool l ( url().isLocalFile() );
02445
02446 if ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles )
02447 || ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
02448 {
02449 KURL u( url() );
02450 u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
02451
02452 kdDebug () << "backup src file name: " << url() << endl;
02453 kdDebug () << "backup dst file name: " << u << endl;
02454
02455
02456 mode_t perms = 0600;
02457 KIO::UDSEntry fentry;
02458 if (KIO::NetAccess::stat (url(), fentry, kapp->mainWidget()))
02459 {
02460 kdDebug () << "stating succesfull: " << url() << endl;
02461 KFileItem item (fentry, url());
02462 perms = item.permissions();
02463 }
02464
02465
02466
02467 if ( (!KIO::NetAccess::exists( u, false, kapp->mainWidget() ) || KIO::NetAccess::del( u, kapp->mainWidget() ))
02468 && KIO::NetAccess::file_copy( url(), u, perms, true, false, kapp->mainWidget() ) )
02469 {
02470 kdDebug(13020)<<"backing up successfull ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02471 }
02472 else
02473 {
02474 kdDebug(13020)<<"backing up failed ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02475
02476 }
02477 }
02478
02479 return KParts::ReadWritePart::save();
02480 }
02481
02482 bool KateDocument::saveFile()
02483 {
02484
02485
02486
02487 if (m_buffer->loadingBorked() && (KMessageBox::warningContinueCancel(widget(),
02488 i18n("This file could not be loaded correctly due to lack of temporary disk space. Saving it could cause data loss.\n\nDo you really want to save it?"),i18n("Possible Data Loss"),i18n("Save Nevertheless")) != KMessageBox::Continue))
02489 return false;
02490
02491
02492
02493
02494 if (m_buffer->binary() && (KMessageBox::warningContinueCancel (widget()
02495 , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
02496 , i18n ("Trying to Save Binary File")
02497 , i18n("Save Nevertheless"), "Binary File Save Warning") != KMessageBox::Continue))
02498 return false;
02499
02500 if ( !url().isEmpty() )
02501 {
02502 if (s_fileChangedDialogsActivated && m_modOnHd)
02503 {
02504 QString str = reasonedMOHString() + "\n\n";
02505
02506 if (!isModified())
02507 {
02508 if (KMessageBox::warningContinueCancel(0,
02509 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"),i18n("Save Nevertheless")) != KMessageBox::Continue)
02510 return false;
02511 }
02512 else
02513 {
02514 if (KMessageBox::warningContinueCancel(0,
02515 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"),i18n("Save Nevertheless")) != KMessageBox::Continue)
02516 return false;
02517 }
02518 }
02519 }
02520
02521
02522
02523
02524 if (!m_buffer->canEncode ()
02525 && (KMessageBox::warningContinueCancel(0,
02526 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"),i18n("Save Nevertheless")) != KMessageBox::Continue))
02527 {
02528 return false;
02529 }
02530
02531
02532 deactivateDirWatch ();
02533
02534
02535
02536
02537 bool success = m_buffer->saveFile (m_file);
02538
02539
02540 createDigest( m_digest );
02541
02542
02543 activateDirWatch ();
02544
02545
02546
02547
02548 if (success)
02549 {
02550
02551 if (!hlSetByUser)
02552 {
02553 int hl (KateHlManager::self()->detectHighlighting (this));
02554
02555 if (hl >= 0)
02556 m_buffer->setHighlight(hl);
02557 }
02558
02559
02560 readVariables();
02561 }
02562
02563
02564
02565
02566 if (success && m_modOnHd)
02567 {
02568 m_modOnHd = false;
02569 m_modOnHdReason = 0;
02570 emit modifiedOnDisc (this, m_modOnHd, 0);
02571 }
02572
02573
02574
02575
02576 if (!success)
02577 KMessageBox::error (widget(), 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.").arg(m_url.url()));
02578
02579
02580
02581
02582 return success;
02583 }
02584
02585 bool KateDocument::saveAs( const KURL &u )
02586 {
02587 QString oldDir = url().directory();
02588
02589 if ( KParts::ReadWritePart::saveAs( u ) )
02590 {
02591
02592 setDocName( QString::null );
02593
02594 if ( u.directory() != oldDir )
02595 readDirConfig();
02596
02597 emit fileNameChanged();
02598 emit nameChanged((Kate::Document *) this);
02599
02600 return true;
02601 }
02602
02603 return false;
02604 }
02605
02606 void KateDocument::readDirConfig ()
02607 {
02608 int depth = config()->searchDirConfigDepth ();
02609
02610 if (m_url.isLocalFile() && (depth > -1))
02611 {
02612 QString currentDir = QFileInfo (m_file).dirPath();
02613
02614
02615 while (depth > -1)
02616 {
02617 kdDebug (13020) << "search for config file in path: " << currentDir << endl;
02618
02619
02620 QFile f (currentDir + "/.kateconfig");
02621
02622 if (f.open (IO_ReadOnly))
02623 {
02624 QTextStream stream (&f);
02625
02626 uint linesRead = 0;
02627 QString line = stream.readLine();
02628 while ((linesRead < 32) && !line.isNull())
02629 {
02630 readVariableLine( line );
02631
02632 line = stream.readLine();
02633
02634 linesRead++;
02635 }
02636
02637 break;
02638 }
02639
02640 QString newDir = QFileInfo (currentDir).dirPath();
02641
02642
02643 if (currentDir == newDir)
02644 break;
02645
02646 currentDir = newDir;
02647 --depth;
02648 }
02649 }
02650 }
02651
02652 void KateDocument::activateDirWatch ()
02653 {
02654
02655 if (m_file == m_dirWatchFile)
02656 return;
02657
02658
02659 deactivateDirWatch ();
02660
02661
02662 if (m_url.isLocalFile() && !m_file.isEmpty())
02663 {
02664 KateFactory::self()->dirWatch ()->addFile (m_file);
02665 m_dirWatchFile = m_file;
02666 }
02667 }
02668
02669 void KateDocument::deactivateDirWatch ()
02670 {
02671 if (!m_dirWatchFile.isEmpty())
02672 KateFactory::self()->dirWatch ()->removeFile (m_dirWatchFile);
02673
02674 m_dirWatchFile = QString::null;
02675 }
02676
02677 bool KateDocument::closeURL()
02678 {
02679 abortLoadKate();
02680
02681
02682
02683
02684 if ( !m_reloading && !url().isEmpty() )
02685 {
02686 if (s_fileChangedDialogsActivated && m_modOnHd)
02687 {
02688 if (!(KMessageBox::warningContinueCancel(
02689 widget(),
02690 reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur."),
02691 i18n("Possible Data Loss"), i18n("Close Nevertheless"),
02692 QString("kate_close_modonhd_%1").arg( m_modOnHdReason ) ) == KMessageBox::Continue))
02693 return false;
02694 }
02695 }
02696
02697
02698
02699
02700 if (!KParts::ReadWritePart::closeURL ())
02701 return false;
02702
02703
02704 deactivateDirWatch ();
02705
02706
02707
02708
02709 m_url = KURL ();
02710 m_file = QString::null;
02711
02712
02713 if (m_modOnHd)
02714 {
02715 m_modOnHd = false;
02716 m_modOnHdReason = 0;
02717 emit modifiedOnDisc (this, m_modOnHd, 0);
02718 }
02719
02720
02721 m_buffer->clear();
02722
02723
02724 clearMarks ();
02725
02726
02727 clearUndo();
02728 clearRedo();
02729
02730
02731 setModified(false);
02732
02733
02734 m_buffer->setHighlight(0);
02735
02736
02737 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
02738 {
02739
02740
02741 view->setCursorPositionInternal(0, 0, 1, false);
02742 view->clearSelection();
02743 view->updateView(true);
02744 }
02745
02746
02747 emit fileNameChanged ();
02748
02749
02750 setDocName (QString::null);
02751
02752
02753 return true;
02754 }
02755
02756 void KateDocument::setReadWrite( bool rw )
02757 {
02758 if (isReadWrite() != rw)
02759 {
02760 KParts::ReadWritePart::setReadWrite (rw);
02761
02762 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
02763 {
02764 view->slotUpdate();
02765 view->slotReadWriteChanged ();
02766 }
02767 }
02768 }
02769
02770 void KateDocument::setModified(bool m) {
02771
02772 if (isModified() != m) {
02773 KParts::ReadWritePart::setModified (m);
02774
02775 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
02776 {
02777 view->slotUpdate();
02778 }
02779
02780 emit modifiedChanged ();
02781 emit modStateChanged ((Kate::Document *)this);
02782 }
02783 if ( m == false && ! undoItems.isEmpty() )
02784 {
02785 lastUndoGroupWhenSaved = undoItems.last();
02786 }
02787
02788 if ( m == false ) docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
02789 }
02790
02791
02792
02793
02794 void KateDocument::makeAttribs(bool needInvalidate)
02795 {
02796 for (uint z = 0; z < m_views.count(); z++)
02797 m_views.at(z)->renderer()->updateAttributes ();
02798
02799 if (needInvalidate)
02800 m_buffer->invalidateHighlighting();
02801
02802 tagAll ();
02803 }
02804
02805
02806 void KateDocument::internalHlChanged()
02807 {
02808 makeAttribs();
02809 }
02810
02811 void KateDocument::addView(KTextEditor::View *view) {
02812 if (!view)
02813 return;
02814
02815 m_views.append( (KateView *) view );
02816 m_textEditViews.append( view );
02817
02818
02819 const KateFileType *t = 0;
02820 if ((m_fileType > -1) && (t = KateFactory::self()->fileTypeManager()->fileType(m_fileType)))
02821 readVariableLine (t->varLine, true);
02822
02823
02824 readVariables (true);
02825
02826 m_activeView = (KateView *) view;
02827 }
02828
02829 void KateDocument::removeView(KTextEditor::View *view) {
02830 if (!view)
02831 return;
02832
02833 if (m_activeView == view)
02834 m_activeView = 0L;
02835
02836 m_views.removeRef( (KateView *) view );
02837 m_textEditViews.removeRef( view );
02838 }
02839
02840 void KateDocument::addSuperCursor(KateSuperCursor *cursor, bool privateC) {
02841 if (!cursor)
02842 return;
02843
02844 m_superCursors.append( cursor );
02845
02846 if (!privateC)
02847 myCursors.append( cursor );
02848 }
02849
02850 void KateDocument::removeSuperCursor(KateSuperCursor *cursor, bool privateC) {
02851 if (!cursor)
02852 return;
02853
02854 if (!privateC)
02855 myCursors.removeRef( cursor );
02856
02857 m_superCursors.removeRef( cursor );
02858 }
02859
02860 bool KateDocument::ownedView(KateView *view) {
02861
02862 return (m_views.containsRef(view) > 0);
02863 }
02864
02865 bool KateDocument::isLastView(int numViews) {
02866 return ((int) m_views.count() == numViews);
02867 }
02868
02869 uint KateDocument::currentColumn( const KateTextCursor& cursor )
02870 {
02871 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
02872
02873 if (textLine)
02874 return textLine->cursorX(cursor.col(), config()->tabWidth());
02875 else
02876 return 0;
02877 }
02878
02879 bool KateDocument::typeChars ( KateView *view, const QString &chars )
02880 {
02881 KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorLine ());
02882
02883 if (!textLine)
02884 return false;
02885
02886 bool bracketInserted = false;
02887 QString buf;
02888 QChar c;
02889
02890 for( uint z = 0; z < chars.length(); z++ )
02891 {
02892 QChar ch = c = chars[z];
02893 if (ch.isPrint() || ch == '\t')
02894 {
02895 buf.append (ch);
02896
02897 if (!bracketInserted && (config()->configFlags() & KateDocument::cfAutoBrackets))
02898 {
02899 QChar end_ch;
02900 bool complete = true;
02901 QChar prevChar = textLine->getChar(view->cursorColumnReal()-1);
02902 QChar nextChar = textLine->getChar(view->cursorColumnReal());
02903 switch(ch) {
02904 case '(': end_ch = ')'; break;
02905 case '[': end_ch = ']'; break;
02906 case '{': end_ch = '}'; break;
02907 case '\'':end_ch = '\'';break;
02908 case '"': end_ch = '"'; break;
02909 default: complete = false;
02910 }
02911 if (complete)
02912 {
02913 if (view->hasSelection())
02914 {
02915 buf.append (view->selection());
02916 buf.append (end_ch);
02917 bracketInserted = true;
02918 }
02919 else
02920 {
02921 if ( ( (ch == '\'' || ch == '"') &&
02922 (prevChar.isLetterOrNumber() || prevChar == ch) )
02923 || nextChar.isLetterOrNumber()
02924 || (nextChar == end_ch && prevChar != ch) )
02925 {
02926 kdDebug(13020) << "AutoBracket refused before: " << nextChar << "\n";
02927 }
02928 else
02929 {
02930 buf.append (end_ch);
02931 bracketInserted = true;
02932 }
02933 }
02934 }
02935 }
02936 }
02937 }
02938
02939 if (buf.isEmpty())
02940 return false;
02941
02942 editStart ();
02943
02944 if (!view->config()->persistentSelection() && view->hasSelection() )
02945 view->removeSelectedText();
02946
02947 int oldLine = view->cursorLine ();
02948 int oldCol = view->cursorColumnReal ();
02949
02950
02951 if (config()->configFlags() & KateDocument::cfOvr)
02952 removeText (view->cursorLine(), view->cursorColumnReal(), view->cursorLine(), kMin( view->cursorColumnReal()+buf.length(), textLine->length() ) );
02953
02954 insertText (view->cursorLine(), view->cursorColumnReal(), buf);
02955 m_indenter->processChar(c);
02956
02957 editEnd ();
02958
02959 if (bracketInserted)
02960 view->setCursorPositionInternal (view->cursorLine(), view->cursorColumnReal()-1);
02961
02962 emit charactersInteractivelyInserted (oldLine, oldCol, chars);
02963
02964 return true;
02965 }
02966
02967 void KateDocument::newLine( KateTextCursor& c, KateViewInternal *v )
02968 {
02969 editStart();
02970
02971 if( !v->view()->config()->persistentSelection() && v->view()->hasSelection() )
02972 v->view()->removeSelectedText();
02973
02974
02975 c = v->getCursor ();
02976
02977 if (c.line() > (int)lastLine())
02978 c.setLine(lastLine());
02979
02980 if ( c.line() < 0 )
02981 c.setLine( 0 );
02982
02983 uint ln = c.line();
02984
02985 KateTextLine::Ptr textLine = kateTextLine(c.line());
02986
02987 if (c.col() > (int)textLine->length())
02988 c.setCol(textLine->length());
02989
02990 if (m_indenter->canProcessNewLine ())
02991 {
02992 int pos = textLine->firstChar();
02993
02994
02995 if (pos < 0)
02996 pos = textLine->length();
02997
02998 if (c.col() < pos)
02999 c.setCol(pos);
03000
03001 editWrapLine (c.line(), c.col());
03002
03003 KateDocCursor cursor (c.line() + 1, pos, this);
03004 m_indenter->processNewline(cursor, true);
03005
03006 c.setPos(cursor);
03007 }
03008 else
03009 {
03010 editWrapLine (c.line(), c.col());
03011 c.setPos(c.line() + 1, 0);
03012 }
03013
03014 removeTrailingSpace( ln );
03015
03016 editEnd();
03017 }
03018
03019 void KateDocument::transpose( const KateTextCursor& cursor)
03020 {
03021 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03022
03023 if (!textLine || (textLine->length() < 2))
03024 return;
03025
03026 uint col = cursor.col();
03027
03028 if (col > 0)
03029 col--;
03030
03031 if ((textLine->length() - col) < 2)
03032 return;
03033
03034 uint line = cursor.line();
03035 QString s;
03036
03037
03038
03039 s.append (textLine->getChar(col+1));
03040 s.append (textLine->getChar(col));
03041
03042
03043
03044 editStart ();
03045 editRemoveText (line, col, 2);
03046 editInsertText (line, col, s);
03047 editEnd ();
03048 }
03049
03050 void KateDocument::backspace( KateView *view, const KateTextCursor& c )
03051 {
03052 if ( !view->config()->persistentSelection() && view->hasSelection() ) {
03053 view->removeSelectedText();
03054 return;
03055 }
03056
03057 uint col = kMax( c.col(), 0 );
03058 uint line = kMax( c.line(), 0 );
03059
03060 if ((col == 0) && (line == 0))
03061 return;
03062
03063 int complement = 0;
03064 if (col > 0)
03065 {
03066 if (config()->configFlags() & KateDocument::cfAutoBrackets)
03067 {
03068
03069 KateTextLine::Ptr tl = m_buffer->plainLine(line);
03070 if(!tl) return;
03071 QChar prevChar = tl->getChar(col-1);
03072 QChar nextChar = tl->getChar(col);
03073
03074 if ( (prevChar == '"' && nextChar == '"') ||
03075 (prevChar == '\'' && nextChar == '\'') ||
03076 (prevChar == '(' && nextChar == ')') ||
03077 (prevChar == '[' && nextChar == ']') ||
03078 (prevChar == '{' && nextChar == '}') )
03079 {
03080 complement = 1;
03081 }
03082 }
03083 if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
03084 {
03085
03086
03087 removeText(line, col-1, line, col+complement);
03088 }
03089 else
03090 {
03091
03092 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03093
03094
03095 if (!textLine)
03096 return;
03097
03098 int colX = textLine->cursorX(col, config()->tabWidth());
03099 int pos = textLine->firstChar();
03100 if (pos > 0)
03101 pos = textLine->cursorX(pos, config()->tabWidth());
03102
03103 if (pos < 0 || pos >= (int)colX)
03104 {
03105
03106 indent( view, line, -1);
03107 }
03108 else
03109 removeText(line, col-1, line, col+complement);
03110 }
03111 }
03112 else
03113 {
03114
03115 if (line >= 1)
03116 {
03117 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
03118
03119
03120 if (!textLine)
03121 return;
03122
03123 if (config()->wordWrap() && textLine->endingWith(QString::fromLatin1(" ")))
03124 {
03125
03126 removeText (line-1, textLine->length()-1, line, 0);
03127 }
03128 else
03129 removeText (line-1, textLine->length(), line, 0);
03130 }
03131 }
03132
03133 emit backspacePressed();
03134 }
03135
03136 void KateDocument::del( KateView *view, const KateTextCursor& c )
03137 {
03138 if ( !view->config()->persistentSelection() && view->hasSelection() ) {
03139 view->removeSelectedText();
03140 return;
03141 }
03142
03143 if( c.col() < (int) m_buffer->plainLine(c.line())->length())
03144 {
03145 removeText(c.line(), c.col(), c.line(), c.col()+1);
03146 }
03147 else if ( (uint)c.line() < lastLine() )
03148 {
03149 removeText(c.line(), c.col(), c.line()+1, 0);
03150 }
03151 }
03152
03153 void KateDocument::paste ( KateView* view )
03154 {
03155 QString s = QApplication::clipboard()->text();
03156
03157 if (s.isEmpty())
03158 return;
03159
03160 uint lines = s.contains (QChar ('\n'));
03161
03162 m_undoDontMerge = true;
03163
03164 editStart ();
03165
03166 if (!view->config()->persistentSelection() && view->hasSelection() )
03167 view->removeSelectedText();
03168
03169 uint line = view->cursorLine ();
03170 uint column = view->cursorColumnReal ();
03171
03172 insertText ( line, column, s, view->blockSelectionMode() );
03173
03174 editEnd();
03175
03176
03177
03178
03179 if (view->blockSelectionMode())
03180 view->setCursorPositionInternal (line+lines, column);
03181
03182 if (m_indenter->canProcessLine()
03183 && config()->configFlags() & KateDocumentConfig::cfIndentPastedText)
03184 {
03185 editStart();
03186
03187 KateDocCursor begin(line, 0, this);
03188 KateDocCursor end(line + lines, 0, this);
03189
03190 m_indenter->processSection (begin, end);
03191
03192 editEnd();
03193 }
03194
03195 if (!view->blockSelectionMode()) emit charactersSemiInteractivelyInserted (line, column, s);
03196 m_undoDontMerge = true;
03197 }
03198
03199 void KateDocument::insertIndentChars ( KateView *view )
03200 {
03201 editStart ();
03202
03203 QString s;
03204 if (config()->configFlags() & KateDocument::cfSpaceIndent)
03205 {
03206 int width = config()->indentationWidth();
03207 s.fill (' ', width - (view->cursorColumnReal() % width));
03208 }
03209 else
03210 s.append ('\t');
03211
03212 insertText (view->cursorLine(), view->cursorColumnReal(), s);
03213
03214 editEnd ();
03215 }
03216
03217 void KateDocument::indent ( KateView *v, uint line, int change)
03218 {
03219 editStart ();
03220
03221 if (!hasSelection())
03222 {
03223
03224 optimizeLeadingSpace(line, config()->configFlags(), change);
03225 }
03226 else
03227 {
03228 int sl = v->selStartLine();
03229 int el = v->selEndLine();
03230 int ec = v->selEndCol();
03231
03232 if ((ec == 0) && ((el-1) >= 0))
03233 {
03234 el--;
03235 }
03236
03237 if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
03238
03239
03240 int adjustedChange = -change;
03241
03242 for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
03243 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03244 int firstChar = textLine->firstChar();
03245 if (firstChar >= 0 && (v->lineSelected(line) || v->lineHasSelected(line))) {
03246 int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
03247 if (maxUnindent < adjustedChange)
03248 adjustedChange = maxUnindent;
03249 }
03250 }
03251
03252 change = -adjustedChange;
03253 }
03254
03255 const bool rts = config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn;
03256 for (line = sl; (int) line <= el; line++) {
03257 if ((v->lineSelected(line) || v->lineHasSelected(line))
03258 && (!rts || lineLength(line) > 0)) {
03259 optimizeLeadingSpace(line, config()->configFlags(), change);
03260 }
03261 }
03262 }
03263
03264 editEnd ();
03265 }
03266
03267 void KateDocument::align(KateView *view, uint line)
03268 {
03269 if (m_indenter->canProcessLine())
03270 {
03271 editStart ();
03272
03273 if (!view->hasSelection())
03274 {
03275 KateDocCursor curLine(line, 0, this);
03276 m_indenter->processLine (curLine);
03277 editEnd ();
03278 activeView()->setCursorPosition (line, curLine.col());
03279 }
03280 else
03281 {
03282 m_indenter->processSection (view->selStart(), view->selEnd());
03283 editEnd ();
03284 }
03285 }
03286 }
03287
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297 void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
03298 {
03299 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03300
03301 int first_char = textline->firstChar();
03302
03303 int w = 0;
03304 if (flags & KateDocument::cfSpaceIndent)
03305 w = config()->indentationWidth();
03306 else
03307 w = config()->tabWidth();
03308
03309 if (first_char < 0)
03310 first_char = textline->length();
03311
03312 int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
03313 if (space < 0)
03314 space = 0;
03315
03316 if (!(flags & KateDocument::cfKeepExtraSpaces))
03317 {
03318 uint extra = space % w;
03319
03320 space -= extra;
03321 if (extra && change < 0) {
03322
03323 space += w;
03324 }
03325 }
03326
03327
03328 replaceWithOptimizedSpace(line, first_char, space, flags);
03329 }
03330
03331 void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
03332 {
03333 uint length;
03334 QString new_space;
03335
03336 if (flags & KateDocument::cfSpaceIndent && ! (flags & KateDocumentConfig::cfMixedIndent) ) {
03337 length = space;
03338 new_space.fill(' ', length);
03339 }
03340 else {
03341 length = space / config()->tabWidth();
03342 new_space.fill('\t', length);
03343
03344 QString extra_space;
03345 extra_space.fill(' ', space % config()->tabWidth());
03346 length += space % config()->tabWidth();
03347 new_space += extra_space;
03348 }
03349
03350 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03351 uint change_from;
03352 for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
03353 if (textline->getChar(change_from) != new_space[change_from])
03354 break;
03355 }
03356
03357 editStart();
03358
03359 if (change_from < upto_column)
03360 removeText(line, change_from, line, upto_column);
03361
03362 if (change_from < length)
03363 insertText(line, change_from, new_space.right(length - change_from));
03364
03365 editEnd();
03366 }
03367
03368
03369
03370
03371
03372 bool KateDocument::removeStringFromBegining(int line, QString &str)
03373 {
03374 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03375
03376 int index = 0;
03377 bool there = false;
03378
03379 if (textline->startingWith(str))
03380 there = true;
03381 else
03382 {
03383 index = textline->firstChar ();
03384
03385 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03386 there = true;
03387 }
03388
03389 if (there)
03390 {
03391
03392 removeText (line, index, line, index+str.length());
03393 }
03394
03395 return there;
03396 }
03397
03398
03399
03400
03401
03402 bool KateDocument::removeStringFromEnd(int line, QString &str)
03403 {
03404 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03405
03406 int index = 0;
03407 bool there = false;
03408
03409 if(textline->endingWith(str))
03410 {
03411 index = textline->length() - str.length();
03412 there = true;
03413 }
03414 else
03415 {
03416 index = textline->lastChar ()-str.length()+1;
03417
03418 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03419 there = true;
03420 }
03421
03422 if (there)
03423 {
03424
03425 removeText (line, index, line, index+str.length());
03426 }
03427
03428 return there;
03429 }
03430
03431
03432
03433
03434
03435 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
03436 {
03437 if (highlight()->getCommentSingleLinePosition(attrib)==KateHighlighting::CSLPosColumn0)
03438 {
03439 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03440 insertText (line, 0, commentLineMark);
03441 }
03442 else
03443 {
03444 QString commentLineMark=highlight()->getCommentSingleLineStart(attrib);
03445 KateTextLine::Ptr l = m_buffer->line(line);
03446 int pos=l->firstChar();
03447 if (pos >=0)
03448 insertText(line,pos,commentLineMark);
03449 }
03450 }
03451
03452
03453
03454
03455
03456 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
03457 {
03458 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03459 QString longCommentMark = shortCommentMark + " ";
03460
03461 editStart();
03462
03463
03464 bool removed = (removeStringFromBegining(line, longCommentMark)
03465 || removeStringFromBegining(line, shortCommentMark));
03466
03467 editEnd();
03468
03469 return removed;
03470 }
03471
03472
03473
03474
03475
03476 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
03477 {
03478 QString startCommentMark = highlight()->getCommentStart( attrib ) + " ";
03479 QString stopCommentMark = " " + highlight()->getCommentEnd( attrib );
03480
03481 editStart();
03482
03483
03484 insertText (line, 0, startCommentMark);
03485
03486
03487 int col = m_buffer->plainLine(line)->length();
03488
03489
03490 insertText (line, col, stopCommentMark);
03491
03492 editEnd();
03493 }
03494
03495
03496
03497
03498
03499 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
03500 {
03501 QString shortStartCommentMark = highlight()->getCommentStart( attrib );
03502 QString longStartCommentMark = shortStartCommentMark + " ";
03503 QString shortStopCommentMark = highlight()->getCommentEnd( attrib );
03504 QString longStopCommentMark = " " + shortStopCommentMark;
03505
03506 editStart();
03507
03508 #ifdef __GNUC__
03509 #warning "that's a bad idea, can lead to stray endings, FIXME"
03510 #endif
03511
03512 bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
03513 || removeStringFromBegining(line, shortStartCommentMark));
03514
03515 bool removedStop = false;
03516 if (removedStart)
03517 {
03518
03519 removedStop = (removeStringFromEnd(line, longStopCommentMark)
03520 || removeStringFromEnd(line, shortStopCommentMark));
03521 }
03522
03523 editEnd();
03524
03525 return (removedStart || removedStop);
03526 }
03527
03528
03529
03530
03531
03532
03533 void KateDocument::addStartStopCommentToSelection( KateView *view, int attrib )
03534 {
03535 QString startComment = highlight()->getCommentStart( attrib );
03536 QString endComment = highlight()->getCommentEnd( attrib );
03537
03538 int sl = view->selStartLine();
03539 int el = view->selEndLine();
03540 int sc = view->selStartCol();
03541 int ec = view->selEndCol();
03542
03543 if ((ec == 0) && ((el-1) >= 0))
03544 {
03545 el--;
03546 ec = m_buffer->plainLine (el)->length();
03547 }
03548
03549 editStart();
03550
03551 insertText (el, ec, endComment);
03552 insertText (sl, sc, startComment);
03553
03554 editEnd ();
03555
03556
03557 ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
03558 view->setSelection(sl, sc, el, ec);
03559 }
03560
03561
03562
03563
03564
03565 void KateDocument::addStartLineCommentToSelection( KateView *view, int attrib )
03566 {
03567 QString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
03568
03569 int sl = view->selStartLine();
03570 int el = view->selEndLine();
03571
03572 if ((view->selEndCol() == 0) && ((el-1) >= 0))
03573 {
03574 el--;
03575 }
03576
03577 editStart();
03578
03579
03580 for (int z = el; z >= sl; z--) {
03581
03582 addStartLineCommentToSingleLine(z, attrib );
03583 }
03584
03585 editEnd ();
03586
03587
03588
03589 KateDocCursor end (view->selEnd());
03590 end.setCol(view->selEndCol() + ((el == view->selEndLine()) ? commentLineMark.length() : 0) );
03591
03592 view->setSelection(view->selStartLine(), 0, end.line(), end.col());
03593 }
03594
03595 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
03596 {
03597 for(; line < (int)m_buffer->count(); line++) {
03598 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03599
03600 if (!textLine)
03601 break;
03602
03603 col = textLine->nextNonSpaceChar(col);
03604 if(col != -1)
03605 return true;
03606 col = 0;
03607 }
03608
03609 line = -1;
03610 col = -1;
03611 return false;
03612 }
03613
03614 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
03615 {
03616 while(true)
03617 {
03618 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03619
03620 if (!textLine)
03621 break;
03622
03623 col = textLine->previousNonSpaceChar(col);
03624 if(col != -1) return true;
03625 if(line == 0) return false;
03626 --line;
03627 col = textLine->length();
03628 }
03629
03630 line = -1;
03631 col = -1;
03632 return false;
03633 }
03634
03635
03636
03637
03638
03639 bool KateDocument::removeStartStopCommentFromSelection( KateView *view, int attrib )
03640 {
03641 QString startComment = highlight()->getCommentStart( attrib );
03642 QString endComment = highlight()->getCommentEnd( attrib );
03643
03644 int sl = kMax<int> (0, view->selStartLine());
03645 int el = kMin<int> (view->selEndLine(), lastLine());
03646 int sc = view->selStartCol();
03647 int ec = view->selEndCol();
03648
03649
03650 if (ec != 0) {
03651 ec--;
03652 } else {
03653 if (el > 0) {
03654 el--;
03655 ec = m_buffer->plainLine(el)->length() - 1;
03656 }
03657 }
03658
03659 int startCommentLen = startComment.length();
03660 int endCommentLen = endComment.length();
03661
03662
03663
03664 bool remove = nextNonSpaceCharPos(sl, sc)
03665 && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
03666 && previousNonSpaceCharPos(el, ec)
03667 && ( (ec - endCommentLen + 1) >= 0 )
03668 && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
03669
03670 if (remove) {
03671 editStart();
03672
03673 removeText (el, ec - endCommentLen + 1, el, ec + 1);
03674 removeText (sl, sc, sl, sc + startCommentLen);
03675
03676 editEnd ();
03677
03678 }
03679
03680 return remove;
03681 }
03682
03683 bool KateDocument::removeStartStopCommentFromRegion(const KateTextCursor &start,const KateTextCursor &end,int attrib)
03684 {
03685 QString startComment = highlight()->getCommentStart( attrib );
03686 QString endComment = highlight()->getCommentEnd( attrib );
03687 int startCommentLen = startComment.length();
03688 int endCommentLen = endComment.length();
03689
03690 bool remove = m_buffer->plainLine(start.line())->stringAtPos(start.col(), startComment)
03691 && ( (end.col() - endCommentLen ) >= 0 )
03692 && m_buffer->plainLine(end.line())->stringAtPos(end.col() - endCommentLen , endComment);
03693 if (remove) {
03694 editStart();
03695 removeText(end.line(),end.col()-endCommentLen,end.line(),end.col());
03696 removeText(start.line(),start.col(),start.line(),start.col()+startCommentLen);
03697 editEnd();
03698 }
03699 return remove;
03700 }
03701
03702
03703
03704
03705
03706 bool KateDocument::removeStartLineCommentFromSelection( KateView *view, int attrib )
03707 {
03708 QString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
03709 QString longCommentMark = shortCommentMark + " ";
03710
03711 int sl = view->selStartLine();
03712 int el = view->selEndLine();
03713
03714 if ((view->selEndCol() == 0) && ((el-1) >= 0))
03715 {
03716 el--;
03717 }
03718
03719
03720 int removeLength = 0;
03721 if (m_buffer->plainLine(el)->startingWith(longCommentMark))
03722 removeLength = longCommentMark.length();
03723 else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
03724 removeLength = shortCommentMark.length();
03725
03726 bool removed = false;
03727
03728 editStart();
03729
03730
03731 for (int z = el; z >= sl; z--)
03732 {
03733
03734 removed = (removeStringFromBegining(z, longCommentMark)
03735 || removeStringFromBegining(z, shortCommentMark)
03736 || removed);
03737 }
03738
03739 editEnd();
03740
03741 return removed;
03742 }
03743
03744
03745
03746
03747
03748 void KateDocument::comment( KateView *v, uint line,uint column, int change)
03749 {
03750
03751
03752
03753
03754 bool hassel = v->hasSelection();
03755 int startAttrib, endAttrib;
03756 if ( hassel )
03757 {
03758 KateTextLine::Ptr ln = kateTextLine( v->selStartLine() );
03759 int l = v->selStartLine(), c = v->selStartCol();
03760 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03761
03762 ln = kateTextLine( v->selEndLine() );
03763 l = v->selEndLine(), c = v->selEndCol();
03764 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03765 }
03766 else
03767 {
03768 KateTextLine::Ptr ln = kateTextLine( line );
03769 if ( ln->length() )
03770 {
03771 startAttrib = ln->attribute( ln->firstChar() );
03772 endAttrib = ln->attribute( ln->lastChar() );
03773 }
03774 else
03775 {
03776 int l = line, c = 0;
03777 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
03778 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
03779 else
03780 startAttrib = endAttrib = 0;
03781 }
03782 }
03783
03784 if ( ! highlight()->canComment( startAttrib, endAttrib ) )
03785 {
03786 kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
03787 return;
03788 }
03789
03790 bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
03791 bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
03792 && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
03793
03794 bool removed = false;
03795
03796 if (change > 0)
03797 {
03798 if ( !hassel )
03799 {
03800 if ( hasStartLineCommentMark )
03801 addStartLineCommentToSingleLine( line, startAttrib );
03802 else if ( hasStartStopCommentMark )
03803 addStartStopCommentToSingleLine( line, startAttrib );
03804 }
03805 else
03806 {
03807
03808
03809
03810
03811
03812
03813
03814 if ( hasStartStopCommentMark &&
03815 ( !hasStartLineCommentMark || (
03816 ( v->selStartCol() > m_buffer->plainLine( v->selStartLine() )->firstChar() ) ||
03817 ( v->selEndCol() < ((int)m_buffer->plainLine( v->selEndLine() )->length()) )
03818 ) ) )
03819 addStartStopCommentToSelection( v, startAttrib );
03820 else if ( hasStartLineCommentMark )
03821 addStartLineCommentToSelection( v, startAttrib );
03822 }
03823 }
03824 else
03825 {
03826 if ( !hassel )
03827 {
03828 removed = ( hasStartLineCommentMark
03829 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
03830 || ( hasStartStopCommentMark
03831 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
03832 if ((!removed) && foldingTree()) {
03833 kdDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)"<<endl;
03834 int commentRegion=(highlight()->commentRegion(startAttrib));
03835 if (commentRegion){
03836 KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
03837 if (n) {
03838 KateTextCursor start,end;
03839 if ((n->nodeType()==commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
03840 kdDebug(13020)<<"Enclosing region found:"<<start.col()<<"/"<<start.line()<<"-"<<end.col()<<"/"<<end.line()<<endl;
03841 removeStartStopCommentFromRegion(start,end,startAttrib);
03842 } else {
03843 kdDebug(13020)<<"Enclosing region found, but not valid"<<endl;
03844 kdDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion<<endl;
03845 }
03846
03847 } else kdDebug(13020)<<"No enclosing region found"<<endl;
03848 } else kdDebug(13020)<<"No comment region specified for current hl"<<endl;
03849 }
03850 }
03851 else
03852 {
03853
03854 removed = ( hasStartLineCommentMark
03855 && removeStartLineCommentFromSelection( v, startAttrib ) )
03856 || ( hasStartStopCommentMark
03857 && removeStartStopCommentFromSelection( v, startAttrib ) );
03858 }
03859 }
03860 }
03861
03862 void KateDocument::transform( KateView *v, const KateTextCursor &c,
03863 KateDocument::TextTransform t )
03864 {
03865 editStart();
03866 uint cl( c.line() ), cc( c.col() );
03867 bool selectionRestored = false;
03868
03869 if ( hasSelection() )
03870 {
03871
03872 KateTextCursor selstart = v->selStart();
03873 KateTextCursor selend = v->selEnd();
03874
03875 int ln = v->selStartLine();
03876 while ( ln <= selend.line() )
03877 {
03878 uint start, end;
03879 start = (ln == selstart.line() || v->blockSelectionMode()) ?
03880 selstart.col() : 0;
03881 end = (ln == selend.line() || v->blockSelectionMode()) ?
03882 selend.col() : lineLength( ln );
03883 if ( start > end )
03884 {
03885 uint t = start;
03886 start = end;
03887 end = t;
03888 }
03889 QString s = text( ln, start, ln, end );
03890 QString o = s;
03891
03892 if ( t == Uppercase )
03893 s = s.upper();
03894 else if ( t == Lowercase )
03895 s = s.lower();
03896 else
03897 {
03898 KateTextLine::Ptr l = m_buffer->plainLine( ln );
03899 uint p ( 0 );
03900 while( p < s.length() )
03901 {
03902
03903
03904
03905
03906 if ( ( ! start && ! p ) ||
03907 ( ( ln == selstart.line() || v->blockSelectionMode() ) &&
03908 ! p && ! highlight()->isInWord( l->getChar( start - 1 )) ) ||
03909 ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
03910 )
03911 s[p] = s.at(p).upper();
03912 p++;
03913 }
03914 }
03915
03916 if ( o != s )
03917 {
03918 removeText( ln, start, ln, end );
03919 insertText( ln, start, s );
03920 }
03921
03922 ln++;
03923 }
03924
03925
03926 v->setSelection( selstart, selend );
03927 selectionRestored = true;
03928
03929 } else {
03930 QString o = text( cl, cc, cl, cc + 1 );
03931 QString s;
03932 int n ( cc );
03933 switch ( t ) {
03934 case Uppercase:
03935 s = o.upper();
03936 break;
03937 case Lowercase:
03938 s = o.lower();
03939 break;
03940 case Capitalize:
03941 {
03942 KateTextLine::Ptr l = m_buffer->plainLine( cl );
03943 while ( n > 0 && highlight()->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
03944 n--;
03945 o = text( cl, n, cl, n + 1 );
03946 s = o.upper();
03947 }
03948 break;
03949 default:
03950 break;
03951 }
03952
03953 if ( s != o )
03954 {
03955 removeText( cl, n, cl, n+1 );
03956 insertText( cl, n, s );
03957 }
03958 }
03959 editEnd();
03960
03961 if ( ! selectionRestored )
03962 v->setCursorPosition( cl, cc );
03963 }
03964
03965 void KateDocument::joinLines( uint first, uint last )
03966 {
03967
03968 editStart();
03969 int line( first );
03970 while ( first < last )
03971 {
03972
03973
03974
03975
03976
03977 KateTextLine::Ptr l = m_buffer->line( line );
03978 KateTextLine::Ptr tl = m_buffer->line( line + 1 );
03979
03980 if ( !l || !tl )
03981 {
03982 editEnd();
03983 return;
03984 }
03985
03986 int pos = tl->firstChar();
03987 if ( pos >= 0 )
03988 {
03989 if (pos != 0)
03990 editRemoveText( line + 1, 0, pos );
03991 if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
03992 editInsertText( line + 1, 0, " " );
03993 }
03994 else
03995 {
03996
03997 editRemoveText( line + 1, 0, tl->length() );
03998 }
03999
04000 editUnWrapLine( line );
04001 first++;
04002 }
04003 editEnd();
04004 }
04005
04006 QString KateDocument::getWord( const KateTextCursor& cursor ) {
04007 int start, end, len;
04008
04009 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
04010 len = textLine->length();
04011 start = end = cursor.col();
04012 if (start > len)
04013 return QString("");
04014
04015 while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
04016 while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
04017 len = end - start;
04018 return QString(&textLine->text()[start], len);
04019 }
04020
04021 void KateDocument::tagLines(int start, int end)
04022 {
04023 for (uint z = 0; z < m_views.count(); z++)
04024 m_views.at(z)->tagLines (start, end, true);
04025 }
04026
04027 void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
04028 {
04029
04030 if (blockSelectionMode() && start.col() > end.col()) {
04031 int sc = start.col();
04032 start.setCol(end.col());
04033 end.setCol(sc);
04034 }
04035
04036 for (uint z = 0; z < m_views.count(); z++)
04037 m_views.at(z)->tagLines(start, end, true);
04038 }
04039
04040 void KateDocument::repaintViews(bool paintOnlyDirty)
04041 {
04042 for (uint z = 0; z < m_views.count(); z++)
04043 m_views.at(z)->repaintText(paintOnlyDirty);
04044 }
04045
04046 void KateDocument::tagAll()
04047 {
04048 for (uint z = 0; z < m_views.count(); z++)
04049 {
04050 m_views.at(z)->tagAll();
04051 m_views.at(z)->updateView (true);
04052 }
04053 }
04054
04055 uint KateDocument::configFlags ()
04056 {
04057 return config()->configFlags();
04058 }
04059
04060 void KateDocument::setConfigFlags (uint flags)
04061 {
04062 config()->setConfigFlags(flags);
04063 }
04064
04065 inline bool isStartBracket( const QChar& c ) { return c == '{' || c == '[' || c == '('; }
04066 inline bool isEndBracket ( const QChar& c ) { return c == '}' || c == ']' || c == ')'; }
04067 inline bool isBracket ( const QChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
04068
04069
04070
04071
04072
04073
04074
04075
04076
04077
04078
04079 void KateDocument::newBracketMark( const KateTextCursor& cursor, KateBracketRange& bm, int maxLines )
04080 {
04081 bm.setValid(false);
04082
04083 bm.start() = cursor;
04084
04085 if( !findMatchingBracket( bm.start(), bm.end(), maxLines ) )
04086 return;
04087
04088 bm.setValid(true);
04089
04090 const int tw = config()->tabWidth();
04091 const int indentStart = m_buffer->plainLine(bm.start().line())->indentDepth(tw);
04092 const int indentEnd = m_buffer->plainLine(bm.end().line())->indentDepth(tw);
04093 bm.setIndentMin(kMin(indentStart, indentEnd));
04094 }
04095
04096 bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end, int maxLines )
04097 {
04098 KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
04099 if( !textLine )
04100 return false;
04101
04102 QChar right = textLine->getChar( start.col() );
04103 QChar left = textLine->getChar( start.col() - 1 );
04104 QChar bracket;
04105
04106 if ( config()->configFlags() & cfOvr ) {
04107 if( isBracket( right ) ) {
04108 bracket = right;
04109 } else {
04110 return false;
04111 }
04112 } else if ( isStartBracket( right ) ) {
04113 bracket = right;
04114 } else if ( isEndBracket( left ) ) {
04115 start.setCol(start.col() - 1);
04116 bracket = left;
04117 } else if ( isBracket( left ) ) {
04118 start.setCol(start.col() - 1);
04119 bracket = left;
04120 } else if ( isBracket( right ) ) {
04121 bracket = right;
04122 } else {
04123 return false;
04124 }
04125
04126 QChar opposite;
04127
04128 switch( bracket ) {
04129 case '{': opposite = '}'; break;
04130 case '}': opposite = '{'; break;
04131 case '[': opposite = ']'; break;
04132 case ']': opposite = '['; break;
04133 case '(': opposite = ')'; break;
04134 case ')': opposite = '('; break;
04135 default: return false;
04136 }
04137
04138 bool forward = isStartBracket( bracket );
04139 int startAttr = textLine->attribute( start.col() );
04140 uint count = 0;
04141 int lines = 0;
04142 end = start;
04143
04144 while( true ) {
04145
04146 if( forward ) {
04147 end.setCol(end.col() + 1);
04148 if( end.col() >= lineLength( end.line() ) ) {
04149 if( end.line() >= (int)lastLine() )
04150 return false;
04151 end.setPos(end.line() + 1, 0);
04152 textLine = m_buffer->plainLine( end.line() );
04153 lines++;
04154 }
04155 } else {
04156 end.setCol(end.col() - 1);
04157 if( end.col() < 0 ) {
04158 if( end.line() <= 0 )
04159 return false;
04160 end.setLine(end.line() - 1);
04161 end.setCol(lineLength( end.line() ) - 1);
04162 textLine = m_buffer->plainLine( end.line() );
04163 lines++;
04164 }
04165 }
04166
04167 if ((maxLines != -1) && (lines > maxLines))
04168 return false;
04169
04170
04171 if( textLine->attribute( end.col() ) != startAttr )
04172 continue;
04173
04174
04175 QChar c = textLine->getChar( end.col() );
04176 if( c == bracket ) {
04177 count++;
04178 } else if( c == opposite ) {
04179 if( count == 0 )
04180 return true;
04181 count--;
04182 }
04183
04184 }
04185 }
04186
04187 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
04188 {
04189 KParts::ReadWritePart::guiActivateEvent( ev );
04190 if ( ev->activated() )
04191 emit selectionChanged();
04192 }
04193
04194 void KateDocument::setDocName (QString name )
04195 {
04196 if ( name == m_docName )
04197 return;
04198
04199 if ( !name.isEmpty() )
04200 {
04201
04202 m_docName = name;
04203 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04204 emit nameChanged((Kate::Document *) this);
04205 return;
04206 }
04207
04208
04209 if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
04210
04211 int count = -1;
04212
04213 for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
04214 {
04215 if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
04216 if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
04217 count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
04218 }
04219
04220 m_docNameNumber = count + 1;
04221
04222 m_docName = url().filename();
04223
04224 if (m_docName.isEmpty())
04225 m_docName = i18n ("Untitled");
04226
04227 if (m_docNameNumber > 0)
04228 m_docName = QString(m_docName + " (%1)").arg(m_docNameNumber+1);
04229
04230 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
04231 emit nameChanged ((Kate::Document *) this);
04232 }
04233
04234 void KateDocument::slotModifiedOnDisk( Kate::View * )
04235 {
04236 if ( m_isasking < 0 )
04237 {
04238 m_isasking = 0;
04239 return;
04240 }
04241
04242 if ( !s_fileChangedDialogsActivated || m_isasking )
04243 return;
04244
04245 if (m_modOnHd && !url().isEmpty())
04246 {
04247 m_isasking = 1;
04248
04249 KateModOnHdPrompt p( this, m_modOnHdReason, reasonedMOHString(), widget() );
04250 switch ( p.exec() )
04251 {
04252 case KateModOnHdPrompt::Save:
04253 {
04254 m_modOnHd = false;
04255 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
04256 url().url(),QString::null,widget(),i18n("Save File"));
04257
04258 kdDebug(13020)<<"got "<<res.URLs.count()<<" URLs"<<endl;
04259 if( ! res.URLs.isEmpty() && ! res.URLs.first().isEmpty() && checkOverwrite( res.URLs.first() ) )
04260 {
04261 setEncoding( res.encoding );
04262
04263 if( ! saveAs( res.URLs.first() ) )
04264 {
04265 KMessageBox::error( widget(), i18n("Save failed") );
04266 m_modOnHd = true;
04267 }
04268 else
04269 emit modifiedOnDisc( this, false, 0 );
04270 }
04271 else
04272 {
04273 m_modOnHd = true;
04274 }
04275
04276 m_isasking = 0;
04277 break;
04278 }
04279
04280 case KateModOnHdPrompt::Reload:
04281 m_modOnHd = false;
04282 emit modifiedOnDisc( this, false, 0 );
04283 reloadFile();
04284 m_isasking = 0;
04285 break;
04286
04287 case KateModOnHdPrompt::Ignore:
04288 m_modOnHd = false;
04289 emit modifiedOnDisc( this, false, 0 );
04290 m_isasking = 0;
04291 break;
04292
04293 case KateModOnHdPrompt::Overwrite:
04294 m_modOnHd = false;
04295 emit modifiedOnDisc( this, false, 0 );
04296 m_isasking = 0;
04297 save();
04298 break;
04299
04300 default:
04301 m_isasking = -1;
04302 }
04303 }
04304 }
04305
04306 void KateDocument::setModifiedOnDisk( int reason )
04307 {
04308 m_modOnHdReason = reason;
04309 m_modOnHd = (reason > 0);
04310 emit modifiedOnDisc( this, (reason > 0), reason );
04311 }
04312
04313 class KateDocumentTmpMark
04314 {
04315 public:
04316 QString line;
04317 KTextEditor::Mark mark;
04318 };
04319
04320 void KateDocument::reloadFile()
04321 {
04322 if ( !url().isEmpty() )
04323 {
04324 if (m_modOnHd && s_fileChangedDialogsActivated)
04325 {
04326 int i = KMessageBox::warningYesNoCancel
04327 (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04328 i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
04329
04330 if ( i != KMessageBox::Yes)
04331 {
04332 if (i == KMessageBox::No)
04333 {
04334 m_modOnHd = false;
04335 m_modOnHdReason = 0;
04336 emit modifiedOnDisc (this, m_modOnHd, 0);
04337 }
04338
04339 return;
04340 }
04341 }
04342
04343 QValueList<KateDocumentTmpMark> tmp;
04344
04345 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
04346 {
04347 KateDocumentTmpMark m;
04348
04349 m.line = textLine (it.current()->line);
04350 m.mark = *it.current();
04351
04352 tmp.append (m);
04353 }
04354
04355 uint mode = hlMode ();
04356 bool byUser = hlSetByUser;
04357
04358 m_storedVariables.clear();
04359
04360 m_reloading = true;
04361
04362 QValueList<int> lines, cols;
04363 for ( uint i=0; i < m_views.count(); i++ )
04364 {
04365 lines.append( m_views.at( i )->cursorLine() );
04366 cols.append( m_views.at( i )->cursorColumn() );
04367 }
04368
04369 KateDocument::openURL( url() );
04370
04371 for ( uint i=0; i < m_views.count(); i++ )
04372 m_views.at( i )->setCursorPositionInternal( lines[ i ], cols[ i ], m_config->tabWidth(), false );
04373
04374 m_reloading = false;
04375
04376 for (uint z=0; z < tmp.size(); z++)
04377 {
04378 if (z < numLines())
04379 {
04380 if (textLine(tmp[z].mark.line) == tmp[z].line)
04381 setMark (tmp[z].mark.line, tmp[z].mark.type);
04382 }
04383 }
04384
04385 if (byUser)
04386 setHlMode (mode);
04387 }
04388 }
04389
04390 void KateDocument::flush ()
04391 {
04392 closeURL ();
04393 }
04394
04395 void KateDocument::setWordWrap (bool on)
04396 {
04397 config()->setWordWrap (on);
04398 }
04399
04400 bool KateDocument::wordWrap ()
04401 {
04402 return config()->wordWrap ();
04403 }
04404
04405 void KateDocument::setWordWrapAt (uint col)
04406 {
04407 config()->setWordWrapAt (col);
04408 }
04409
04410 unsigned int KateDocument::wordWrapAt ()
04411 {
04412 return config()->wordWrapAt ();
04413 }
04414
04415 void KateDocument::applyWordWrap ()
04416 {
04417
04418 }
04419
04420 void KateDocument::setPageUpDownMovesCursor (bool on)
04421 {
04422 config()->setPageUpDownMovesCursor (on);
04423 }
04424
04425 bool KateDocument::pageUpDownMovesCursor ()
04426 {
04427 return config()->pageUpDownMovesCursor ();
04428 }
04429
04430 void KateDocument::dumpRegionTree()
04431 {
04432 m_buffer->foldingTree()->debugDump();
04433 }
04434
04435
04436
04437
04438 KTextEditor::Cursor *KateDocument::createCursor ( )
04439 {
04440 return new KateSuperCursor (this, false, 0, 0, this);
04441 }
04442
04443 void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
04444 {
04445 if (view)
04446 view->tagLines(range->start(), range->end());
04447 else
04448 tagLines(range->start(), range->end());
04449 }
04450
04451 void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
04452 {
04453 m_buffer->lineInfo(info,line);
04454 }
04455
04456 KateCodeFoldingTree *KateDocument::foldingTree ()
04457 {
04458 return m_buffer->foldingTree();
04459 }
04460
04461 void KateDocument::setEncoding (const QString &e)
04462 {
04463 if ( m_encodingSticky )
04464 return;
04465
04466 QString ce = m_config->encoding().lower();
04467 if ( e.lower() == ce )
04468 return;
04469
04470 m_config->setEncoding( e );
04471 if ( ! m_loading )
04472 reloadFile();
04473 }
04474
04475 QString KateDocument::encoding() const
04476 {
04477 return m_config->encoding();
04478 }
04479
04480 void KateDocument::updateConfig ()
04481 {
04482 emit undoChanged ();
04483 tagAll();
04484
04485 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
04486 {
04487 view->updateDocumentConfig ();
04488 }
04489
04490
04491 if (m_indenter->modeNumber() != m_config->indentationMode())
04492 {
04493 delete m_indenter;
04494 m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
04495 }
04496
04497 m_indenter->updateConfig();
04498
04499 m_buffer->setTabWidth (config()->tabWidth());
04500
04501
04502 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
04503 {
04504 if (config()->plugin (i))
04505 loadPlugin (i);
04506 else
04507 unloadPlugin (i);
04508 }
04509 }
04510
04511
04512
04513
04514
04515
04516
04517
04518 QRegExp KateDocument::kvLine = QRegExp("kate:(.*)");
04519 QRegExp KateDocument::kvLineWildcard = QRegExp("kate-wildcard\\((.*)\\):(.*)");
04520 QRegExp KateDocument::kvLineMime = QRegExp("kate-mimetype\\((.*)\\):(.*)");
04521 QRegExp KateDocument::kvVar = QRegExp("([\\w\\-]+)\\s+([^;]+)");
04522
04523 void KateDocument::readVariables(bool onlyViewAndRenderer)
04524 {
04525 if (!onlyViewAndRenderer)
04526 m_config->configStart();
04527
04528
04529 KateView *v;
04530 for (v = m_views.first(); v != 0L; v= m_views.next() )
04531 {
04532 v->config()->configStart();
04533 v->renderer()->config()->configStart();
04534 }
04535
04536 for (uint i=0; i < kMin( 9U, numLines() ); ++i )
04537 {
04538 readVariableLine( textLine( i ), onlyViewAndRenderer );
04539 }
04540 if ( numLines() > 10 )
04541 {
04542 for ( uint i = kMax(10U, numLines() - 10); i < numLines(); ++i )
04543 {
04544 readVariableLine( textLine( i ), onlyViewAndRenderer );
04545 }
04546 }
04547
04548 if (!onlyViewAndRenderer)
04549 m_config->configEnd();
04550
04551 for (v = m_views.first(); v != 0L; v= m_views.next() )
04552 {
04553 v->config()->configEnd();
04554 v->renderer()->config()->configEnd();
04555 }
04556 }
04557
04558 void KateDocument::readVariableLine( QString t, bool onlyViewAndRenderer )
04559 {
04560
04561
04562 if (t.find("kate") < 0)
04563 return;
04564
04565
04566 QString s;
04567
04568 if ( kvLine.search( t ) > -1 )
04569 {
04570 s = kvLine.cap(1);
04571
04572 kdDebug (13020) << "normal variable line kate: matched: " << s << endl;
04573 }
04574 else if (kvLineWildcard.search( t ) > -1)
04575 {
04576 QStringList wildcards (QStringList::split(';', kvLineWildcard.cap(1)));
04577 QString nameOfFile = url().fileName();
04578
04579 bool found = false;
04580 for (int i = 0; !found && i < wildcards.size(); ++i)
04581 {
04582 QRegExp wildcard (wildcards[i], true, true);
04583
04584 found = wildcard.exactMatch (nameOfFile);
04585 }
04586
04587
04588 if (!found)
04589 return;
04590
04591 s = kvLineWildcard.cap(2);
04592
04593 kdDebug (13020) << "guarded variable line kate-wildcard: matched: " << s << endl;
04594 }
04595 else if (kvLineMime.search( t ) > -1)
04596 {
04597 QStringList types (QStringList::split(';', kvLineMime.cap(1)));
04598
04599
04600 if (!types.contains (mimeType ()))
04601 return;
04602
04603 s = kvLineMime.cap(2);
04604
04605 kdDebug (13020) << "guarded variable line kate-mimetype: matched: " << s << endl;
04606 }
04607 else
04608 {
04609 return;
04610 }
04611
04612 QStringList vvl;
04613 vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
04614 << "line-numbers" << "icon-border" << "folding-markers"
04615 << "bookmark-sorting" << "auto-center-lines"
04616 << "icon-bar-color"
04617
04618 << "background-color" << "selection-color"
04619 << "current-line-color" << "bracket-highlight-color"
04620 << "word-wrap-marker-color"
04621 << "font" << "font-size" << "scheme";
04622 int p( 0 );
04623
04624 QString var, val;
04625 while ( (p = kvVar.search( s, p )) > -1 )
04626 {
04627 p += kvVar.matchedLength();
04628 var = kvVar.cap( 1 );
04629 val = kvVar.cap( 2 ).stripWhiteSpace();
04630 bool state;
04631 int n;
04632
04633
04634 if (onlyViewAndRenderer)
04635 {
04636 if ( vvl.contains( var ) )
04637 setViewVariable( var, val );
04638 }
04639 else
04640 {
04641
04642 if ( var == "word-wrap" && checkBoolValue( val, &state ) )
04643 setWordWrap( state );
04644 else if ( var == "block-selection" && checkBoolValue( val, &state ) )
04645 setBlockSelectionMode( state );
04646
04647
04648 else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
04649 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
04650 else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
04651 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
04652 else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
04653 m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
04654 else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
04655 m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
04656 else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
04657 m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
04658 else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
04659 m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
04660 else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
04661 m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
04662 else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
04663 m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
04664 else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
04665 m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
04666 else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
04667 m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
04668 else if ( var == "space-indent" && checkBoolValue( val, &state ) )
04669 m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
04670 else if ( var == "smart-home" && checkBoolValue( val, &state ) )
04671 m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
04672 else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
04673 m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
04674 else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
04675 m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
04676 else if ( var == "mixed-indent" && checkBoolValue( val, &state ) )
04677 m_config->setConfigFlags( KateDocumentConfig::cfMixedIndent, state );
04678
04679
04680 else if ( var == "tab-width" && checkIntValue( val, &n ) )
04681 m_config->setTabWidth( n );
04682 else if ( var == "indent-width" && checkIntValue( val, &n ) )
04683 m_config->setIndentationWidth( n );
04684 else if ( var == "indent-mode" )
04685 {
04686 if ( checkIntValue( val, &n ) )
04687 m_config->setIndentationMode( n );
04688 else
04689 m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
04690 }
04691 else if ( var == "word-wrap-column" && checkIntValue( val, &n ) && n > 0 )
04692 m_config->setWordWrapAt( n );
04693 else if ( var == "undo-steps" && checkIntValue( val, &n ) && n >= 0 )
04694 setUndoSteps( n );
04695
04696
04697 else if ( var == "eol" || var == "end-of-line" )
04698 {
04699 QStringList l;
04700 l << "unix" << "dos" << "mac";
04701 if ( (n = l.findIndex( val.lower() )) != -1 )
04702 m_config->setEol( n );
04703 }
04704 else if ( var == "encoding" )
04705 m_config->setEncoding( val );
04706 else if ( var == "syntax" || var == "hl" )
04707 {
04708 for ( uint i=0; i < hlModeCount(); i++ )
04709 {
04710 if ( hlModeName( i ).lower() == val.lower() )
04711 {
04712 setHlMode( i );
04713 break;
04714 }
04715 }
04716 }
04717
04718
04719 else if ( vvl.contains( var ) )
04720 setViewVariable( var, val );
04721 else
04722 {
04723 m_storedVariables.insert( var, val );
04724 emit variableChanged( var, val );
04725 }
04726 }
04727 }
04728 }
04729
04730 void KateDocument::setViewVariable( QString var, QString val )
04731 {
04732 KateView *v;
04733 bool state;
04734 int n;
04735 QColor c;
04736 for (v = m_views.first(); v != 0L; v= m_views.next() )
04737 {
04738 if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
04739 v->config()->setDynWordWrap( state );
04740 else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
04741 v->config()->setPersistentSelection( state );
04742
04743 else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
04744 v->config()->setLineNumbers( state );
04745 else if (var == "icon-border" && checkBoolValue( val, &state ) )
04746 v->config()->setIconBar( state );
04747 else if (var == "folding-markers" && checkBoolValue( val, &state ) )
04748 v->config()->setFoldingBar( state );
04749 else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
04750 v->config()->setAutoCenterLines( n );
04751 else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
04752 v->renderer()->config()->setIconBarColor( c );
04753
04754 else if ( var == "background-color" && checkColorValue( val, c ) )
04755 v->renderer()->config()->setBackgroundColor( c );
04756 else if ( var == "selection-color" && checkColorValue( val, c ) )
04757 v->renderer()->config()->setSelectionColor( c );
04758 else if ( var == "current-line-color" && checkColorValue( val, c ) )
04759 v->renderer()->config()->setHighlightedLineColor( c );
04760 else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
04761 v->renderer()->config()->setHighlightedBracketColor( c );
04762 else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
04763 v->renderer()->config()->setWordWrapMarkerColor( c );
04764 else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
04765 {
04766 QFont _f( *v->renderer()->config()->font( ) );
04767
04768 if ( var == "font" )
04769 {
04770 _f.setFamily( val );
04771 _f.setFixedPitch( QFont( val ).fixedPitch() );
04772 }
04773 else
04774 _f.setPointSize( n );
04775
04776 v->renderer()->config()->setFont( _f );
04777 }
04778 else if ( var == "scheme" )
04779 {
04780 v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
04781 }
04782 }
04783 }
04784
04785 bool KateDocument::checkBoolValue( QString val, bool *result )
04786 {
04787 val = val.stripWhiteSpace().lower();
04788 QStringList l;
04789 l << "1" << "on" << "true";
04790 if ( l.contains( val ) )
04791 {
04792 *result = true;
04793 return true;
04794 }
04795 l.clear();
04796 l << "0" << "off" << "false";
04797 if ( l.contains( val ) )
04798 {
04799 *result = false;
04800 return true;
04801 }
04802 return false;
04803 }
04804
04805 bool KateDocument::checkIntValue( QString val, int *result )
04806 {
04807 bool ret( false );
04808 *result = val.toInt( &ret );
04809 return ret;
04810 }
04811
04812 bool KateDocument::checkColorValue( QString val, QColor &c )
04813 {
04814 c.setNamedColor( val );
04815 return c.isValid();
04816 }
04817
04818
04819 QString KateDocument::variable( const QString &name ) const
04820 {
04821 if ( m_storedVariables.contains( name ) )
04822 return m_storedVariables[ name ];
04823
04824 return "";
04825 }
04826
04827
04828
04829 void KateDocument::slotModOnHdDirty (const QString &path)
04830 {
04831 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
04832 {
04833
04834 if ( ! m_digest.isEmpty() )
04835 {
04836 QCString tmp;
04837 if ( createDigest( tmp ) && tmp == m_digest )
04838 return;
04839 }
04840
04841 m_modOnHd = true;
04842 m_modOnHdReason = 1;
04843
04844
04845 if (m_isasking == -1)
04846 m_isasking = false;
04847
04848 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
04849 }
04850 }
04851
04852 void KateDocument::slotModOnHdCreated (const QString &path)
04853 {
04854 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
04855 {
04856 m_modOnHd = true;
04857 m_modOnHdReason = 2;
04858
04859
04860 if (m_isasking == -1)
04861 m_isasking = false;
04862
04863 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
04864 }
04865 }
04866
04867 void KateDocument::slotModOnHdDeleted (const QString &path)
04868 {
04869 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
04870 {
04871 m_modOnHd = true;
04872 m_modOnHdReason = 3;
04873
04874
04875 if (m_isasking == -1)
04876 m_isasking = false;
04877
04878 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
04879 }
04880 }
04881
04882 bool KateDocument::createDigest( QCString &result )
04883 {
04884 bool ret = false;
04885 result = "";
04886 if ( url().isLocalFile() )
04887 {
04888 QFile f ( url().path() );
04889 if ( f.open( IO_ReadOnly) )
04890 {
04891 KMD5 md5;
04892 ret = md5.update( f );
04893 md5.hexDigest( result );
04894 f.close();
04895 ret = true;
04896 }
04897 }
04898 return ret;
04899 }
04900
04901 QString KateDocument::reasonedMOHString() const
04902 {
04903 switch( m_modOnHdReason )
04904 {
04905 case 1:
04906 return i18n("The file '%1' was modified by another program.").arg( url().prettyURL() );
04907 break;
04908 case 2:
04909 return i18n("The file '%1' was created by another program.").arg( url().prettyURL() );
04910 break;
04911 case 3:
04912 return i18n("The file '%1' was deleted by another program.").arg( url().prettyURL() );
04913 break;
04914 default:
04915 return QString();
04916 }
04917 }
04918
04919 void KateDocument::removeTrailingSpace( uint line )
04920 {
04921
04922 if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
04923 {
04924 KateTextLine::Ptr ln = kateTextLine( line );
04925
04926 if ( ! ln ) return;
04927
04928 if ( line == activeView()->cursorLine()
04929 && activeView()->cursorColumnReal() >= (uint)kMax(0,ln->lastChar()) )
04930 return;
04931
04932 if ( ln->length() )
04933 {
04934 uint p = ln->lastChar() + 1;
04935 uint l = ln->length() - p;
04936 if ( l )
04937 editRemoveText( line, p, l);
04938 }
04939 }
04940 }
04941
04942 void KateDocument::updateFileType (int newType, bool user)
04943 {
04944 if (user || !m_fileTypeSetByUser)
04945 {
04946 const KateFileType *t = 0;
04947 if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
04948 {
04949 m_fileType = newType;
04950
04951 if (t)
04952 {
04953 m_config->configStart();
04954
04955 KateView *v;
04956 for (v = m_views.first(); v != 0L; v= m_views.next() )
04957 {
04958 v->config()->configStart();
04959 v->renderer()->config()->configStart();
04960 }
04961
04962 readVariableLine( t->varLine );
04963
04964 m_config->configEnd();
04965 for (v = m_views.first(); v != 0L; v= m_views.next() )
04966 {
04967 v->config()->configEnd();
04968 v->renderer()->config()->configEnd();
04969 }
04970 }
04971 }
04972 }
04973 }
04974
04975 uint KateDocument::documentNumber () const
04976 {
04977 return KTextEditor::Document::documentNumber ();
04978 }
04979
04980
04981
04982
04983 void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
04984 *handled=true;
04985 *abortClosing=true;
04986 if (m_url.isEmpty())
04987 {
04988 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
04989 QString::null,QString::null,0,i18n("Save File"));
04990
04991 if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
04992 *abortClosing=true;
04993 return;
04994 }
04995 setEncoding( res.encoding );
04996 saveAs( res.URLs.first() );
04997 *abortClosing=false;
04998 }
04999 else
05000 {
05001 save();
05002 *abortClosing=false;
05003 }
05004
05005 }
05006
05007 bool KateDocument::checkOverwrite( KURL u )
05008 {
05009 if( !u.isLocalFile() )
05010 return true;
05011
05012 QFileInfo info( u.path() );
05013 if( !info.exists() )
05014 return true;
05015
05016 return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
05017 i18n( "A file named \"%1\" already exists. "
05018 "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
05019 i18n( "Overwrite File?" ),
05020 i18n( "&Overwrite" ) );
05021 }
05022
05023 void KateDocument::setDefaultEncoding (const QString &encoding)
05024 {
05025 s_defaultEncoding = encoding;
05026 }
05027
05028
05029 bool KateDocument::insertTemplateTextImplementation ( uint line, uint column, const QString &templateString, const QMap<QString,QString> &initialValues, QWidget *) {
05030 return (new KateTemplateHandler(this,line,column,templateString,initialValues))->initOk();
05031 }
05032
05033 void KateDocument::testTemplateCode() {
05034 int col=activeView()->cursorColumn();
05035 int line=activeView()->cursorLine();
05036 insertTemplateText(line,col,"for ${index} \\${NOPLACEHOLDER} ${index} ${blah} ${fullname} \\$${Placeholder} \\${${PLACEHOLDER2}}\n next line:${ANOTHERPLACEHOLDER} $${DOLLARBEFOREPLACEHOLDER} {NOTHING} {\n${cursor}\n}",QMap<QString,QString>());
05037 }
05038
05039 bool KateDocument::invokeTabInterceptor(KKey key) {
05040 if (m_tabInterceptor) return (*m_tabInterceptor)(key);
05041 return false;
05042 }
05043
05044 bool KateDocument::setTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05045 if (m_tabInterceptor) return false;
05046 m_tabInterceptor=interceptor;
05047 return true;
05048 }
05049
05050 bool KateDocument::removeTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
05051 if (m_tabInterceptor!=interceptor) return false;
05052 m_tabInterceptor=0;
05053 return true;
05054 }
05055
05056
05057
05058 bool KateDocument::setSelection ( uint startLine, uint startCol, uint endLine, uint endCol )
05059 { if (m_activeView) return m_activeView->setSelection (startLine, startCol, endLine, endCol); return false; }
05060
05061 bool KateDocument::clearSelection ()
05062 { if (m_activeView) return m_activeView->clearSelection(); return false; }
05063
05064 bool KateDocument::hasSelection () const
05065 { if (m_activeView) return m_activeView->hasSelection (); return false; }
05066
05067 QString KateDocument::selection () const
05068 { if (m_activeView) return m_activeView->selection (); return QString(""); }
05069
05070 bool KateDocument::removeSelectedText ()
05071 { if (m_activeView) return m_activeView->removeSelectedText (); return false; }
05072
05073 bool KateDocument::selectAll()
05074 { if (m_activeView) return m_activeView->selectAll (); return false; }
05075
05076 int KateDocument::selStartLine()
05077 { if (m_activeView) return m_activeView->selStartLine (); return 0; }
05078
05079 int KateDocument::selStartCol()
05080 { if (m_activeView) return m_activeView->selStartCol (); return 0; }
05081
05082 int KateDocument::selEndLine()
05083 { if (m_activeView) return m_activeView->selEndLine (); return 0; }
05084
05085 int KateDocument::selEndCol()
05086 { if (m_activeView) return m_activeView->selEndCol (); return 0; }
05087
05088 bool KateDocument::blockSelectionMode ()
05089 { if (m_activeView) return m_activeView->blockSelectionMode (); return false; }
05090
05091 bool KateDocument::setBlockSelectionMode (bool on)
05092 { if (m_activeView) return m_activeView->setBlockSelectionMode (on); return false; }
05093
05094 bool KateDocument::toggleBlockSelectionMode ()
05095 { if (m_activeView) return m_activeView->toggleBlockSelectionMode (); return false; }
05096
05097
05098
05099
05100