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