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 QWidget *w = widget ();
02461 if (!w && !m_views.isEmpty ())
02462 w = m_views.first();
02463
02464 if (w)
02465 m_job->setWindow (w->topLevelWidget());
02466
02467 emit started( m_job );
02468
02469 return true;
02470 }
02471 }
02472
02473 void KateDocument::slotDataKate ( KIO::Job *, const QByteArray &data )
02474 {
02475 kdDebug(13020) << "KateDocument::slotData" << endl;
02476
02477 if (!m_tempFile || !m_tempFile->file())
02478 return;
02479
02480 m_tempFile->file()->writeBlock (data);
02481 }
02482
02483 void KateDocument::slotFinishedKate ( KIO::Job * job )
02484 {
02485 kdDebug(13020) << "KateDocument::slotJobFinished" << endl;
02486
02487 if (!m_tempFile)
02488 return;
02489
02490 delete m_tempFile;
02491 m_tempFile = 0;
02492 m_job = 0;
02493
02494 if (job->error())
02495 emit canceled( job->errorString() );
02496 else
02497 {
02498 if ( openFile(job) )
02499 emit setWindowCaption( m_url.prettyURL() );
02500
02501 emit completed();
02502 }
02503 }
02504
02505 void KateDocument::abortLoadKate()
02506 {
02507 if ( m_job )
02508 {
02509 kdDebug(13020) << "Aborting job " << m_job << endl;
02510 m_job->kill();
02511 m_job = 0;
02512 }
02513
02514 delete m_tempFile;
02515 m_tempFile = 0;
02516 }
02517
02518 bool KateDocument::openFile()
02519 {
02520 return openFile (0);
02521 }
02522
02523 bool KateDocument::openFile(KIO::Job * job)
02524 {
02525
02526 activateDirWatch ();
02527
02528
02529
02530
02531 if (job)
02532 {
02533 QString metaDataCharset = job->queryMetaData("charset");
02534
02535 if (!metaDataCharset.isEmpty ())
02536 setEncoding (metaDataCharset);
02537 }
02538
02539
02540
02541
02542 QString serviceType = m_extension->urlArgs().serviceType.simplifyWhiteSpace();
02543 int pos = serviceType.find(';');
02544 if (pos != -1)
02545 setEncoding (serviceType.mid(pos+1));
02546
02547
02548 bool success = m_buffer->openFile (m_file);
02549
02550
02551
02552
02553 if (success)
02554 {
02555 if (m_highlight && !m_url.isLocalFile()) {
02556
02557 m_buffer->setHighlight(m_highlight);
02558 }
02559
02560
02561 if (!hlSetByUser)
02562 {
02563 int hl (KateHlManager::self()->detectHighlighting (this));
02564
02565 if (hl >= 0)
02566 internalSetHlMode(hl);
02567 }
02568
02569 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
02570
02571
02572 readVariables();
02573
02574
02575 createDigest( m_digest );
02576 }
02577
02578
02579
02580
02581 updateViews();
02582
02583
02584
02585
02586 emit fileNameChanged ();
02587
02588
02589
02590
02591 setDocName (QString::null);
02592
02593
02594
02595
02596 if (m_modOnHd)
02597 {
02598 m_modOnHd = false;
02599 m_modOnHdReason = 0;
02600 emit modifiedOnDisc (this, m_modOnHd, 0);
02601 }
02602
02603
02604
02605
02606 if (s_openErrorDialogsActivated)
02607 {
02608 if (!success && m_buffer->loadingBorked())
02609 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()));
02610 else if (!success)
02611 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()));
02612 }
02613
02614
02615
02616
02617 return success;
02618 }
02619
02620 bool KateDocument::save()
02621 {
02622
02623 bool l ( url().isLocalFile() );
02624 if ( ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles ) ||
02625 ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
02626 && isModified() ) {
02627
02628 KURL u( url() );
02629 u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
02630 if ( ! KIO::NetAccess::upload( url().path(), u, kapp->mainWidget() ) )
02631 kdDebug(13020)<<"backing up failed ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
02632 }
02633
02634 return KParts::ReadWritePart::save();
02635 }
02636
02637 bool KateDocument::saveFile()
02638 {
02639
02640
02641
02642 bool reallySaveIt = !m_buffer->loadingBorked() || (KMessageBox::warningYesNo(widget(),
02643 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);
02644
02645 if ( !url().isEmpty() )
02646 {
02647 if (s_fileChangedDialogsActivated && m_modOnHd)
02648 {
02649 QString str = reasonedMOHString() + "\n\n";
02650
02651 if (!isModified())
02652 {
02653 if (!(KMessageBox::warningYesNo(0,
02654 str + i18n("Do you really want to save this unmodified file? You could overwrite changed data in the file on disk.")) == KMessageBox::Yes))
02655 reallySaveIt = false;
02656 }
02657 else
02658 {
02659 if (!(KMessageBox::warningYesNo(0,
02660 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))
02661 reallySaveIt = false;
02662 }
02663 }
02664 }
02665
02666
02667
02668
02669 bool canEncode = true;
02670
02671 if (reallySaveIt)
02672 canEncode = m_buffer->canEncode ();
02673
02674
02675
02676
02677 bool success = false;
02678
02679
02680 deactivateDirWatch ();
02681
02682
02683
02684
02685 if (reallySaveIt && canEncode)
02686 success = m_buffer->saveFile (m_file);
02687
02688
02689 createDigest( m_digest );
02690
02691
02692 activateDirWatch ();
02693
02694
02695
02696
02697 if (success)
02698 {
02699
02700 if (!hlSetByUser)
02701 {
02702 int hl (KateHlManager::self()->detectHighlighting (this));
02703
02704 if (hl >= 0)
02705 internalSetHlMode(hl);
02706 }
02707
02708
02709 updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
02710
02711
02712 readVariables();
02713 }
02714
02715
02716
02717
02718 emit fileNameChanged ();
02719
02720
02721
02722
02723 setDocName (QString::null);
02724
02725
02726
02727
02728 if (success && m_modOnHd)
02729 {
02730 m_modOnHd = false;
02731 m_modOnHdReason = 0;
02732 emit modifiedOnDisc (this, m_modOnHd, 0);
02733 }
02734
02735
02736
02737
02738 if (reallySaveIt && !canEncode)
02739 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."));
02740 else if (reallySaveIt && !success)
02741 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()));
02742
02743
02744
02745
02746 return success;
02747 }
02748
02749 void KateDocument::activateDirWatch ()
02750 {
02751
02752 if (m_file == m_dirWatchFile)
02753 return;
02754
02755
02756 deactivateDirWatch ();
02757
02758
02759 if (m_url.isLocalFile() && !m_file.isEmpty())
02760 {
02761 KateFactory::self()->dirWatch ()->addFile (m_file);
02762 m_dirWatchFile = m_file;
02763 }
02764 }
02765
02766 void KateDocument::deactivateDirWatch ()
02767 {
02768 if (!m_dirWatchFile.isEmpty())
02769 KateFactory::self()->dirWatch ()->removeFile (m_dirWatchFile);
02770
02771 m_dirWatchFile = QString::null;
02772 }
02773
02774 bool KateDocument::closeURL()
02775 {
02776 abortLoadKate();
02777
02778
02779
02780
02781 if ( !m_reloading && !url().isEmpty() )
02782 {
02783 if (s_fileChangedDialogsActivated && m_modOnHd)
02784 {
02785 if (!(KMessageBox::warningYesNo(0,
02786 reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur.")) == KMessageBox::Yes))
02787 return false;
02788 }
02789 }
02790
02791
02792
02793
02794 if (!KParts::ReadWritePart::closeURL ())
02795 return false;
02796
02797
02798 deactivateDirWatch ();
02799
02800
02801
02802
02803 m_url = KURL ();
02804 m_file = QString::null;
02805
02806
02807 if (m_modOnHd)
02808 {
02809 m_modOnHd = false;
02810 m_modOnHdReason = 0;
02811 emit modifiedOnDisc (this, m_modOnHd, 0);
02812 }
02813
02814
02815 m_buffer->clear();
02816
02817
02818 clearMarks ();
02819
02820
02821 clearUndo();
02822 clearRedo();
02823
02824
02825 setModified(false);
02826
02827
02828 internalSetHlMode(0);
02829
02830
02831 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
02832 {
02833
02834
02835 view->setCursorPositionInternal(0, 0, 1, false);
02836 view->updateView(true);
02837 }
02838
02839
02840 emit fileNameChanged ();
02841
02842
02843 setDocName (QString::null);
02844
02845
02846 return true;
02847 }
02848
02849 void KateDocument::setReadWrite( bool rw )
02850 {
02851 if (isReadWrite() != rw)
02852 {
02853 KParts::ReadWritePart::setReadWrite (rw);
02854
02855 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
02856 {
02857 view->slotUpdate();
02858 view->slotReadWriteChanged ();
02859 }
02860 }
02861 }
02862
02863 void KateDocument::setModified(bool m) {
02864
02865 if (isModified() != m) {
02866 KParts::ReadWritePart::setModified (m);
02867
02868 for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
02869 {
02870 view->slotUpdate();
02871 }
02872
02873 emit modifiedChanged ();
02874 emit modStateChanged ((Kate::Document *)this);
02875 }
02876 if ( m == false && ! undoItems.isEmpty() )
02877 {
02878 lastUndoGroupWhenSaved = undoItems.last();
02879 }
02880
02881 if ( m == false ) docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
02882 }
02883
02884
02885
02886
02887 void KateDocument::makeAttribs()
02888 {
02889 m_highlight->clearAttributeArrays ();
02890
02891 for (uint z = 0; z < m_views.count(); z++)
02892 m_views.at(z)->renderer()->updateAttributes ();
02893
02894 m_buffer->invalidateHighlighting();
02895
02896 tagAll ();
02897 }
02898
02899
02900 void KateDocument::internalHlChanged()
02901 {
02902 makeAttribs();
02903 }
02904
02905 void KateDocument::addView(KTextEditor::View *view) {
02906 if (!view)
02907 return;
02908
02909 m_views.append( (KateView *) view );
02910 m_textEditViews.append( view );
02911
02912
02913 const KateFileType *t = 0;
02914 if ((m_fileType > -1) && (t = KateFactory::self()->fileTypeManager()->fileType(m_fileType)))
02915 readVariableLine (t->varLine, true);
02916
02917
02918 readVariables (true);
02919
02920 m_activeView = (KateView *) view;
02921 }
02922
02923 void KateDocument::removeView(KTextEditor::View *view) {
02924 if (!view)
02925 return;
02926
02927 if (m_activeView == view)
02928 m_activeView = 0L;
02929
02930 m_views.removeRef( (KateView *) view );
02931 m_textEditViews.removeRef( view );
02932 }
02933
02934 void KateDocument::addSuperCursor(KateSuperCursor *cursor, bool privateC) {
02935 if (!cursor)
02936 return;
02937
02938 m_superCursors.append( cursor );
02939
02940 if (!privateC)
02941 myCursors.append( cursor );
02942 }
02943
02944 void KateDocument::removeSuperCursor(KateSuperCursor *cursor, bool privateC) {
02945 if (!cursor)
02946 return;
02947
02948 if (!privateC)
02949 myCursors.removeRef( cursor );
02950
02951 m_superCursors.removeRef( cursor );
02952 }
02953
02954 bool KateDocument::ownedView(KateView *view) {
02955
02956 return (m_views.containsRef(view) > 0);
02957 }
02958
02959 bool KateDocument::isLastView(int numViews) {
02960 return ((int) m_views.count() == numViews);
02961 }
02962
02963 uint KateDocument::currentColumn( const KateTextCursor& cursor )
02964 {
02965 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
02966
02967 if (textLine)
02968 return textLine->cursorX(cursor.col(), config()->tabWidth());
02969 else
02970 return 0;
02971 }
02972
02973 bool KateDocument::typeChars ( KateView *view, const QString &chars )
02974 {
02975 KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorLine ());
02976
02977 if (!textLine)
02978 return false;
02979
02980 int oldLine = view->cursorLine ();
02981 int oldCol = view->cursorColumnReal ();
02982
02983 bool bracketInserted = false;
02984 QString buf;
02985 QChar c;
02986 for( uint z = 0; z < chars.length(); z++ )
02987 {
02988 QChar ch = c = chars[z];
02989
02990 if (ch.isPrint() || ch == '\t')
02991 {
02992 buf.append (ch);
02993
02994 if (!bracketInserted && (config()->configFlags() & KateDocument::cfAutoBrackets))
02995 {
02996 if (ch == '(') { bracketInserted = true; buf.append (')'); }
02997 if (ch == '[') { bracketInserted = true; buf.append (']'); }
02998 if (ch == '{') { bracketInserted = true; buf.append ('}'); }
02999 }
03000 }
03001 }
03002
03003 if (buf.isEmpty())
03004 return false;
03005
03006 editStart ();
03007
03008 if (!(config()->configFlags() & KateDocument::cfPersistent) && hasSelection() )
03009 removeSelectedText();
03010
03011 if (config()->configFlags() & KateDocument::cfOvr)
03012 removeText (view->cursorLine(), view->cursorColumnReal(), view->cursorLine(), QMIN( view->cursorColumnReal()+buf.length(), textLine->length() ) );
03013
03014 insertText (view->cursorLine(), view->cursorColumnReal(), buf);
03015 m_indenter->processChar(c);
03016
03017 editEnd ();
03018
03019 if (bracketInserted)
03020 view->setCursorPositionInternal (view->cursorLine(), view->cursorColumnReal()-1);
03021
03022 emit charactersInteractivelyInserted (oldLine, oldCol, chars);
03023
03024 return true;
03025 }
03026
03027 void KateDocument::newLine( KateTextCursor& c, KateViewInternal *v )
03028 {
03029 editStart();
03030
03031 if( !(config()->configFlags() & cfPersistent) && hasSelection() )
03032 removeSelectedText();
03033
03034
03035 c = v->getCursor ();
03036
03037 if (c.line() > (int)lastLine())
03038 c.setLine(lastLine());
03039
03040 uint ln = c.line();
03041
03042 KateTextLine::Ptr textLine = kateTextLine(c.line());
03043 if (c.col() > (int)textLine->length())
03044 c.setCol(textLine->length());
03045
03046 if (!(config()->configFlags() & KateDocument::cfAutoIndent))
03047 {
03048 insertText( c.line(), c.col(), "\n" );
03049 c.setPos(c.line() + 1, 0);
03050 }
03051 else
03052 {
03053 int pos = textLine->firstChar();
03054 if (c.col() < pos)
03055 c.setCol(pos);
03056
03057 insertText (c.line(), c.col(), "\n");
03058
03059 KateDocCursor cursor (c.line() + 1, pos, this);
03060 m_indenter->processNewline(cursor, true);
03061 c.setPos(cursor);
03062 }
03063
03064 removeTrailingSpace( ln );
03065
03066 editEnd();
03067 }
03068
03069 void KateDocument::transpose( const KateTextCursor& cursor)
03070 {
03071 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03072
03073 if (!textLine || (textLine->length() < 2))
03074 return;
03075
03076 uint col = cursor.col();
03077
03078 if (col > 0)
03079 col--;
03080
03081 if ((textLine->length() - col) < 2)
03082 return;
03083
03084 uint line = cursor.line();
03085 QString s;
03086
03087
03088
03089 s.append (textLine->getChar(col+1));
03090 s.append (textLine->getChar(col));
03091
03092
03093
03094 editStart ();
03095 editRemoveText (line, col, 2);
03096 editInsertText (line, col, s);
03097 editEnd ();
03098 }
03099
03100 void KateDocument::backspace( const KateTextCursor& c )
03101 {
03102 if( !(config()->configFlags() & cfPersistent) && hasSelection() ) {
03103 removeSelectedText();
03104 return;
03105 }
03106
03107 uint col = QMAX( c.col(), 0 );
03108 uint line = QMAX( c.line(), 0 );
03109
03110 if ((col == 0) && (line == 0))
03111 return;
03112
03113 if (col > 0)
03114 {
03115 if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
03116 {
03117
03118
03119 removeText(line, col-1, line, col);
03120 }
03121 else
03122 {
03123
03124
03125 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03126 int colX = textLine->cursorX(col, config()->tabWidth());
03127 int pos = textLine->firstChar();
03128 if (pos > 0)
03129 pos = textLine->cursorX(pos, config()->tabWidth());
03130
03131 if (pos < 0 || pos >= (int)colX)
03132 {
03133
03134
03135 int y = line;
03136 while (--y >= 0)
03137 {
03138 textLine = m_buffer->plainLine(y);
03139 pos = textLine->firstChar();
03140
03141 if (pos >= 0)
03142 {
03143 pos = textLine->cursorX(pos, config()->tabWidth());
03144 if (pos < (int)colX)
03145 {
03146 replaceWithOptimizedSpace(line, col, pos, config()->configFlags());
03147 break;
03148 }
03149 }
03150 }
03151 if (y < 0) {
03152
03153 removeText(line, 0, line, col);
03154 }
03155 }
03156 else
03157 removeText(line, col-1, line, col);
03158 }
03159 }
03160 else
03161 {
03162
03163 if (line >= 1)
03164 {
03165 KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
03166 if (config()->wordWrap() && textLine->endingWith(QString::fromLatin1(" ")))
03167 {
03168
03169 removeText (line-1, textLine->length()-1, line, 0);
03170 }
03171 else
03172 removeText (line-1, textLine->length(), line, 0);
03173 }
03174 }
03175
03176 emit backspacePressed();
03177 }
03178
03179 void KateDocument::del( const KateTextCursor& c )
03180 {
03181 if ( !(config()->configFlags() & cfPersistent) && hasSelection() ) {
03182 removeSelectedText();
03183 return;
03184 }
03185
03186 if( c.col() < (int) m_buffer->plainLine(c.line())->length())
03187 {
03188 removeText(c.line(), c.col(), c.line(), c.col()+1);
03189 }
03190 else
03191 {
03192 removeText(c.line(), c.col(), c.line()+1, 0);
03193 }
03194 }
03195
03196 void KateDocument::cut()
03197 {
03198 if (!hasSelection())
03199 return;
03200
03201 copy();
03202 removeSelectedText();
03203 }
03204
03205 void KateDocument::copy()
03206 {
03207 if (!hasSelection())
03208 return;
03209
03210 QApplication::clipboard()->setText(selection ());
03211 }
03212
03213 void KateDocument::paste ( KateView* view )
03214 {
03215 QString s = QApplication::clipboard()->text();
03216
03217 if (s.isEmpty())
03218 return;
03219
03220 m_undoDontMerge = true;
03221
03222 editStart ();
03223
03224 if (!(config()->configFlags() & KateDocument::cfPersistent) && hasSelection() )
03225 removeSelectedText();
03226
03227 uint line = view->cursorLine ();
03228 uint column = view->cursorColumnReal ();
03229
03230 insertText ( line, column, s, blockSelect );
03231
03232 KateDocCursor begin((int)editTagLineStart, 0, this);
03233 KateDocCursor end((int)editTagLineEnd, 0, this);
03234
03235 editEnd();
03236
03237
03238
03239
03240 if (blockSelect)
03241 {
03242 uint lines = s.contains (QChar ('\n'));
03243 view->setCursorPositionInternal (line+lines, column);
03244 }
03245
03246 if (m_indenter->canProcessLine())
03247 {
03248 editStart();
03249 m_indenter->processSection (begin, end);
03250 editEnd();
03251 }
03252
03253 m_undoDontMerge = true;
03254 }
03255
03256 void KateDocument::selectWord( const KateTextCursor& cursor )
03257 {
03258 int start, end, len;
03259
03260 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03261 if(!textLine)
03262 return;
03263
03264 len = textLine->length();
03265 start = end = cursor.col();
03266 while (start > 0 && m_highlight->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
03267 while (end < len && m_highlight->isInWord(textLine->getChar(end), textLine->attribute(start - 1))) end++;
03268 if (end <= start) return;
03269
03270 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03271 clearSelection ();
03272
03273 setSelection (cursor.line(), start, cursor.line(), end);
03274 }
03275
03276 void KateDocument::selectLine( const KateTextCursor& cursor )
03277 {
03278 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03279 clearSelection ();
03280
03281 setSelection (cursor.line(), 0, cursor.line()+1, 0 );
03282 }
03283
03284 void KateDocument::selectLength( const KateTextCursor& cursor, int length )
03285 {
03286 int start, end;
03287
03288 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
03289 start = cursor.col();
03290 end = start + length;
03291 if (end <= start) return;
03292
03293 if (!(config()->configFlags() & KateDocument::cfKeepSelection))
03294 clearSelection ();
03295 setSelection (cursor.line(), start, cursor.line(), end);
03296 }
03297
03298 void KateDocument::insertIndentChars ( KateView *view )
03299 {
03300 editStart ();
03301
03302 QString s;
03303 if (config()->configFlags() & KateDocument::cfSpaceIndent)
03304 {
03305 int width = config()->indentationWidth();
03306 s.fill (' ', width - (view->cursorColumnReal() % width));
03307 }
03308 else
03309 s.append ('\t');
03310
03311 insertText (view->cursorLine(), view->cursorColumnReal(), s);
03312
03313 editEnd ();
03314 }
03315
03316 void KateDocument::indent ( KateView *, uint line, int change)
03317 {
03318 editStart ();
03319
03320 if (!hasSelection())
03321 {
03322
03323 optimizeLeadingSpace(line, config()->configFlags(), change);
03324 }
03325 else
03326 {
03327 int sl = selectStart.line();
03328 int el = selectEnd.line();
03329 int ec = selectEnd.col();
03330
03331 if ((ec == 0) && ((el-1) >= 0))
03332 {
03333 el--;
03334 }
03335
03336 if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
03337
03338
03339 int adjustedChange = -change;
03340
03341 for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
03342 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03343 int firstChar = textLine->firstChar();
03344 if (firstChar >= 0 && (lineSelected(line) || lineHasSelected(line))) {
03345 int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
03346 if (maxUnindent < adjustedChange)
03347 adjustedChange = maxUnindent;
03348 }
03349 }
03350
03351 change = -adjustedChange;
03352 }
03353
03354 for (line = sl; (int) line <= el; line++) {
03355 if (lineSelected(line) || lineHasSelected(line)) {
03356 optimizeLeadingSpace(line, config()->configFlags(), change);
03357 }
03358 }
03359 }
03360
03361 editEnd ();
03362 }
03363
03364 void KateDocument::align(uint line)
03365 {
03366 if (m_indenter->canProcessLine())
03367 {
03368 editStart ();
03369
03370 if (!hasSelection())
03371 {
03372 KateDocCursor curLine(line, 0, this);
03373 m_indenter->processLine (curLine);
03374 editEnd ();
03375 activeView()->setCursorPosition (line, curLine.col());
03376 }
03377 else
03378 {
03379 m_indenter->processSection(selectStart, selectEnd);
03380 editEnd ();
03381 }
03382 }
03383 }
03384
03385
03386
03387
03388
03389
03390
03391
03392
03393
03394 void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
03395 {
03396 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03397
03398 int first_char = textline->firstChar();
03399
03400 int w = 0;
03401 if (flags & KateDocument::cfSpaceIndent)
03402 w = config()->indentationWidth();
03403 else
03404 w = config()->tabWidth();
03405
03406 if (first_char < 0)
03407 first_char = textline->length();
03408
03409 int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
03410 if (space < 0)
03411 space = 0;
03412
03413 if (!(flags & KateDocument::cfKeepExtraSpaces))
03414 {
03415 uint extra = space % w;
03416
03417 space -= extra;
03418 if (extra && change < 0) {
03419
03420 space += w;
03421 }
03422 }
03423
03424
03425 replaceWithOptimizedSpace(line, first_char, space, flags);
03426 }
03427
03428 void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
03429 {
03430 uint length;
03431 QString new_space;
03432
03433 if (flags & KateDocument::cfSpaceIndent) {
03434 length = space;
03435 new_space.fill(' ', length);
03436 }
03437 else {
03438 length = space / config()->tabWidth();
03439 new_space.fill('\t', length);
03440
03441 QString extra_space;
03442 extra_space.fill(' ', space % config()->tabWidth());
03443 length += space % config()->tabWidth();
03444 new_space += extra_space;
03445 }
03446
03447 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03448 uint change_from;
03449 for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
03450 if (textline->getChar(change_from) != new_space[change_from])
03451 break;
03452 }
03453
03454 editStart();
03455
03456 if (change_from < upto_column)
03457 removeText(line, change_from, line, upto_column);
03458
03459 if (change_from < length)
03460 insertText(line, change_from, new_space.right(length - change_from));
03461
03462 editEnd();
03463 }
03464
03465
03466
03467
03468
03469 bool KateDocument::removeStringFromBegining(int line, QString &str)
03470 {
03471 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03472
03473 int index = 0;
03474 bool there = false;
03475
03476 if (textline->startingWith(str))
03477 there = true;
03478 else
03479 {
03480 index = textline->firstChar ();
03481
03482 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03483 there = true;
03484 }
03485
03486 if (there)
03487 {
03488
03489 removeText (line, index, line, index+str.length());
03490 }
03491
03492 return there;
03493 }
03494
03495
03496
03497
03498
03499 bool KateDocument::removeStringFromEnd(int line, QString &str)
03500 {
03501 KateTextLine::Ptr textline = m_buffer->plainLine(line);
03502
03503 int index = 0;
03504 bool there = false;
03505
03506 if(textline->endingWith(str))
03507 {
03508 index = textline->length() - str.length();
03509 there = true;
03510 }
03511 else
03512 {
03513 index = textline->lastChar ()-str.length()+1;
03514
03515 if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
03516 there = true;
03517 }
03518
03519 if (there)
03520 {
03521
03522 removeText (line, index, line, index+str.length());
03523 }
03524
03525 return there;
03526 }
03527
03528
03529
03530
03531
03532 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
03533 {
03534 QString commentLineMark = m_highlight->getCommentSingleLineStart( attrib ) + " ";
03535 insertText (line, 0, commentLineMark);
03536 }
03537
03538
03539
03540
03541
03542 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
03543 {
03544 QString shortCommentMark = m_highlight->getCommentSingleLineStart( attrib );
03545 QString longCommentMark = shortCommentMark + " ";
03546
03547 editStart();
03548
03549
03550 bool removed = (removeStringFromBegining(line, longCommentMark)
03551 || removeStringFromBegining(line, shortCommentMark));
03552
03553 editEnd();
03554
03555 return removed;
03556 }
03557
03558
03559
03560
03561
03562 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
03563 {
03564 QString startCommentMark = m_highlight->getCommentStart( attrib ) + " ";
03565 QString stopCommentMark = " " + m_highlight->getCommentEnd( attrib );
03566
03567 editStart();
03568
03569
03570 insertText (line, 0, startCommentMark);
03571
03572
03573 int col = m_buffer->plainLine(line)->length();
03574
03575
03576 insertText (line, col, stopCommentMark);
03577
03578 editEnd();
03579 }
03580
03581
03582
03583
03584
03585 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
03586 {
03587 QString shortStartCommentMark = m_highlight->getCommentStart( attrib );
03588 QString longStartCommentMark = shortStartCommentMark + " ";
03589 QString shortStopCommentMark = m_highlight->getCommentEnd( attrib );
03590 QString longStopCommentMark = " " + shortStopCommentMark;
03591
03592 editStart();
03593
03594
03595 bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
03596 || removeStringFromBegining(line, shortStartCommentMark));
03597
03598 bool removedStop = false;
03599 if (removedStart)
03600 {
03601
03602 removedStop = (removeStringFromEnd(line, longStopCommentMark)
03603 || removeStringFromEnd(line, shortStopCommentMark));
03604 }
03605
03606 editEnd();
03607
03608 return (removedStart || removedStop);
03609 }
03610
03611
03612
03613
03614
03615
03616 void KateDocument::addStartStopCommentToSelection( int attrib )
03617 {
03618 QString startComment = m_highlight->getCommentStart( attrib );
03619 QString endComment = m_highlight->getCommentEnd( attrib );
03620
03621 int sl = selectStart.line();
03622 int el = selectEnd.line();
03623 int sc = selectStart.col();
03624 int ec = selectEnd.col();
03625
03626 if ((ec == 0) && ((el-1) >= 0))
03627 {
03628 el--;
03629 ec = m_buffer->plainLine (el)->length();
03630 }
03631
03632 editStart();
03633
03634 insertText (el, ec, endComment);
03635 insertText (sl, sc, startComment);
03636
03637 editEnd ();
03638
03639
03640 ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
03641 setSelection(sl, sc, el, ec);
03642 }
03643
03644
03645
03646
03647
03648 void KateDocument::addStartLineCommentToSelection( int attrib )
03649 {
03650 QString commentLineMark = m_highlight->getCommentSingleLineStart( attrib ) + " ";
03651
03652 int sl = selectStart.line();
03653 int el = selectEnd.line();
03654
03655 if ((selectEnd.col() == 0) && ((el-1) >= 0))
03656 {
03657 el--;
03658 }
03659
03660 editStart();
03661
03662
03663 for (int z = el; z >= sl; z--) {
03664 insertText (z, 0, commentLineMark);
03665 }
03666
03667 editEnd ();
03668
03669
03670 selectEnd.setCol(selectEnd.col() + ((el == selectEnd.line()) ? commentLineMark.length() : 0) );
03671 setSelection(selectStart.line(), 0, selectEnd.line(), selectEnd.col());
03672 }
03673
03674 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
03675 {
03676 for(; line < (int)m_buffer->count(); line++) {
03677 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03678
03679 if (!textLine)
03680 break;
03681
03682 col = textLine->nextNonSpaceChar(col);
03683 if(col != -1)
03684 return true;
03685 col = 0;
03686 }
03687
03688 line = -1;
03689 col = -1;
03690 return false;
03691 }
03692
03693 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
03694 {
03695 while(true)
03696 {
03697 KateTextLine::Ptr textLine = m_buffer->plainLine(line);
03698
03699 if (!textLine)
03700 break;
03701
03702 col = textLine->previousNonSpaceChar(col);
03703 if(col != -1) return true;
03704 if(line == 0) return false;
03705 --line;
03706 col = textLine->length();
03707 }
03708
03709 line = -1;
03710 col = -1;
03711 return false;
03712 }
03713
03714
03715
03716
03717
03718 bool KateDocument::removeStartStopCommentFromSelection( int attrib )
03719 {
03720 QString startComment = m_highlight->getCommentStart( attrib );
03721 QString endComment = m_highlight->getCommentEnd( attrib );
03722
03723 int sl = kMax<int> (0, selectStart.line());
03724 int el = kMin<int> (selectEnd.line(), lastLine());
03725 int sc = selectStart.col();
03726 int ec = selectEnd.col();
03727
03728
03729 if (ec != 0) {
03730 ec--;
03731 } else {
03732 if (el > 0) {
03733 el--;
03734 ec = m_buffer->plainLine(el)->length() - 1;
03735 }
03736 }
03737
03738 int startCommentLen = startComment.length();
03739 int endCommentLen = endComment.length();
03740
03741
03742
03743 bool remove = nextNonSpaceCharPos(sl, sc)
03744 && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
03745 && previousNonSpaceCharPos(el, ec)
03746 && ( (ec - endCommentLen + 1) >= 0 )
03747 && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
03748
03749 if (remove) {
03750 editStart();
03751
03752 removeText (el, ec - endCommentLen + 1, el, ec + 1);
03753 removeText (sl, sc, sl, sc + startCommentLen);
03754
03755 editEnd ();
03756
03757
03758 ec -= endCommentLen + ( (el == sl) ? startCommentLen : 0 );
03759 setSelection(sl, sc, el, ec + 1);
03760 }
03761
03762 return remove;
03763 }
03764
03765
03766
03767
03768
03769 bool KateDocument::removeStartLineCommentFromSelection( int attrib )
03770 {
03771 QString shortCommentMark = m_highlight->getCommentSingleLineStart( attrib );
03772 QString longCommentMark = shortCommentMark + " ";
03773
03774 int sl = selectStart.line();
03775 int el = selectEnd.line();
03776
03777 if ((selectEnd.col() == 0) && ((el-1) >= 0))
03778 {
03779 el--;
03780 }
03781
03782
03783 int removeLength = 0;
03784 if (m_buffer->plainLine(el)->startingWith(longCommentMark))
03785 removeLength = longCommentMark.length();
03786 else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
03787 removeLength = shortCommentMark.length();
03788
03789 bool removed = false;
03790
03791 editStart();
03792
03793
03794 for (int z = el; z >= sl; z--)
03795 {
03796
03797 removed = (removeStringFromBegining(z, longCommentMark)
03798 || removeStringFromBegining(z, shortCommentMark)
03799 || removed);
03800 }
03801
03802 editEnd();
03803
03804 if(removed) {
03805
03806 selectEnd.setCol(selectEnd.col() - ((el == selectEnd.line()) ? removeLength : 0) );
03807 setSelection(selectStart.line(), selectStart.col(), selectEnd.line(), selectEnd.col());
03808 }
03809
03810 return removed;
03811 }
03812
03813
03814
03815
03816
03817 void KateDocument::comment( KateView *, uint line, int change)
03818 {
03819
03820
03821
03822
03823 bool hassel = hasSelection();
03824 int startAttrib, endAttrib;
03825 if ( hassel )
03826 {
03827 KateTextLine::Ptr ln = kateTextLine( selectStart.line() );
03828 int l = selectStart.line(), c = selectStart.col();
03829 startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03830
03831 ln = kateTextLine( selectEnd.line() );
03832 l = selectEnd.line(), c = selectEnd.col();
03833 endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
03834 }
03835 else
03836 {
03837 KateTextLine::Ptr ln = kateTextLine( line );
03838 if ( ln->length() )
03839 {
03840 startAttrib = ln->attribute( ln->firstChar() );
03841 endAttrib = ln->attribute( ln->lastChar() );
03842 }
03843 else
03844 {
03845 int l = line, c = 0;
03846 if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
03847 startAttrib = endAttrib = kateTextLine( l )->attribute( c );
03848 else
03849 startAttrib = endAttrib = 0;
03850 }
03851 }
03852
03853 if ( ! m_highlight->canComment( startAttrib, endAttrib ) )
03854 {
03855 kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
03856 return;
03857 }
03858
03859 bool hasStartLineCommentMark = !(m_highlight->getCommentSingleLineStart( startAttrib ).isEmpty());
03860 bool hasStartStopCommentMark = ( !(m_highlight->getCommentStart( startAttrib ).isEmpty())
03861 && !(m_highlight->getCommentEnd( endAttrib ).isEmpty()) );
03862
03863 bool removed = false;
03864
03865 if (change > 0)
03866 {
03867 if ( !hassel )
03868 {
03869 if ( hasStartLineCommentMark )
03870 addStartLineCommentToSingleLine( line, startAttrib );
03871 else if ( hasStartStopCommentMark )
03872 addStartStopCommentToSingleLine( line, startAttrib );
03873 }
03874 else
03875 {
03876
03877
03878
03879
03880
03881
03882
03883 if ( hasStartStopCommentMark &&
03884 ( !hasStartLineCommentMark || (
03885 ( selectStart.col() > m_buffer->plainLine( selectStart.line() )->firstChar() ) ||
03886 ( selectEnd.col() < ((int)m_buffer->plainLine( selectEnd.line() )->length()) )
03887 ) ) )
03888 addStartStopCommentToSelection( startAttrib );
03889 else if ( hasStartLineCommentMark )
03890 addStartLineCommentToSelection( startAttrib );
03891 }
03892 }
03893 else
03894 {
03895 if ( !hassel )
03896 {
03897 removed = ( hasStartLineCommentMark
03898 && removeStartLineCommentFromSingleLine( line, startAttrib ) )
03899 || ( hasStartStopCommentMark
03900 && removeStartStopCommentFromSingleLine( line, startAttrib ) );
03901 }
03902 else
03903 {
03904
03905 removed = ( hasStartLineCommentMark
03906 && removeStartLineCommentFromSelection( startAttrib ) )
03907 || ( hasStartStopCommentMark
03908 && removeStartStopCommentFromSelection( startAttrib ) );
03909 }
03910 }
03911 }
03912
03913 void KateDocument::transform( KateView *, const KateTextCursor &c,
03914 KateDocument::TextTransform t )
03915 {
03916 editStart();
03917 uint cl( c.line() ), cc( c.col() );
03918
03919 if ( hasSelection() )
03920 {
03921
03922 KateTextCursor s = selectStart;
03923 KateTextCursor e = selectEnd;
03924
03925 int ln = selStartLine();
03926 while ( ln <= selEndLine() )
03927 {
03928 uint start, end;
03929 start = (ln == selStartLine() || blockSelectionMode()) ?
03930 selStartCol() : 0;
03931 end = (ln == selEndLine() || blockSelectionMode()) ?
03932 selEndCol() : lineLength( ln );
03933 QString s = text( ln, start, ln, end );
03934
03935 if ( t == Uppercase )
03936 s = s.upper();
03937 else if ( t == Lowercase )
03938 s = s.lower();
03939 else
03940 {
03941 KateTextLine::Ptr l = m_buffer->plainLine( ln );
03942 uint p ( 0 );
03943 while( p < s.length() )
03944 {
03945
03946
03947
03948
03949 if ( ( ! start && ! p ) ||
03950 ( ( ln == selStartLine() || blockSelectionMode() ) &&
03951 ! p && ! m_highlight->isInWord( l->getChar( start - 1 )) ) ||
03952 ( p && ! m_highlight->isInWord( s.at( p-1 ) ) )
03953 )
03954 s[p] = s.at(p).upper();
03955 p++;
03956 }
03957 }
03958
03959 removeText( ln, start, ln, end );
03960 insertText( ln, start, s );
03961
03962 ln++;
03963 }
03964
03965
03966 setSelection( s, e );
03967
03968 } else {
03969 QString s;
03970 int n ( cc );
03971 switch ( t ) {
03972 case Uppercase:
03973 s = text( cl, cc, cl, cc + 1 ).upper();
03974 break;
03975 case Lowercase:
03976 s = text( cl, cc, cl, cc + 1 ).lower();
03977 break;
03978 case Capitalize:
03979 {
03980 KateTextLine::Ptr l = m_buffer->plainLine( cl );
03981 while ( n > 0 && m_highlight->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
03982 n--;
03983 s = text( cl, n, cl, n + 1 ).upper();
03984 }
03985 break;
03986 default:
03987 break;
03988 }
03989 removeText( cl, n, cl, n+1 );
03990 insertText( cl, n, s );
03991 }
03992
03993 editEnd();
03994
03995 if ( activeView() )
03996 activeView()->setCursorPosition( cl, cc );
03997 }
03998
03999 void KateDocument::joinLines( uint first, uint last )
04000 {
04001
04002 editStart();
04003 int line( first );
04004 while ( first < last )
04005 {
04006
04007
04008
04009
04010
04011 KateTextLine::Ptr l = m_buffer->line( line );
04012 KateTextLine::Ptr tl = m_buffer->line( line + 1 );
04013
04014 if ( !l || !tl )
04015 {
04016 editEnd();
04017 return;
04018 }
04019
04020 int pos = tl->firstChar();
04021 if ( pos >= 0 )
04022 {
04023 if (pos != 0)
04024 editRemoveText( line + 1, 0, pos );
04025 if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
04026 editInsertText( line + 1, 0, " " );
04027 }
04028 else
04029 {
04030
04031 editRemoveText( line + 1, 0, tl->length() );
04032 }
04033
04034 editUnWrapLine( line );
04035 first++;
04036 }
04037 editEnd();
04038 }
04039
04040 QString KateDocument::getWord( const KateTextCursor& cursor ) {
04041 int start, end, len;
04042
04043 KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
04044 len = textLine->length();
04045 start = end = cursor.col();
04046 if (start > len)
04047 return QString("");
04048
04049 while (start > 0 && m_highlight->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
04050 while (end < len && m_highlight->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
04051 len = end - start;
04052 return QString(&textLine->text()[start], len);
04053 }
04054
04055 void KateDocument::tagLines(int start, int end)
04056 {
04057 for (uint z = 0; z < m_views.count(); z++)
04058 m_views.at(z)->tagLines (start, end, true);
04059 }
04060
04061 void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
04062 {
04063
04064 if (blockSelectionMode() && start.col() > end.col()) {
04065 int sc = start.col();
04066 start.setCol(end.col());
04067 end.setCol(sc);
04068 }
04069
04070 for (uint z = 0; z < m_views.count(); z++)
04071 m_views.at(z)->tagLines(start, end, true);
04072 }
04073
04074 void KateDocument::tagSelection(const KateTextCursor &oldSelectStart, const KateTextCursor &oldSelectEnd)
04075 {
04076 if (hasSelection()) {
04077 if (oldSelectStart.line() == -1) {
04078
04079
04080
04081 tagLines(selectStart, selectEnd);
04082
04083 } else if (blockSelectionMode() && (oldSelectStart.col() != selectStart.col() || oldSelectEnd.col() != selectEnd.col())) {
04084
04085 tagLines(selectStart, selectEnd);
04086 tagLines(oldSelectStart, oldSelectEnd);
04087
04088 } else {
04089 if (oldSelectStart != selectStart) {
04090 if (oldSelectStart < selectStart)
04091 tagLines(oldSelectStart, selectStart);
04092 else
04093 tagLines(selectStart, oldSelectStart);
04094 }
04095
04096 if (oldSelectEnd != selectEnd) {
04097 if (oldSelectEnd < selectEnd)
04098 tagLines(oldSelectEnd, selectEnd);
04099 else
04100 tagLines(selectEnd, oldSelectEnd);
04101 }
04102 }
04103
04104 } else {
04105
04106 tagLines(oldSelectStart, oldSelectEnd);
04107 }
04108 }
04109
04110 void KateDocument::repaintViews(bool paintOnlyDirty)
04111 {
04112 for (uint z = 0; z < m_views.count(); z++)
04113 m_views.at(z)->repaintText(paintOnlyDirty);
04114 }
04115
04116 void KateDocument::tagAll()
04117 {
04118 for (uint z = 0; z < m_views.count(); z++)
04119 {
04120 m_views.at(z)->tagAll();
04121 m_views.at(z)->updateView (true);
04122 }
04123 }
04124
04125 void KateDocument::updateViews()
04126 {
04127 if (noViewUpdates)
04128 return;
04129
04130 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
04131 {
04132 view->updateView(true);
04133 }
04134 }
04135
04136 uint KateDocument::configFlags ()
04137 {
04138 return config()->configFlags();
04139 }
04140
04141 void KateDocument::setConfigFlags (uint flags)
04142 {
04143 config()->setConfigFlags(flags);
04144 }
04145
04146 bool KateDocument::lineColSelected (int line, int col)
04147 {
04148 if ( (!blockSelect) && (col < 0) )
04149 col = 0;
04150
04151 KateTextCursor cursor(line, col);
04152
04153 if (blockSelect)
04154 return cursor.line() >= selectStart.line() && cursor.line() <= selectEnd.line() && cursor.col() >= selectStart.col() && cursor.col() < selectEnd.col();
04155 else
04156 return (cursor >= selectStart) && (cursor < selectEnd);
04157 }
04158
04159 bool KateDocument::lineSelected (int line)
04160 {
04161 return (!blockSelect)
04162 && (selectStart <= KateTextCursor(line, 0))
04163 && (line < selectEnd.line());
04164 }
04165
04166 bool KateDocument::lineEndSelected (int line, int endCol)
04167 {
04168 return (!blockSelect)
04169 && (line > selectStart.line() || (line == selectStart.line() && (selectStart.col() < endCol || endCol == -1)))
04170 && (line < selectEnd.line() || (line == selectEnd.line() && (endCol <= selectEnd.col() && endCol != -1)));
04171 }
04172
04173 bool KateDocument::lineHasSelected (int line)
04174 {
04175 return (selectStart < selectEnd)
04176 && (line >= selectStart.line())
04177 && (line <= selectEnd.line());
04178 }
04179
04180 bool KateDocument::lineIsSelection (int line)
04181 {
04182 return (line == selectStart.line() && line == selectEnd.line());
04183 }
04184
04185 inline bool isStartBracket( const QChar& c ) { return c == '{' || c == '[' || c == '('; }
04186 inline bool isEndBracket ( const QChar& c ) { return c == '}' || c == ']' || c == ')'; }
04187 inline bool isBracket ( const QChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
04188
04189
04190
04191
04192
04193
04194
04195
04196
04197
04198
04199 void KateDocument::newBracketMark( const KateTextCursor& cursor, KateTextRange& bm )
04200 {
04201 bm.setValid(false);
04202
04203 bm.start() = cursor;
04204
04205 if( !findMatchingBracket( bm.start(), bm.end() ) )
04206 return;
04207
04208 bm.setValid(true);
04209 }
04210
04211 bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end )
04212 {
04213 KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
04214 if( !textLine )
04215 return false;
04216
04217 QChar right = textLine->getChar( start.col() );
04218 QChar left = textLine->getChar( start.col() - 1 );
04219 QChar bracket;
04220
04221 if ( config()->configFlags() & cfOvr ) {
04222 if( isBracket( right ) ) {
04223 bracket = right;
04224 } else {
04225 return false;
04226 }
04227 } else if ( isStartBracket( right ) ) {
04228 bracket = right;
04229 } else if ( isEndBracket( left ) ) {
04230 start.setCol(start.col() - 1);
04231 bracket = left;
04232 } else if ( isBracket( left ) ) {
04233 start.setCol(start.col() - 1);
04234 bracket = left;
04235 } else if ( isBracket( right ) ) {
04236 bracket = right;
04237 } else {
04238 return false;
04239 }
04240
04241 QChar opposite;
04242
04243 switch( bracket ) {
04244 case '{': opposite = '}'; break;
04245 case '}': opposite = '{'; break;
04246 case '[': opposite = ']'; break;
04247 case ']': opposite = '['; break;
04248 case '(': opposite = ')'; break;
04249 case ')': opposite = '('; break;
04250 default: return false;
04251 }
04252
04253 bool forward = isStartBracket( bracket );
04254 int startAttr = textLine->attribute( start.col() );
04255 uint count = 0;
04256 end = start;
04257
04258 while( true ) {
04259
04260 if( forward ) {
04261 end.setCol(end.col() + 1);
04262 if( end.col() >= lineLength( end.line() ) ) {
04263 if( end.line() >= (int)lastLine() )
04264 return false;
04265 end.setPos(end.line() + 1, 0);
04266 textLine = m_buffer->plainLine( end.line() );
04267 }
04268 } else {
04269 end.setCol(end.col() - 1);
04270 if( end.col() < 0 ) {
04271 if( end.line() <= 0 )
04272 return false;
04273 end.setLine(end.line() - 1);
04274 end.setCol(lineLength( end.line() ) - 1);
04275 textLine = m_buffer->plainLine( end.line() );
04276 }
04277 }
04278
04279
04280 if( textLine->attribute( end.col() ) != startAttr )
04281 continue;
04282
04283
04284 QChar c = textLine->getChar( end.col() );
04285 if( c == bracket ) {
04286 count++;
04287 } else if( c == opposite ) {
04288 if( count == 0 )
04289 return true;
04290 count--;
04291 }
04292
04293 }
04294 }
04295
04296 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
04297 {
04298 KParts::ReadWritePart::guiActivateEvent( ev );
04299 if ( ev->activated() )
04300 emit selectionChanged();
04301 }
04302
04303 void KateDocument::setDocName (QString name )
04304 {
04305 if ( !name.isEmpty() )
04306 {
04307
04308 m_docName = name;
04309 emit nameChanged((Kate::Document *) this);
04310 return;
04311 }
04312
04313
04314 if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
04315
04316 int count = -1;
04317
04318 for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
04319 {
04320 if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
04321 if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
04322 count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
04323 }
04324
04325 m_docNameNumber = count + 1;
04326
04327 m_docName = url().filename();
04328
04329 if (m_docName.isEmpty())
04330 m_docName = i18n ("Untitled");
04331
04332 if (m_docNameNumber > 0)
04333 m_docName = QString(m_docName + " (%1)").arg(m_docNameNumber+1);
04334
04335 emit nameChanged ((Kate::Document *) this);
04336 }
04337
04338 void KateDocument::slotModifiedOnDisk( Kate::View *v )
04339 {
04340 if ( !s_fileChangedDialogsActivated || m_isasking )
04341 return;
04342
04343 if (m_modOnHd && !url().isEmpty())
04344 {
04345 m_isasking = 1;
04346
04347 if ( m_modOnHdReason == 3 )
04348 {
04349 switch ( KMessageBox::warningYesNoCancel( widget(),
04350 reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04351 i18n("File Was Deleted on Disk"),
04352 i18n("&Save As..."), i18n("&Ignore Changes")) )
04353 {
04354 case KMessageBox::Yes:
04355 m_modOnHd = false;
04356 emit modifiedOnDisc( this, false, 0 );
04357 saveAs(url());
04358 m_isasking = 0;
04359 break;
04360
04361 case KMessageBox::No:
04362 m_modOnHd = false;
04363 emit modifiedOnDisc( this, false, 0 );
04364 m_isasking = 0;
04365 break;
04366
04367 default:
04368 m_isasking = -1;
04369 }
04370 } else {
04371 switch ( KMessageBox::warningYesNoCancel( widget(),
04372 reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04373 i18n("File Was Modified on Disk"),
04374 i18n("&Reload File"), i18n("&Ignore Changes")) )
04375 {
04376 case KMessageBox::Yes:
04377 m_modOnHd = false;
04378 emit modifiedOnDisc( this, false, 0 );
04379 reloadFile();
04380 m_isasking = 0;
04381 break;
04382
04383 case KMessageBox::No:
04384 m_modOnHd = false;
04385 emit modifiedOnDisc( this, false, 0 );
04386 m_isasking = 0;
04387 break;
04388
04389 default:
04390 m_isasking = -1;
04391 }
04392 }
04393 }
04394 }
04395
04396 void KateDocument::setModifiedOnDisk( int reason )
04397 {
04398 m_modOnHdReason = reason;
04399 emit modifiedOnDisc( this, (reason > 0), reason );
04400 }
04401
04402 class KateDocumentTmpMark
04403 {
04404 public:
04405 QString line;
04406 KTextEditor::Mark mark;
04407 };
04408
04409 void KateDocument::reloadFile()
04410 {
04411 if ( !url().isEmpty() )
04412 {
04413 if (m_modOnHd && s_fileChangedDialogsActivated)
04414 {
04415 int i = KMessageBox::warningYesNoCancel
04416 (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
04417 i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
04418
04419 if ( i != KMessageBox::Yes)
04420 {
04421 if (i == KMessageBox::No)
04422 {
04423 m_modOnHd = false;
04424 m_modOnHdReason = 0;
04425 emit modifiedOnDisc (this, m_modOnHd, 0);
04426 }
04427
04428 return;
04429 }
04430 }
04431
04432 QValueList<KateDocumentTmpMark> tmp;
04433
04434 for( QIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
04435 {
04436 KateDocumentTmpMark m;
04437
04438 m.line = textLine (it.current()->line);
04439 m.mark = *it.current();
04440
04441 tmp.append (m);
04442 }
04443
04444 uint mode = hlMode ();
04445 bool byUser = hlSetByUser;
04446
04447 m_storedVariables.clear();
04448
04449 m_reloading = true;
04450 KateDocument::openURL( url() );
04451 m_reloading = false;
04452
04453 for (uint z=0; z < tmp.size(); z++)
04454 {
04455 if (z < numLines())
04456 {
04457 if (textLine(tmp[z].mark.line) == tmp[z].line)
04458 setMark (tmp[z].mark.line, tmp[z].mark.type);
04459 }
04460 }
04461
04462 if (byUser)
04463 setHlMode (mode);
04464 }
04465 }
04466
04467 void KateDocument::flush ()
04468 {
04469 closeURL ();
04470 }
04471
04472 void KateDocument::setWordWrap (bool on)
04473 {
04474 config()->setWordWrap (on);
04475 }
04476
04477 bool KateDocument::wordWrap ()
04478 {
04479 return config()->wordWrap ();
04480 }
04481
04482 void KateDocument::setWordWrapAt (uint col)
04483 {
04484 config()->setWordWrapAt (col);
04485 }
04486
04487 unsigned int KateDocument::wordWrapAt ()
04488 {
04489 return config()->wordWrapAt ();
04490 }
04491
04492 void KateDocument::applyWordWrap ()
04493 {
04494 if (hasSelection())
04495 wrapText (selectStart.line(), selectEnd.line());
04496 else
04497 wrapText (0, lastLine());
04498 }
04499
04500 void KateDocument::setPageUpDownMovesCursor (bool on)
04501 {
04502 config()->setPageUpDownMovesCursor (on);
04503 }
04504
04505 bool KateDocument::pageUpDownMovesCursor ()
04506 {
04507 return config()->pageUpDownMovesCursor ();
04508 }
04509
04510 void KateDocument::exportAs(const QString& filter)
04511 {
04512 if (filter=="kate_html_export")
04513 {
04514 KURL url = KFileDialog::getSaveURL(QString::null,"text/html",0,i18n("Export File As"));
04515 if ( url.isEmpty() )
04516 return;
04517
04518 QString filename;
04519 KTempFile tmp;
04520
04521 if ( url.isLocalFile() )
04522 filename = url.path();
04523 else
04524 filename = tmp.name();
04525
04526 KSaveFile *savefile=new KSaveFile(filename);
04527 if (!savefile->status())
04528 {
04529 if (exportDocumentToHTML(savefile->textStream(),filename))
04530 savefile->close();
04531 else savefile->abort();
04532
04533 }
04534
04535
04536 delete savefile;
04537
04538 if ( url.isLocalFile() )
04539 return;
04540
04541 KIO::NetAccess::upload( filename, url, 0 );
04542 }
04543 }
04544
04545
04546 bool KateDocument::exportDocumentToHTML(QTextStream *outputStream,const QString &name)
04547 {
04548 outputStream->setEncoding(QTextStream::UnicodeUTF8);
04549
04550 (*outputStream) << "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" << endl;
04551 (*outputStream) << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"DTD/xhtml1-strict.dtd\">" << endl;
04552 (*outputStream) << "<html xmlns=\"http://www.w3.org/1999/xhtml\">" << endl;
04553 (*outputStream) << "<head>" << endl;
04554 (*outputStream) << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\" />" << endl;
04555 (*outputStream) << "<meta name=\"Generator\" content=\"Kate, the KDE Advanced Text Editor\" />" << endl;
04556
04557 (*outputStream) << "<title>" << name.right(name.length() - name.findRev('/') -1) << "</title>" << endl;
04558 (*outputStream) << "</head>" << endl;
04559
04560 (*outputStream) << "<body><pre>" << endl;
04561
04562
04563
04564 bool previousCharacterWasBold = false;
04565 bool previousCharacterWasItalic = false;
04566
04567
04568
04569 bool needToReinitializeTags = false;
04570 QColor previousCharacterColor(0,0,0);
04571 (*outputStream) << "<span style='color: #000000'>";
04572
04573 for (uint curLine=0;curLine<numLines();curLine++)
04574 {
04575 KateTextLine::Ptr textLine = m_buffer->plainLine(curLine);
04576
04577
04578 for (uint curPos=0;curPos<textLine->length();curPos++)
04579 {
04580
04581 QMemArray<KateAttribute> *attributes = m_highlight->attributes (0);
04582 KateAttribute* charAttributes = 0;
04583
04584 if (textLine->attribute(curPos) < attributes->size())
04585 charAttributes = &attributes->at(textLine->attribute(curPos));
04586 else
04587 charAttributes = &attributes->at(0);
04588
04589
04590
04591 if ( (charAttributes->textColor() != previousCharacterColor))
04592 {
04593
04594 if (previousCharacterWasBold)
04595 (*outputStream) << "</b>";
04596 if (previousCharacterWasItalic)
04597 (*outputStream) << "</i>";
04598
04599
04600 (*outputStream) << "</span>";
04601
04602 int red, green, blue;
04603
04604 charAttributes->textColor().rgb(&red, &green, &blue);
04605 (*outputStream) << "<span style='color: #"
04606 << ( (red < 0x10)?"0":"")
04607 << QString::number(red, 16)
04608 << ( (green < 0x10)?"0":"")
04609 << QString::number(green, 16)
04610 << ( (blue < 0x10)?"0":"")
04611 << QString::number(blue, 16)
04612 << "'>";
04613
04614 needToReinitializeTags = true;
04615 }
04616
04617 if ( (needToReinitializeTags && charAttributes->bold()) ||
04618 (!previousCharacterWasBold && charAttributes->bold()) )
04619
04620 (*outputStream) << "<b>";
04621 if ( !needToReinitializeTags && (previousCharacterWasBold && !charAttributes->bold()) )
04622
04623 (*outputStream) << "</b>";
04624
04625
04626 if ( (needToReinitializeTags && charAttributes->italic()) ||
04627 (!previousCharacterWasItalic && charAttributes->italic()) )
04628
04629 (*outputStream) << "<i>";
04630 if ( !needToReinitializeTags && (previousCharacterWasItalic && !charAttributes->italic()) )
04631
04632 (*outputStream) << "</i>";
04633
04634
04635 (*outputStream) << HTMLEncode(textLine->getChar(curPos));
04636
04637
04638 previousCharacterWasItalic = charAttributes->italic();
04639 previousCharacterWasBold = charAttributes->bold();
04640 previousCharacterColor = charAttributes->textColor();
04641 needToReinitializeTags = false;
04642 }
04643
04644 (*outputStream) << endl;
04645 }
04646
04647
04648 if (previousCharacterWasBold)
04649 (*outputStream) << "</b>";
04650 if (previousCharacterWasItalic)
04651 (*outputStream) << "</i>";
04652
04653
04654 (*outputStream) << "</span>";
04655 (*outputStream) << "</pre></body>";
04656 (*outputStream) << "</html>";
04657
04658 return true;
04659 }
04660
04661 QString KateDocument::HTMLEncode(QChar theChar)
04662 {
04663 switch (theChar.latin1())
04664 {
04665 case '>':
04666 return QString(">");
04667 case '<':
04668 return QString("<");
04669 case '&':
04670 return QString("&");
04671 };
04672 return theChar;
04673 }
04674
04675 Kate::ConfigPage *KateDocument::colorConfigPage (QWidget *p)
04676 {
04677 return (Kate::ConfigPage*) new KateSchemaConfigPage (p, this);
04678 }
04679
04680 Kate::ConfigPage *KateDocument::viewDefaultsConfigPage (QWidget *p)
04681 {
04682 return (Kate::ConfigPage*) new KateViewDefaultsConfig(p);
04683 }
04684
04685 Kate::ConfigPage *KateDocument::fontConfigPage (QWidget *p)
04686 {
04687 return (Kate::ConfigPage*) new KateSchemaConfigPage ( p );
04688 }
04689
04690 Kate::ConfigPage *KateDocument::indentConfigPage (QWidget *p)
04691 {
04692 return (Kate::ConfigPage*) new KateIndentConfigTab(p);
04693 }
04694
04695 Kate::ConfigPage *KateDocument::selectConfigPage (QWidget *p)
04696 {
04697 return (Kate::ConfigPage*) new KateSelectConfigTab(p);
04698 }
04699
04700 Kate::ConfigPage *KateDocument::editConfigPage (QWidget *p)
04701 {
04702 return (Kate::ConfigPage*) new KateEditConfigTab(p);
04703 }
04704
04705 Kate::ConfigPage *KateDocument::keysConfigPage (QWidget *p)
04706 {
04707 return (Kate::ConfigPage*) new KateEditKeyConfiguration(p, this);
04708 }
04709
04710 Kate::ConfigPage *KateDocument::hlConfigPage (QWidget *p)
04711 {
04712 return (Kate::ConfigPage*) new KateHlConfigPage (p);
04713 }
04714
04715 Kate::ConfigPage *KateDocument::saveConfigPage(QWidget *p)
04716 {
04717 return (Kate::ConfigPage*) new KateSaveConfigTab(p);
04718 }
04719
04720 Kate::ActionMenu *KateDocument::hlActionMenu (const QString& text, QObject* parent, const char* name)
04721 {
04722 KateViewHighlightAction *menu = new KateViewHighlightAction (text, parent, name);
04723 menu->setWhatsThis(i18n("Here you can choose how the current document should be highlighted."));
04724 menu->updateMenu (this);
04725
04726 return (Kate::ActionMenu *)menu;
04727 }
04728
04729 Kate::ActionMenu *KateDocument::exportActionMenu (const QString& text, QObject* parent, const char* name)
04730 {
04731 KateExportAction *menu = new KateExportAction (text, parent, name);
04732 menu->updateMenu (this);
04733 menu->setWhatsThis(i18n("This command allows you to export the current document"
04734 " with all highlighting information into a markup document, e.g. HTML."));
04735 return (Kate::ActionMenu *)menu;
04736 }
04737
04738 void KateDocument::dumpRegionTree()
04739 {
04740 m_buffer->foldingTree()->debugDump();
04741 }
04742
04743 unsigned int KateDocument::getRealLine(unsigned int virtualLine)
04744 {
04745 return m_buffer->lineNumber (virtualLine);
04746 }
04747
04748 unsigned int KateDocument::getVirtualLine(unsigned int realLine)
04749 {
04750 return m_buffer->lineVisibleNumber (realLine);
04751 }
04752
04753 unsigned int KateDocument::visibleLines ()
04754 {
04755 return m_buffer->countVisible ();
04756 }
04757
04758 KateTextLine::Ptr KateDocument::kateTextLine(uint i)
04759 {
04760 return m_buffer->line (i);
04761 }
04762
04763 KateTextLine::Ptr KateDocument::plainKateTextLine(uint i)
04764 {
04765 return m_buffer->plainLine (i);
04766 }
04767
04768
04769
04770
04771 KTextEditor::Cursor *KateDocument::createCursor ( )
04772 {
04773 return new KateSuperCursor (this, false, 0, 0, this);
04774 }
04775
04776 void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
04777 {
04778 if (view)
04779 view->tagLines(range->start(), range->end());
04780 else
04781 tagLines(range->start(), range->end());
04782 }
04783
04784
04785
04786
04787 void KateDocument::spellcheck()
04788 {
04789 if( !isReadWrite() || text().isEmpty())
04790 return;
04791
04792 QString mt = mimeType();
04793
04794 KSpell::SpellerType type = KSpell::Text;
04795 if ( mt == "text/x-tex" || mt == "text/x-latex" )
04796 type = KSpell::TeX;
04797 else if ( mt == "text/html" || mt == "text/xml" )
04798 type = KSpell::HTML;
04799
04800 m_kspell = new KSpell( 0, i18n("Spellcheck"),
04801 this, SLOT(ready(KSpell *)), 0, true, false, type );
04802
04803 connect( m_kspell, SIGNAL(death()),
04804 this, SLOT(spellCleanDone()) );
04805
04806 connect( m_kspell, SIGNAL(misspelling(const QString&, const QStringList&, unsigned int)),
04807 this, SLOT(misspelling(const QString&, const QStringList&, unsigned int)) );
04808 connect( m_kspell, SIGNAL(corrected(const QString&, const QString&, unsigned int)),
04809 this, SLOT(corrected(const QString&, const QString&, unsigned int)) );
04810 connect( m_kspell, SIGNAL(done(const QString&)),
04811 this, SLOT(spellResult(const QString&)) );
04812 }
04813
04814 void KateDocument::ready(KSpell *)
04815 {
04816 m_kspell->setProgressResolution( 1 );
04817
04818 m_kspell->check( text() );
04819
04820 kdDebug () << "SPELLING READY STATUS: " << m_kspell->status () << endl;
04821 }
04822
04823 void KateDocument::locatePosition( uint pos, uint& line, uint& col )
04824 {
04825 uint cnt = 0;
04826
04827 line = col = 0;
04828
04829
04830
04831
04832 for( ; line < numLines() && cnt <= pos; line++ )
04833 cnt += lineLength(line) + 1;
04834
04835 line--;
04836 col = pos - (cnt - lineLength(line)) + 1;
04837 }
04838
04839 void KateDocument::misspelling( const QString& origword, const QStringList&, unsigned int pos )
04840 {
04841 uint line, col;
04842
04843 locatePosition( pos, line, col );
04844
04845 if (activeView())
04846 activeView()->setCursorPositionInternal (line, col, 1);
04847
04848 setSelection( line, col, line, col + origword.length() );
04849 }
04850
04851 void KateDocument::corrected( const QString& originalword, const QString& newword, unsigned int pos )
04852 {
04853 uint line, col;
04854
04855 locatePosition( pos, line, col );
04856
04857 removeText( line, col, line, col + originalword.length() );
04858 insertText( line, col, newword );
04859 }
04860
04861 void KateDocument::spellResult( const QString& )
04862 {
04863 clearSelection();
04864 m_kspell->cleanUp();
04865 }
04866
04867 void KateDocument::spellCleanDone()
04868 {
04869 KSpell::spellStatus status = m_kspell->status();
04870
04871 if( status == KSpell::Error ) {
04872 KMessageBox::sorry( 0,
04873 i18n("ISpell could not be started. "
04874 "Please make sure you have ISpell "
04875 "properly configured and in your PATH."));
04876 } else if( status == KSpell::Crashed ) {
04877 KMessageBox::sorry( 0,
04878 i18n("ISpell seems to have crashed."));
04879 }
04880
04881 delete m_kspell;
04882 m_kspell = 0;
04883
04884 kdDebug () << "SPELLING END" << endl;
04885 }
04886
04887
04888 void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
04889 {
04890 m_buffer->lineInfo(info,line);
04891 }
04892
04893 KateCodeFoldingTree *KateDocument::foldingTree ()
04894 {
04895 return m_buffer->foldingTree();
04896 }
04897
04898 void KateDocument::setEncoding (const QString &e)
04899 {
04900 m_config->setEncoding(e);
04901 }
04902
04903 QString KateDocument::encoding() const
04904 {
04905 return m_config->encoding();
04906 }
04907
04908 void KateDocument::updateConfig ()
04909 {
04910 emit undoChanged ();
04911 tagAll();
04912
04913 for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
04914 {
04915 view->updateDocumentConfig ();
04916 }
04917
04918
04919 if (m_indenter->modeNumber() != m_config->indentationMode())
04920 {
04921 delete m_indenter;
04922 m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
04923 }
04924
04925 m_indenter->updateConfig();
04926
04927 m_buffer->setTabWidth (config()->tabWidth());
04928
04929
04930 for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
04931 {
04932 if (config()->plugin (i))
04933 loadPlugin (i);
04934 else
04935 unloadPlugin (i);
04936 }
04937 }
04938
04939
04940
04941
04942
04943
04944
04945
04946 QRegExp KateDocument::kvLine = QRegExp("kate:(.*)");
04947 QRegExp KateDocument::kvVar = QRegExp("([\\w\\-]+)\\s+([^;]+)");
04948
04949 void KateDocument::readVariables(bool onlyViewAndRenderer)
04950 {
04951 if (!onlyViewAndRenderer)
04952 m_config->configStart();
04953
04954
04955 KateView *v;
04956 for (v = m_views.first(); v != 0L; v= m_views.next() )
04957 {
04958 v->config()->configStart();
04959 v->renderer()->config()->configStart();
04960 }
04961
04962 for (uint i=0; i < QMIN( 9, numLines() ); ++i )
04963 {
04964 readVariableLine( textLine( i ), onlyViewAndRenderer );
04965 }
04966 if ( numLines() > 10 )
04967 {
04968 for ( uint i = QMAX(10, numLines() - 10); i < numLines(); ++i )
04969 {
04970 readVariableLine( textLine( i ), onlyViewAndRenderer );
04971 }
04972 }
04973
04974 if (!onlyViewAndRenderer)
04975 m_config->configEnd();
04976
04977 for (v = m_views.first(); v != 0L; v= m_views.next() )
04978 {
04979 v->config()->configEnd();
04980 v->renderer()->config()->configEnd();
04981 }
04982 }
04983
04984 void KateDocument::readVariableLine( QString t, bool onlyViewAndRenderer )
04985 {
04986 if ( kvLine.search( t ) > -1 )
04987 {
04988 QStringList vvl;
04989 vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
04990 << "line-numbers" << "icon-border" << "folding-markers"
04991 << "bookmark-sorting" << "auto-center-lines"
04992 << "icon-bar-color"
04993
04994 << "background-color" << "selection-color"
04995 << "current-line-color" << "bracket-highlight-color"
04996 << "word-wrap-marker-color"
04997 << "font" << "font-size" << "scheme";
04998 int p( 0 );
04999 QString s = kvLine.cap(1);
05000 QString var, val;
05001 while ( (p = kvVar.search( s, p )) > -1 )
05002 {
05003 p += kvVar.matchedLength();
05004 var = kvVar.cap( 1 );
05005 val = kvVar.cap( 2 ).stripWhiteSpace();
05006 bool state;
05007 int n;
05008
05009
05010 if (onlyViewAndRenderer)
05011 {
05012 if ( vvl.contains( var ) )
05013 setViewVariable( var, val );
05014 }
05015 else
05016 {
05017
05018 if ( var == "word-wrap" && checkBoolValue( val, &state ) )
05019 setWordWrap( state );
05020 else if ( var == "block-selection" && checkBoolValue( val, &state ) )
05021 setBlockSelectionMode( state );
05022
05023
05024 else if ( var == "auto-indent" && checkBoolValue( val, &state ) )
05025 m_config->setConfigFlags( KateDocumentConfig::cfAutoIndent, state );
05026 else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
05027 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
05028 else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
05029 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
05030 else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
05031 m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
05032 else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
05033 m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
05034 else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
05035 m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
05036 else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
05037 m_config->setConfigFlags( KateDocumentConfig::cfPersistent, state );
05038 else if ( var == "keep-selection" && checkBoolValue( val, &state ) )
05039 m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
05040 else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
05041 m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
05042 else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
05043 m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
05044 else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
05045 m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
05046 else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
05047 m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
05048 else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
05049 m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
05050 else if ( var == "space-indent" && checkBoolValue( val, &state ) )
05051 m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
05052 else if ( var == "smart-home" && checkBoolValue( val, &state ) )
05053 m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
05054 else if ( var == "replace-tabs-save" && checkBoolValue( val, &state ) )
05055 m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabs, state );
05056 else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
05057 m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
05058 else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
05059 m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
05060
05061
05062 else if ( var == "tab-width" && checkIntValue( val, &n ) )
05063 m_config->setTabWidth( n );
05064 else if ( var == "indent-width" && checkIntValue( val, &n ) )
05065 m_config->setIndentationWidth( n );
05066 else if ( var == "indent-mode" )
05067 {
05068 if ( checkIntValue( val, &n ) )
05069 m_config->setIndentationMode( n );
05070 else
05071 m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
05072 }
05073 else if ( var == "word-wrap-column" && n > 0 && checkIntValue( val, &n ) )
05074 m_config->setWordWrapAt( n );
05075 else if ( var == "undo-steps" && n >= 0 && checkIntValue( val, &n ) )
05076 setUndoSteps( n );
05077
05078
05079 else if ( var == "eol" || var == "end-of-line" )
05080 {
05081 QStringList l;
05082 l << "unix" << "dos" << "mac";
05083 if ( (n = l.findIndex( val.lower() )) != -1 )
05084 m_config->setEol( n );
05085 }
05086 else if ( var == "encoding" )
05087 m_config->setEncoding( val );
05088 else if ( var == "syntax" || var == "hl" )
05089 {
05090 for ( uint i=0; i < hlModeCount(); i++ )
05091 {
05092 if ( hlModeName( i ) == val )
05093 {
05094 setHlMode( i );
05095 break;
05096 }
05097 }
05098 }
05099
05100
05101 else if ( vvl.contains( var ) )
05102 setViewVariable( var, val );
05103 else
05104 {
05105 m_storedVariables.insert( var, val );
05106 emit variableChanged( var, val );
05107 }
05108 }
05109 }
05110 }
05111 }
05112
05113 void KateDocument::setViewVariable( QString var, QString val )
05114 {
05115 KateView *v;
05116 bool state;
05117 int n;
05118 QColor c;
05119 for (v = m_views.first(); v != 0L; v= m_views.next() )
05120 {
05121 if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
05122 v->config()->setDynWordWrap( state );
05123
05124 else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
05125 v->config()->setLineNumbers( state );
05126 else if (var == "icon-border" && checkBoolValue( val, &state ) )
05127 v->config()->setIconBar( state );
05128 else if (var == "folding-markers" && checkBoolValue( val, &state ) )
05129 v->config()->setFoldingBar( state );
05130 else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
05131 v->config()->setAutoCenterLines( n );
05132 else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
05133 v->renderer()->config()->setIconBarColor( c );
05134
05135 else if ( var == "background-color" && checkColorValue( val, c ) )
05136 v->renderer()->config()->setBackgroundColor( c );
05137 else if ( var == "selection-color" && checkColorValue( val, c ) )
05138 v->renderer()->config()->setSelectionColor( c );
05139 else if ( var == "current-line-color" && checkColorValue( val, c ) )
05140 v->renderer()->config()->setHighlightedLineColor( c );
05141 else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
05142 v->renderer()->config()->setHighlightedBracketColor( c );
05143 else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
05144 v->renderer()->config()->setWordWrapMarkerColor( c );
05145 else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
05146 {
05147 QFont _f( *v->renderer()->config()->font( ) );
05148
05149 if ( var == "font" )
05150 {
05151 _f.setFamily( val );
05152 _f.setFixedPitch( QFont( val ).fixedPitch() );
05153 }
05154 else
05155 _f.setPointSize( n );
05156
05157 v->renderer()->config()->setFont( _f );
05158 }
05159 else if ( var == "scheme" )
05160 {
05161 v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
05162 }
05163 }
05164 }
05165
05166 bool KateDocument::checkBoolValue( QString val, bool *result )
05167 {
05168 val = val.stripWhiteSpace().lower();
05169 QStringList l;
05170 l << "1" << "on" << "true";
05171 if ( l.contains( val ) )
05172 {
05173 *result = true;
05174 return true;
05175 }
05176 l.clear();
05177 l << "0" << "off" << "false";
05178 if ( l.contains( val ) )
05179 {
05180 *result = false;
05181 return true;
05182 }
05183 return false;
05184 }
05185
05186 bool KateDocument::checkIntValue( QString val, int *result )
05187 {
05188 bool ret( false );
05189 *result = val.toInt( &ret );
05190 return ret;
05191 }
05192
05193 bool KateDocument::checkColorValue( QString val, QColor &c )
05194 {
05195 c.setNamedColor( val );
05196 return c.isValid();
05197 }
05198
05199
05200 QString KateDocument::variable( const QString &name ) const
05201 {
05202 if ( m_storedVariables.contains( name ) )
05203 return m_storedVariables[ name ];
05204
05205 return "";
05206 }
05207
05208
05209
05210 void KateDocument::slotModOnHdDirty (const QString &path)
05211 {
05212 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
05213 {
05214
05215 if ( ! m_digest.isEmpty() )
05216 {
05217 QCString tmp;
05218 if ( createDigest( tmp ) && tmp == m_digest )
05219 return;
05220 }
05221
05222 m_modOnHd = true;
05223 m_modOnHdReason = 1;
05224
05225
05226 if (m_isasking == -1)
05227 m_isasking = false;
05228
05229 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05230 }
05231 }
05232
05233 void KateDocument::slotModOnHdCreated (const QString &path)
05234 {
05235 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
05236 {
05237 m_modOnHd = true;
05238 m_modOnHdReason = 2;
05239
05240
05241 if (m_isasking == -1)
05242 m_isasking = false;
05243
05244 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05245 }
05246 }
05247
05248 void KateDocument::slotModOnHdDeleted (const QString &path)
05249 {
05250 if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
05251 {
05252 m_modOnHd = true;
05253 m_modOnHdReason = 3;
05254
05255
05256 if (m_isasking == -1)
05257 m_isasking = false;
05258
05259 emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
05260 }
05261 }
05262
05263 bool KateDocument::createDigest( QCString &result )
05264 {
05265 bool ret = false;
05266 result = "";
05267 if ( url().isLocalFile() )
05268 {
05269 QFile f ( url().path() );
05270 if ( f.open( IO_ReadOnly) )
05271 {
05272 KMD5 md5;
05273 ret = md5.update( f );
05274 md5.hexDigest( result );
05275 f.close();
05276 }
05277 }
05278 return ret;
05279 }
05280
05281 QString KateDocument::reasonedMOHString() const
05282 {
05283 QString reason;
05284 if ( m_modOnHdReason == 1 )
05285 reason = i18n("modified");
05286 else if ( m_modOnHdReason == 2 )
05287 reason = i18n("created");
05288 else if ( m_modOnHdReason == 3 )
05289 reason = i18n("deleted");
05290
05291 return i18n("The file '%1' was changed (%2) on disk by another program!").arg( url().prettyURL() ).arg( reason );
05292 }
05293
05294
05295 void KateDocument::removeTrailingSpace( uint line )
05296 {
05297
05298 if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
05299 {
05300 KateTextLine::Ptr ln = kateTextLine( line );
05301
05302 if ( ! ln ) return;
05303
05304 if ( line == activeView()->cursorLine()
05305 && activeView()->cursorColumnReal() >= (uint)QMAX(0,ln->lastChar()) )
05306 return;
05307
05308 if ( ln->length() )
05309 {
05310 uint p = ln->lastChar() + 1;
05311 uint l = ln->length() - p;
05312 if ( l )
05313 editRemoveText( line, p, l);
05314 }
05315 }
05316 }
05317
05318 bool KateDocument::wrapCursor ()
05319 {
05320 return !blockSelect && (configFlags() & KateDocument::cfWrapCursor);
05321 }
05322
05323 void KateDocument::updateFileType (int newType, bool user)
05324 {
05325 if (user || !m_fileTypeSetByUser)
05326 {
05327 const KateFileType *t = 0;
05328 if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
05329 {
05330 m_fileType = newType;
05331
05332 if (t)
05333 {
05334 m_config->configStart();
05335
05336 KateView *v;
05337 for (v = m_views.first(); v != 0L; v= m_views.next() )
05338 {
05339 v->config()->configStart();
05340 v->renderer()->config()->configStart();
05341 }
05342
05343 readVariableLine( t->varLine );
05344
05345 m_config->configEnd();
05346 for (v = m_views.first(); v != 0L; v= m_views.next() )
05347 {
05348 v->config()->configEnd();
05349 v->renderer()->config()->configEnd();
05350 }
05351 }
05352 }
05353 }
05354 }
05355
05356 uint KateDocument::documentNumber () const
05357 {
05358 return KTextEditor::Document::documentNumber ();
05359 }
05360
05361
05362
05363
05364 void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
05365 *handled=true;
05366 *abortClosing=true;
05367 if (m_url.isEmpty())
05368 {
05369 KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
05370 QString::null,QString::null,0,i18n("Save File"));
05371
05372 if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
05373 *abortClosing=true;
05374 return;
05375 }
05376 setEncoding( res.encoding );
05377 saveAs( res.URLs.first() );
05378 *abortClosing=false;
05379 }
05380 else
05381 {
05382 save();
05383 *abortClosing=false;
05384 }
05385
05386 }
05387
05388 bool KateDocument::checkOverwrite( KURL u )
05389 {
05390 if( !u.isLocalFile() )
05391 return true;
05392
05393 QFileInfo info( u.path() );
05394 if( !info.exists() )
05395 return true;
05396
05397 return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
05398 i18n( "A file named \"%1\" already exists. "
05399 "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
05400 i18n( "Overwrite File?" ),
05401 i18n( "&Overwrite" ) );
05402 }
05403
05404 void KateDocument::setDefaultEncoding (const QString &encoding)
05405 {
05406 s_defaultEncoding = encoding;
05407 }
05408
05409 void KateDocument::setIMSelectionValue( uint imStartLine, uint imStart, uint imEnd,
05410 uint imSelStart, uint imSelEnd, bool imComposeEvent )
05411 {
05412 m_imStartLine = imStartLine;
05413 m_imStart = imStart;
05414 m_imEnd = imEnd;
05415 m_imSelStart = imSelStart;
05416 m_imSelEnd = imSelEnd;
05417 m_imComposeEvent = imComposeEvent;
05418 }
05419
05420 void KateDocument::getIMSelectionValue( uint *imStartLine, uint *imStart, uint *imEnd,
05421 uint *imSelStart, uint *imSelEnd )
05422 {
05423 *imStartLine = m_imStartLine;
05424 *imStart = m_imStart;
05425 *imEnd = m_imEnd;
05426 *imSelStart = m_imSelStart;
05427 *imSelEnd = m_imSelEnd;
05428 }
05429
05430