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