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