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