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