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