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