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
00072 #include <qtimer.h>
00073 #include <qfile.h>
00074 #include <qclipboard.h>
00075 #include <qtextstream.h>
00076 #include <qtextcodec.h>
00077 #include <qmap.h>
00078
00079
00080
00081 class KatePartPluginItem
00082 {
00083 public:
00084 KTextEditor::Plugin *plugin;
00085 };
00086
00087
00088
00089
00090
00091
00092 KateDocument::KateDocument ( bool bSingleViewMode, bool bBrowserView,
00093 bool bReadOnly, QWidget *parentWidget,
00094 const char *widgetName, QObject *parent, const char *name)
00095 : Kate::Document(parent, name),
00096 m_plugins (KateFactory::self()->plugins().count()),
00097 m_undoDontMerge(false),
00098 m_undoIgnoreCancel(false),
00099 lastUndoGroupWhenSaved( 0 ),
00100 docWasSavedWhenUndoWasEmpty( true ),
00101 m_modOnHd (false),
00102 m_modOnHdReason (0),
00103 m_job (0),
00104 m_tempFile (0),
00105 m_tabInterceptor(0)
00106 {
00107 m_undoComplexMerge=false;
00108 m_isInUndo = false;
00109
00110 setObjId ("KateDocument#"+documentDCOPSuffix());
00111
00112
00113 setBlockSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
00114 setConfigInterfaceDCOPSuffix (documentDCOPSuffix());
00115 setConfigInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
00116 setCursorInterfaceDCOPSuffix (documentDCOPSuffix());
00117 setEditInterfaceDCOPSuffix (documentDCOPSuffix());
00118 setEncodingInterfaceDCOPSuffix (documentDCOPSuffix());
00119 setHighlightingInterfaceDCOPSuffix (documentDCOPSuffix());
00120 setMarkInterfaceDCOPSuffix (documentDCOPSuffix());
00121 setMarkInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
00122 setPrintInterfaceDCOPSuffix (documentDCOPSuffix());
00123 setSearchInterfaceDCOPSuffix (documentDCOPSuffix());
00124 setSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
00125 setSelectionInterfaceExtDCOPSuffix (documentDCOPSuffix());
00126 setSessionConfigInterfaceDCOPSuffix (documentDCOPSuffix());
00127 setUndoInterfaceDCOPSuffix (documentDCOPSuffix());
00128 setWordWrapInterfaceDCOPSuffix (documentDCOPSuffix());
00129
00130
00131 m_plugins.fill (0);
00132
00133
00134 KateFactory::self()->registerDocument (this);
00135
00136 m_reloading = false;
00137 m_loading = false;
00138 m_encodingSticky = false;
00139
00140 m_buffer = new KateBuffer (this);
00141
00142
00143
00144 m_config = new KateDocumentConfig (this);
00145
00146
00147 m_activeView = 0L;
00148
00149 hlSetByUser = false;
00150 m_fileType = -1;
00151 m_fileTypeSetByUser = false;
00152 setInstance( KateFactory::self()->instance() );
00153
00154 editSessionNumber = 0;
00155 editIsRunning = false;
00156 m_editCurrentUndo = 0L;
00157 editWithUndo = false;
00158
00159 m_docNameNumber = 0;
00160
00161 m_bSingleViewMode = bSingleViewMode;
00162 m_bBrowserView = bBrowserView;
00163 m_bReadOnly = bReadOnly;
00164
00165 m_marks.setAutoDelete( true );
00166 m_markPixmaps.setAutoDelete( true );
00167 m_markDescriptions.setAutoDelete( true );
00168 setMarksUserChangable( markType01 );
00169
00170 m_undoMergeTimer = new QTimer(this);
00171 connect(m_undoMergeTimer, SIGNAL(timeout()), SLOT(undoCancel()));
00172
00173 clearMarks ();
00174 clearUndo ();
00175 clearRedo ();
00176 setModified (false);
00177 docWasSavedWhenUndoWasEmpty = true;
00178
00179
00180 m_buffer->setHighlight (0);
00181
00182 m_extension = new KateBrowserExtension( this );
00183 m_arbitraryHL = new KateArbitraryHighlight();
00184 m_indenter = KateAutoIndent::createIndenter ( this, 0 );
00185
00186 m_indenter->updateConfig ();
00187
00188
00189 connect(m_buffer, SIGNAL(tagLines(int,int)), this, SLOT(tagLines(int,int)));
00190 connect(m_buffer, SIGNAL(codeFoldingUpdated()),this,SIGNAL(codeFoldingUpdated()));
00191
00192
00193 connect(KateHlManager::self(),SIGNAL(changed()),SLOT(internalHlChanged()));
00194
00195
00196 connect(m_arbitraryHL, SIGNAL(tagLines(KateView*, KateSuperRange*)), SLOT(tagArbitraryLines(KateView*, KateSuperRange*)));
00197
00198
00199 connect( KateFactory::self()->dirWatch(), SIGNAL(dirty (const QString &)),
00200 this, SLOT(slotModOnHdDirty (const QString &)) );
00201
00202 connect( KateFactory::self()->dirWatch(), SIGNAL(created (const QString &)),
00203 this, SLOT(slotModOnHdCreated (const QString &)) );
00204
00205 connect( KateFactory::self()->dirWatch(), SIGNAL(deleted (const QString &)),
00206 this, SLOT(slotModOnHdDeleted (const QString &)) );
00207
00208
00209 setDocName ("");
00210
00211
00212 if ( m_bSingleViewMode )
00213 {
00214 KTextEditor::View *view = createView( parentWidget, widgetName );
00215 insertChildClient( view );
00216 view->show();
00217 setWidget( view );
00218 }
00219
00220 connect(this,SIGNAL(sigQueryClose(bool *, bool*)),this,SLOT(slotQueryClose_save(bool *, bool*)));
00221
00222 m_isasking = 0;
00223
00224
00225 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
00226 {
00227 if (config()->plugin (i))
00228 loadPlugin (i);
00229 }
00230 }
00231
00232
00233
00234
00235 KateDocument::~KateDocument()
00236 {
00237
00238 deactivateDirWatch ();
00239
00240 if (!singleViewMode())
00241 {
00242
00243 m_views.setAutoDelete( true );
00244 m_views.clear();
00245 }
00246
00247 delete m_editCurrentUndo;
00248
00249 delete m_arbitraryHL;
00250
00251
00252 undoItems.setAutoDelete(true);
00253 undoItems.clear();
00254
00255
00256 unloadAllPlugins ();
00257
00258 delete m_config;
00259 delete m_indenter;
00260 KateFactory::self()->deregisterDocument (this);
00261 }
00262
00263
00264
00265 void KateDocument::unloadAllPlugins ()
00266 {
00267 for (uint i=0; i<m_plugins.count(); i++)
00268 unloadPlugin (i);
00269 }
00270
00271 void KateDocument::enableAllPluginsGUI (KateView *view)
00272 {
00273 for (uint i=0; i<m_plugins.count(); i++)
00274 enablePluginGUI (m_plugins[i], view);
00275 }
00276
00277 void KateDocument::disableAllPluginsGUI (KateView *view)
00278 {
00279 for (uint i=0; i<m_plugins.count(); i++)
00280 disablePluginGUI (m_plugins[i], view);
00281 }
00282
00283 void KateDocument::loadPlugin (uint pluginIndex)
00284 {
00285 if (m_plugins[pluginIndex]) return;
00286
00287 m_plugins[pluginIndex] = KTextEditor::createPlugin (QFile::encodeName((KateFactory::self()->plugins())[pluginIndex]->library()), this);
00288
00289 enablePluginGUI (m_plugins[pluginIndex]);
00290 }
00291
00292 void KateDocument::unloadPlugin (uint pluginIndex)
00293 {
00294 if (!m_plugins[pluginIndex]) return;
00295
00296 disablePluginGUI (m_plugins[pluginIndex]);
00297
00298 delete m_plugins[pluginIndex];
00299 m_plugins[pluginIndex] = 0L;
00300 }
00301
00302 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
00303 {
00304 if (!plugin) return;
00305 if (!KTextEditor::pluginViewInterface(plugin)) return;
00306
00307 KXMLGUIFactory *factory = view->factory();
00308 if ( factory )
00309 factory->removeClient( view );
00310
00311 KTextEditor::pluginViewInterface(plugin)->addView(view);
00312
00313 if ( factory )
00314 factory->addClient( view );
00315 }
00316
00317 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin)
00318 {
00319 if (!plugin) return;
00320 if (!KTextEditor::pluginViewInterface(plugin)) return;
00321
00322 for (uint i=0; i< m_views.count(); i++)
00323 enablePluginGUI (plugin, m_views.at(i));
00324 }
00325
00326 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
00327 {
00328 if (!plugin) return;
00329 if (!KTextEditor::pluginViewInterface(plugin)) return;
00330
00331 KXMLGUIFactory *factory = view->factory();
00332 if ( factory )
00333 factory->removeClient( view );
00334
00335 KTextEditor::pluginViewInterface( plugin )->removeView( view );
00336
00337 if ( factory )
00338 factory->addClient( view );
00339 }
00340
00341 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin)
00342 {
00343 if (!plugin) return;
00344 if (!KTextEditor::pluginViewInterface(plugin)) return;
00345
00346 for (uint i=0; i< m_views.count(); i++)
00347 disablePluginGUI (plugin, m_views.at(i));
00348 }
00349
00350
00351
00352
00353 KTextEditor::View *KateDocument::createView( QWidget *parent, const char *name )
00354 {
00355 KateView* newView = new KateView( this, parent, name);
00356 connect(newView, SIGNAL(cursorPositionChanged()), SLOT(undoCancel()));
00357 if ( s_fileChangedDialogsActivated )
00358 connect( newView, SIGNAL(gotFocus( Kate::View * )), this, SLOT(slotModifiedOnDisk()) );
00359 return newView;
00360 }
00361
00362 QPtrList<KTextEditor::View> KateDocument::views () const
00363 {
00364 return m_textEditViews;
00365 }
00366
00367 void KateDocument::setActiveView( KateView *view )
00368 {
00369 if ( m_activeView == view ) return;
00370
00371 m_activeView = view;
00372 }
00373
00374
00375
00376
00377 uint KateDocument::configPages () const
00378 {
00379 return 10;
00380 }
00381
00382 KTextEditor::ConfigPage *KateDocument::configPage (uint number, QWidget *parent, const char * )
00383 {
00384 switch( number )
00385 {
00386 case 0:
00387 return new KateViewDefaultsConfig (parent);
00388
00389 case 1:
00390 return new KateSchemaConfigPage (parent, this);
00391
00392 case 2:
00393 return new KateSelectConfigTab (parent);
00394
00395 case 3:
00396 return new KateEditConfigTab (parent);
00397
00398 case 4:
00399 return new KateIndentConfigTab (parent);
00400
00401 case 5:
00402 return new KateSaveConfigTab (parent);
00403
00404 case 6:
00405 return new KateHlConfigPage (parent, this);
00406
00407 case 7:
00408 return new KateFileTypeConfigTab (parent);
00409
00410 case 8:
00411 return new KateEditKeyConfiguration (parent, this);
00412
00413 case 9:
00414 return new KatePartPluginConfigPage (parent);
00415
00416 default:
00417 return 0;
00418 }
00419
00420 return 0;
00421 }
00422
00423 QString KateDocument::configPageName (uint number) const
00424 {
00425 switch( number )
00426 {
00427 case 0:
00428 return i18n ("Appearance");
00429
00430 case 1:
00431 return i18n ("Fonts & Colors");
00432
00433 case 2:
00434 return i18n ("Cursor & Selection");
00435
00436 case 3:
00437 return i18n ("Editing");
00438
00439 case 4:
00440 return i18n ("Indentation");
00441
00442 case 5:
00443 return i18n("Open/Save");
00444
00445 case 6:
00446 return i18n ("Highlighting");
00447
00448 case 7:
00449 return i18n("Filetypes");
00450
00451 case 8:
00452 return i18n ("Shortcuts");
00453
00454 case 9:
00455 return i18n ("Plugins");
00456
00457 default:
00458 return QString ("");
00459 }
00460
00461 return QString ("");
00462 }
00463
00464 QString KateDocument::configPageFullName (uint number) const
00465 {
00466 switch( number )
00467 {
00468 case 0:
00469 return i18n("Appearance");
00470
00471 case 1:
00472 return i18n ("Font & Color Schemas");
00473
00474 case 2:
00475 return i18n ("Cursor & Selection Behavior");
00476
00477 case 3:
00478 return i18n ("Editing Options");
00479
00480 case 4:
00481 return i18n ("Indentation Rules");
00482
00483 case 5:
00484 return i18n("File Opening & Saving");
00485
00486 case 6:
00487 return i18n ("Highlighting Rules");
00488
00489 case 7:
00490 return i18n("Filetype Specific Settings");
00491
00492 case 8:
00493 return i18n ("Shortcuts Configuration");
00494
00495 case 9:
00496 return i18n ("Plugin Manager");
00497
00498 default:
00499 return QString ("");
00500 }
00501
00502 return QString ("");
00503 }
00504
00505 QPixmap KateDocument::configPagePixmap (uint number, int size) const
00506 {
00507 switch( number )
00508 {
00509 case 0:
00510 return BarIcon("view_text",size);
00511
00512 case 1:
00513 return BarIcon("colorize", size);
00514
00515 case 2:
00516 return BarIcon("frame_edit", size);
00517
00518 case 3:
00519 return BarIcon("edit", size);
00520
00521 case 4:
00522 return BarIcon("rightjust", size);
00523
00524 case 5:
00525 return BarIcon("filesave", size);
00526
00527 case 6:
00528 return BarIcon("source", size);
00529
00530 case 7:
00531 return BarIcon("edit", size);
00532
00533 case 8:
00534 return BarIcon("key_enter", size);
00535
00536 case 9:
00537 return BarIcon("connect_established", size);
00538
00539 default:
00540 return BarIcon("edit", size);
00541 }
00542
00543 return BarIcon("edit", size);
00544 }
00545
00546
00547
00548
00549 QString KateDocument::text() const
00550 {
00551 QString s;
00552
00553 for (uint i = 0; i < m_buffer->count(); i++)
00554 {
00555 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00556
00557 if (textLine)
00558 {
00559 s.append (textLine->string());
00560
00561 if ((i+1) < m_buffer->count())
00562 s.append('\n');
00563 }
00564 }
00565
00566 return s;
00567 }
00568
00569 QString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol ) const
00570 {
00571 return text(startLine, startCol, endLine, endCol, false);
00572 }
00573
00574 QString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise) const
00575 {
00576 if ( blockwise && (startCol > endCol) )
00577 return QString ();
00578
00579 QString s;
00580
00581 if (startLine == endLine)
00582 {
00583 if (startCol > endCol)
00584 return QString ();
00585
00586 KateTextLine::Ptr textLine = m_buffer->plainLine(startLine);
00587
00588 if ( !textLine )
00589 return QString ();
00590
00591 return textLine->string(startCol, endCol-startCol);
00592 }
00593 else
00594 {
00595
00596 for (uint i = startLine; (i <= endLine) && (i < m_buffer->count()); i++)
00597 {
00598 KateTextLine::Ptr textLine = m_buffer->plainLine(i);
00599
00600 if ( !blockwise )
00601 {
00602 if (i == startLine)
00603 s.append (textLine->string(startCol, textLine->length()-startCol));
00604 else if (i == endLine)
00605 s.append (textLine->string(0, endCol));
00606 else
00607 s.append (textLine->string());
00608 }
00609 else
00610 {
00611 s.append( textLine->string( startCol, endCol-startCol));
00612 }
00613
00614 if ( i < endLine )
00615 s.append('\n');
00616 }
00617 }
00618
00619 return s;
00620 }
00621
00622 QString KateDocument::textLine( uint line ) const
00623 {
00624 KateTextLine::Ptr l = m_buffer->plainLine(line);
00625
00626 if (!l)
00627 return QString();
00628
00629 return l->string();
00630 }
00631
00632 bool KateDocument::setText(const QString &s)
00633 {
00634 if (!isReadWrite())
00635 return false;
00636
00637 QPtrList<KTextEditor::Mark> m = marks ();
00638 QValueList<KTextEditor::Mark> msave;
00639
00640 for (uint i=0; i < m.count(); i++)
00641 msave.append (*m.at(i));
00642
00643 editStart ();
00644
00645
00646 clear();
00647
00648
00649 insertText (0, 0, s);
00650
00651 editEnd ();
00652
00653 for (uint i=0; i < msave.count(); i++)
00654 setMark (msave[i].line, msave[i].type);
00655
00656 return true;
00657 }
00658
00659 bool KateDocument::clear()
00660 {
00661 if (!isReadWrite())
00662 return false;
00663
00664 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() ) {
00665 view->clear();
00666 view->tagAll();
00667 view->update();
00668 }
00669
00670 clearMarks ();
00671
00672 return removeText (0,0,lastLine()+1, 0);
00673 }
00674
00675 bool KateDocument::insertText( uint line, uint col, const QString &s)
00676 {
00677 return insertText (line, col, s, false);
00678 }
00679
00680 bool KateDocument::insertText( uint line, uint col, const QString &s, bool blockwise )
00681 {
00682 if (!isReadWrite())
00683 return false;
00684
00685 if (s.isEmpty())
00686 return true;
00687
00688 if (line == numLines())
00689 editInsertLine(line,"");
00690 else if (line > lastLine())
00691 return false;
00692
00693 editStart ();
00694
00695 uint insertPos = col;
00696 uint len = s.length();
00697
00698 QString buf;
00699
00700 bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo );
00701 uint tw = config()->tabWidth();
00702 uint insertPosExpanded = insertPos;
00703 KateTextLine::Ptr l = m_buffer->line( line );
00704 if (l != 0)
00705 insertPosExpanded = l->cursorX( insertPos, tw );
00706
00707 for (uint pos = 0; pos < len; pos++)
00708 {
00709 QChar ch = s[pos];
00710
00711 if (ch == '\n')
00712 {
00713 editInsertText (line, insertPos, buf);
00714
00715 if ( !blockwise )
00716 {
00717 editWrapLine (line, insertPos + buf.length());
00718 insertPos = insertPosExpanded = 0;
00719 }
00720 else
00721 {
00722 if ( line == lastLine() )
00723 editWrapLine (line, insertPos + buf.length());
00724 }
00725
00726 line++;
00727 buf.truncate(0);
00728 l = m_buffer->line( line );
00729 if (l)
00730 insertPosExpanded = l->cursorX( insertPos, tw );
00731 }
00732 else
00733 {
00734 if ( replacetabs && ch == '\t' )
00735 {
00736 uint tr = tw - ( insertPosExpanded+buf.length() )%tw;
00737 for ( uint i=0; i < tr; i++ )
00738 buf += ' ';
00739 }
00740 else
00741 buf += ch;
00742 }
00743 }
00744
00745 editInsertText (line, insertPos, buf);
00746
00747 editEnd ();
00748 emit textInserted(line,insertPos);
00749 return true;
00750 }
00751
00752 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol )
00753 {
00754 return removeText (startLine, startCol, endLine, endCol, false);
00755 }
00756
00757 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise)
00758 {
00759 if (!isReadWrite())
00760 return false;
00761
00762 if ( blockwise && (startCol > endCol) )
00763 return false;
00764
00765 if ( startLine > endLine )
00766 return false;
00767
00768 if ( startLine > lastLine() )
00769 return false;
00770
00771 if (!blockwise) {
00772 emit aboutToRemoveText(KateTextRange(startLine,startCol,endLine,endCol));
00773 }
00774 editStart ();
00775
00776 if ( !blockwise )
00777 {
00778 if ( endLine > lastLine() )
00779 {
00780 endLine = lastLine()+1;
00781 endCol = 0;
00782 }
00783
00784 if (startLine == endLine)
00785 {
00786 editRemoveText (startLine, startCol, endCol-startCol);
00787 }
00788 else if ((startLine+1) == endLine)
00789 {
00790 if ( (m_buffer->plainLine(startLine)->length()-startCol) > 0 )
00791 editRemoveText (startLine, startCol, m_buffer->plainLine(startLine)->length()-startCol);
00792
00793 editRemoveText (startLine+1, 0, endCol);
00794 editUnWrapLine (startLine);
00795 }
00796 else
00797 {
00798 for (uint line = endLine; line >= startLine; line--)
00799 {
00800 if ((line > startLine) && (line < endLine))
00801 {
00802 editRemoveLine (line);
00803 }
00804 else
00805 {
00806 if (line == endLine)
00807 {
00808 if ( endLine <= lastLine() )
00809 editRemoveText (line, 0, endCol);
00810 }
00811 else
00812 {
00813 if ( (m_buffer->plainLine(line)->length()-startCol) > 0 )
00814 editRemoveText (line, startCol, m_buffer->plainLine(line)->length()-startCol);
00815
00816 editUnWrapLine (startLine);
00817 }
00818 }
00819
00820 if ( line == 0 )
00821 break;
00822 }
00823 }
00824 }
00825 else
00826 {
00827 if ( endLine > lastLine() )
00828 endLine = lastLine ();
00829
00830 for (uint line = endLine; line >= startLine; line--)
00831 {
00832
00833 editRemoveText (line, startCol, endCol-startCol);
00834
00835 if ( line == 0 )
00836 break;
00837 }
00838 }
00839
00840 editEnd ();
00841 emit textRemoved();
00842 return true;
00843 }
00844
00845 bool KateDocument::insertLine( uint l, const QString &str )
00846 {
00847 if (!isReadWrite())
00848 return false;
00849
00850 if (l > numLines())
00851 return false;
00852
00853 return editInsertLine (l, str);
00854 }
00855
00856 bool KateDocument::removeLine( uint line )
00857 {
00858 if (!isReadWrite())
00859 return false;
00860
00861 if (line > lastLine())
00862 return false;
00863
00864 return editRemoveLine (line);
00865 }
00866
00867 uint KateDocument::length() const
00868 {
00869 uint l = 0;
00870
00871 for (uint i = 0; i < m_buffer->count(); i++)
00872 {
00873 KateTextLine::Ptr line = m_buffer->plainLine(i);
00874
00875 if (line)
00876 l += line->length();
00877 }
00878
00879 return l;
00880 }
00881
00882 uint KateDocument::numLines() const
00883 {
00884 return m_buffer->count();
00885 }
00886
00887 uint KateDocument::numVisLines() const
00888 {
00889 return m_buffer->countVisible ();
00890 }
00891
00892 int KateDocument::lineLength ( uint line ) const
00893 {
00894 KateTextLine::Ptr l = m_buffer->plainLine(line);
00895
00896 if (!l)
00897 return -1;
00898
00899 return l->length();
00900 }
00901
00902
00903
00904
00905
00906
00907 void KateDocument::editStart (bool withUndo)
00908 {
00909 editSessionNumber++;
00910
00911 if (editSessionNumber > 1)
00912 return;
00913
00914 editIsRunning = true;
00915 editWithUndo = withUndo;
00916
00917 if (editWithUndo)
00918 undoStart();
00919 else
00920 undoCancel();
00921
00922 for (uint z = 0; z < m_views.count(); z++)
00923 {
00924 m_views.at(z)->editStart ();
00925 }
00926
00927 m_buffer->editStart ();
00928 }
00929
00930 void KateDocument::undoStart()
00931 {
00932 if (m_editCurrentUndo || (m_activeView && m_activeView->imComposeEvent())) return;
00933
00934
00935 if ((config()->undoSteps() > 0) && (undoItems.count() > config()->undoSteps()))
00936 {
00937 undoItems.setAutoDelete(true);
00938 undoItems.removeFirst();
00939 undoItems.setAutoDelete(false);
00940 docWasSavedWhenUndoWasEmpty = false;
00941 }
00942
00943
00944 m_editCurrentUndo = new KateUndoGroup(this);
00945 }
00946
00947 void KateDocument::undoEnd()
00948 {
00949 if (m_activeView && m_activeView->imComposeEvent())
00950 return;
00951
00952 if (m_editCurrentUndo)
00953 {
00954 bool changedUndo = false;
00955
00956 if (m_editCurrentUndo->isEmpty())
00957 delete m_editCurrentUndo;
00958 else if (!m_undoDontMerge && undoItems.last() && undoItems.last()->merge(m_editCurrentUndo,m_undoComplexMerge))
00959 delete m_editCurrentUndo;
00960 else
00961 {
00962 undoItems.append(m_editCurrentUndo);
00963 changedUndo = true;
00964 }
00965
00966 m_undoDontMerge = false;
00967 m_undoIgnoreCancel = true;
00968
00969 m_editCurrentUndo = 0L;
00970
00971
00972
00973 m_undoMergeTimer->start(5000, true);
00974
00975 if (changedUndo)
00976 emit undoChanged();
00977 }
00978 }
00979
00980 void KateDocument::undoCancel()
00981 {
00982 if (m_undoIgnoreCancel) {
00983 m_undoIgnoreCancel = false;
00984 return;
00985 }
00986
00987 m_undoDontMerge = true;
00988
00989 Q_ASSERT(!m_editCurrentUndo);
00990
00991
00992 delete m_editCurrentUndo;
00993 m_editCurrentUndo = 0L;
00994 }
00995
00996 void KateDocument::undoSafePoint() {
00997 Q_ASSERT(m_editCurrentUndo);
00998 if (!m_editCurrentUndo) return;
00999 m_editCurrentUndo->safePoint();
01000 }
01001
01002
01003
01004
01005 void KateDocument::editEnd ()
01006 {
01007 if (editSessionNumber == 0)
01008 return;
01009
01010
01011 if (m_buffer->editChanged() && (editSessionNumber == 1))
01012 if (editWithUndo && config()->wordWrap())
01013 wrapText (m_buffer->editTagStart(), m_buffer->editTagEnd());
01014
01015 editSessionNumber--;
01016
01017 if (editSessionNumber > 0)
01018 return;
01019
01020
01021
01022 m_buffer->editEnd ();
01023
01024 if (editWithUndo)
01025 undoEnd();
01026
01027
01028 for (uint z = 0; z < m_views.count(); z++)
01029 m_views.at(z)->editEnd (m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
01030
01031 if (m_buffer->editChanged())
01032 {
01033 setModified(true);
01034 emit textChanged ();
01035 }
01036
01037 editIsRunning = false;
01038 }
01039
01040 bool KateDocument::wrapText (uint startLine, uint endLine)
01041 {
01042 uint col = config()->wordWrapAt();
01043
01044 if (col == 0)
01045 return false;
01046
01047 editStart ();
01048
01049 for (uint line = startLine; (line <= endLine) && (line < numLines()); line++)
01050 {
01051 KateTextLine::Ptr l = m_buffer->line(line);
01052
01053 if (!l)
01054 return false;
01055
01056 kdDebug (13020) << "try wrap line: " << line << endl;
01057
01058 if (l->lengthWithTabs(m_buffer->tabWidth()) > col)
01059 {
01060 KateTextLine::Ptr nextl = m_buffer->line(line+1);
01061
01062 kdDebug (13020) << "do wrap line: " << line << endl;
01063
01064 const QChar *text = l->text();
01065 uint eolPosition = l->length()-1;
01066
01067
01068 uint x = 0;
01069 const QString & t = l->string();
01070 uint z2 = 0;
01071 for ( ; z2 < l->length(); z2++)
01072 {
01073 if (t[z2] == QChar('\t'))
01074 x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
01075 else
01076 x++;
01077
01078 if (x > col)
01079 break;
01080 }
01081
01082 uint searchStart = kMin (z2, l->length()-1);
01083
01084
01085
01086 if (searchStart == eolPosition && text[searchStart].isSpace())
01087 searchStart--;
01088
01089
01090
01091
01092
01093
01094
01095 int z = 0;
01096 uint nw = 0;
01097 for (z=searchStart; z > 0; z--)
01098 {
01099 if (text[z].isSpace()) break;
01100 if ( ! nw && highlight()->canBreakAt( text[z] , l->attribute(z) ) )
01101 nw = z;
01102 }
01103
01104 if (z > 0)
01105 {
01106
01107 editRemoveText (line, z, 1);
01108 }
01109 else
01110 {
01111
01112
01113
01114 if ( nw && nw < col ) nw++;
01115 z = nw ? nw : col;
01116 }
01117
01118 if (nextl && !nextl->isAutoWrapped())
01119 {
01120 editWrapLine (line, z, true);
01121 editMarkLineAutoWrapped (line+1, true);
01122
01123 endLine++;
01124 }
01125 else
01126 {
01127 if (nextl && (nextl->length() > 0) && !nextl->getChar(0).isSpace() && ((l->length() < 1) || !l->getChar(l->length()-1).isSpace()))
01128 editInsertText (line+1, 0, QString (" "));
01129
01130 bool newLineAdded = false;
01131 editWrapLine (line, z, false, &newLineAdded);
01132
01133 editMarkLineAutoWrapped (line+1, true);
01134
01135 endLine++;
01136 }
01137 }
01138 }
01139
01140 editEnd ();
01141
01142 return true;
01143 }
01144
01145 void KateDocument::editAddUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const QString &text)
01146 {
01147 if (editIsRunning && editWithUndo && m_editCurrentUndo) {
01148 m_editCurrentUndo->addItem(type, line, col, len, text);
01149
01150
01151 if (redoItems.count()) {
01152 redoItems.setAutoDelete(true);
01153 redoItems.clear();
01154 redoItems.setAutoDelete(false);
01155 }
01156 }
01157 }
01158
01159 bool KateDocument::editInsertText ( uint line, uint col, const QString &str )
01160 {
01161 if (!isReadWrite())
01162 return false;
01163
01164 QString s = str;
01165
01166 KateTextLine::Ptr l = m_buffer->line(line);
01167
01168 if (!l)
01169 return false;
01170
01171 if ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo )
01172 {
01173 uint tw = config()->tabWidth();
01174 int pos = 0;
01175 uint l = 0;
01176 while ( (pos = s.find('\t')) > -1 )
01177 {
01178 l = tw - ( (col + pos)%tw );
01179 s.replace( pos, 1, QString().fill( ' ', l ) );
01180 }
01181 }
01182
01183 editStart ();
01184
01185 editAddUndo (KateUndoGroup::editInsertText, line, col, s.length(), s);
01186
01187 l->insertText (col, s.length(), s.unicode());
01188
01189
01190 m_buffer->changeLine(line);
01191
01192 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01193 it.current()->editTextInserted (line, col, s.length());
01194
01195 editEnd ();
01196
01197 return true;
01198 }
01199
01200 bool KateDocument::editRemoveText ( uint line, uint col, uint len )
01201 {
01202 if (!isReadWrite())
01203 return false;
01204
01205 KateTextLine::Ptr l = m_buffer->line(line);
01206
01207 if (!l)
01208 return false;
01209
01210 editStart ();
01211
01212 editAddUndo (KateUndoGroup::editRemoveText, line, col, len, l->string().mid(col, len));
01213
01214 l->removeText (col, len);
01215 removeTrailingSpace( line );
01216
01217 m_buffer->changeLine(line);
01218
01219 for( QPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
01220 it.current()->editTextRemoved (line, col, len);
01221
01222 editEnd ();
01223
01224 return true;
01225 }
01226
01227 bool KateDocument::editMarkLineAutoWrapped ( uint line, bool autowrapped )
01228 {
01229 if (!isReadWrite())
01230 return false;
01231
01232 KateTextLine::Ptr l = m_buffer->line(line);
01233
01234 if (!l)
01235 return false;
01236
01237 editStart ();
01238
01239 editAddUndo (KateUndoGroup::editMarkLineAutoWrapped, line, autowrapped ? 1 : 0, 0, QString::null);
01240
01241 l->setAutoWrapped (autowrapped);
01242
01243 m_buffer->changeLine(line);
01244
01245 editEnd ();
01246
01247 return true;
01248 }
01249
01250 bool KateDocument::editWrapLine ( uint line, uint col, bool newLine, bool *newLineAdded)
01251 {
01252 if (!isReadWrite())
01253 return false;
01254
01255 KateTextLine::Ptr l = m_buffer->line(line);
01256
01257 if (!l)
01258 return false;
01259
01260 editStart ();
01261
01262 KateTextLine::Ptr nextLine = m_buffer->line(line+1);
01263
01264 int pos = l->length() - col;
01265
01266 if (pos < 0)
01267 pos = 0;
01268
01269 editAddUndo (KateUndoGroup::editWrapLine, line, col, pos, (!nextLine || newLine) ? "1" : "0");
01270
01271 if (!nextLine || newLine)
01272 {
01273 KateTextLine::Ptr textLine = new KateTextLine();
01274
01275 textLine->insertText (0, pos, l->text()+col, l->attributes()+col);
01276 l->truncate(col);
01277
01278 m_buffer->insertLine (line+1, textLine);
01279 m_buffer->changeLine(line);
01280
01281 QPtrList<KTextEditor::Mark> list;
01282 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
01283 {
01284 if( it.current()->line >