• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kate
 

kate

  • kate
  • part
katedocument.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2001-2004 Christoph Cullmann <cullmann@kde.org>
3  Copyright (C) 2001 Joseph Wenninger <jowenn@kde.org>
4  Copyright (C) 1999 Jochen Wilhelmy <digisnap@cs.tu-berlin.de>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License version 2 as published by the Free Software Foundation.
9 
10  This library is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02111-13020, USA.
19 */
20 
21 //BEGIN includes
22 #include "katedocument.h"
23 #include "katedocument.moc"
24 #include "katekeyinterceptorfunctor.h"
25 #include "katefactory.h"
26 #include "katedialogs.h"
27 #include "katehighlight.h"
28 #include "kateview.h"
29 #include "katesearch.h"
30 #include "kateautoindent.h"
31 #include "katetextline.h"
32 #include "katedocumenthelpers.h"
33 #include "kateprinter.h"
34 #include "katelinerange.h"
35 #include "katesupercursor.h"
36 #include "katearbitraryhighlight.h"
37 #include "katerenderer.h"
38 #include "kateattribute.h"
39 #include "kateconfig.h"
40 #include "katefiletype.h"
41 #include "kateschema.h"
42 #include "katetemplatehandler.h"
43 #include <tdetexteditor/plugin.h>
44 
45 #include <tdeio/job.h>
46 #include <tdeio/netaccess.h>
47 #include <tdeio/tdefileitem.h>
48 
49 
50 #include <tdeparts/event.h>
51 
52 #include <tdelocale.h>
53 #include <tdeglobal.h>
54 #include <tdeapplication.h>
55 #include <tdepopupmenu.h>
56 #include <tdeconfig.h>
57 #include <tdefiledialog.h>
58 #include <tdemessagebox.h>
59 #include <kstdaction.h>
60 #include <kiconloader.h>
61 #include <kxmlguifactory.h>
62 #include <kdialogbase.h>
63 #include <kdebug.h>
64 #include <tdeglobalsettings.h>
65 #include <klibloader.h>
66 #include <kdirwatch.h>
67 #include <twin.h>
68 #include <kencodingfiledialog.h>
69 #include <tdetempfile.h>
70 #include <kmdcodec.h>
71 #include <kstandarddirs.h>
72 
73 #include <tqtimer.h>
74 #include <tqfile.h>
75 #include <tqclipboard.h>
76 #include <tqtextstream.h>
77 #include <tqtextcodec.h>
78 #include <tqmap.h>
79 //END includes
80 
81 //BEGIN PRIVATE CLASSES
82 class KatePartPluginItem
83 {
84  public:
85  KTextEditor::Plugin *plugin;
86 };
87 //END PRIVATE CLASSES
88 
89 //BEGIN d'tor, c'tor
90 //
91 // KateDocument Constructor
92 //
93 KateDocument::KateDocument ( bool bSingleViewMode, bool bBrowserView,
94  bool bReadOnly, TQWidget *parentWidget,
95  const char *widgetName, TQObject *parent, const char *name)
96 : Kate::Document(parent, name),
97  m_plugins (KateFactory::self()->plugins().count()),
98  m_undoDontMerge(false),
99  m_undoIgnoreCancel(false),
100  lastUndoGroupWhenSaved( 0 ),
101  lastRedoGroupWhenSaved( 0 ),
102  docWasSavedWhenUndoWasEmpty( true ),
103  docWasSavedWhenRedoWasEmpty( true ),
104  m_modOnHd (false),
105  m_modOnHdReason (0),
106  m_job (0),
107  m_tempFile (0),
108  m_tabInterceptor(0)
109 {
110  m_undoComplexMerge=false;
111  m_isInUndo = false;
112  // my dcop object
113  setObjId ("KateDocument#"+documentDCOPSuffix());
114 
115  // tdetexteditor interfaces
116  setBlockSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
117  setConfigInterfaceDCOPSuffix (documentDCOPSuffix());
118  setConfigInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
119  setCursorInterfaceDCOPSuffix (documentDCOPSuffix());
120  setEditInterfaceDCOPSuffix (documentDCOPSuffix());
121  setEncodingInterfaceDCOPSuffix (documentDCOPSuffix());
122  setHighlightingInterfaceDCOPSuffix (documentDCOPSuffix());
123  setMarkInterfaceDCOPSuffix (documentDCOPSuffix());
124  setMarkInterfaceExtensionDCOPSuffix (documentDCOPSuffix());
125  setPrintInterfaceDCOPSuffix (documentDCOPSuffix());
126  setSearchInterfaceDCOPSuffix (documentDCOPSuffix());
127  setSelectionInterfaceDCOPSuffix (documentDCOPSuffix());
128  setSelectionInterfaceExtDCOPSuffix (documentDCOPSuffix());
129  setSessionConfigInterfaceDCOPSuffix (documentDCOPSuffix());
130  setUndoInterfaceDCOPSuffix (documentDCOPSuffix());
131  setWordWrapInterfaceDCOPSuffix (documentDCOPSuffix());
132 
133  // init local plugin array
134  m_plugins.fill (0);
135 
136  // register doc at factory
137  KateFactory::self()->registerDocument (this);
138 
139  m_reloading = false;
140  m_loading = false;
141  m_encodingSticky = false;
142 
143  m_buffer = new KateBuffer (this);
144 
145  // init the config object, be careful not to use it
146  // until the initial readConfig() call is done
147  m_config = new KateDocumentConfig (this);
148 
149  // init some more vars !
150  m_activeView = 0L;
151 
152  hlSetByUser = false;
153  m_fileType = -1;
154  m_fileTypeSetByUser = false;
155  setInstance( KateFactory::self()->instance() );
156 
157  editSessionNumber = 0;
158  editIsRunning = false;
159  m_editCurrentUndo = 0L;
160  editWithUndo = false;
161 
162  m_docNameNumber = 0;
163 
164  m_bSingleViewMode = bSingleViewMode;
165  m_bBrowserView = bBrowserView;
166  m_bReadOnly = bReadOnly;
167 
168  m_marks.setAutoDelete( true );
169  m_markPixmaps.setAutoDelete( true );
170  m_markDescriptions.setAutoDelete( true );
171  setMarksUserChangable( markType01 );
172 
173  m_undoMergeTimer = new TQTimer(this);
174  connect(m_undoMergeTimer, TQ_SIGNAL(timeout()), TQ_SLOT(undoCancel()));
175 
176  clearMarks ();
177  clearUndo ();
178  clearRedo ();
179  setModified (false);
180  docWasSavedWhenUndoWasEmpty = true;
181 
182  // normal hl
183  m_buffer->setHighlight (0);
184 
185  m_extension = new KateBrowserExtension( this );
186  m_arbitraryHL = new KateArbitraryHighlight();
187  m_indenter = KateAutoIndent::createIndenter ( this, 0 );
188 
189  m_indenter->updateConfig ();
190 
191  // some nice signals from the buffer
192  connect(m_buffer, TQ_SIGNAL(tagLines(int,int)), this, TQ_SLOT(tagLines(int,int)));
193  connect(m_buffer, TQ_SIGNAL(codeFoldingUpdated()),this,TQ_SIGNAL(codeFoldingUpdated()));
194 
195  // if the user changes the highlight with the dialog, notify the doc
196  connect(KateHlManager::self(),TQ_SIGNAL(changed()),TQ_SLOT(internalHlChanged()));
197 
198  // signal for the arbitrary HL
199  connect(m_arbitraryHL, TQ_SIGNAL(tagLines(KateView*, KateSuperRange*)), TQ_SLOT(tagArbitraryLines(KateView*, KateSuperRange*)));
200 
201  // signals for mod on hd
202  connect( KateFactory::self()->dirWatch(), TQ_SIGNAL(dirty (const TQString &)),
203  this, TQ_SLOT(slotModOnHdDirty (const TQString &)) );
204 
205  connect( KateFactory::self()->dirWatch(), TQ_SIGNAL(created (const TQString &)),
206  this, TQ_SLOT(slotModOnHdCreated (const TQString &)) );
207 
208  connect( KateFactory::self()->dirWatch(), TQ_SIGNAL(deleted (const TQString &)),
209  this, TQ_SLOT(slotModOnHdDeleted (const TQString &)) );
210 
211  // update doc name
212  setDocName ("");
213 
214  // if single view mode, like in the konqui embedding, create a default view ;)
215  if ( m_bSingleViewMode )
216  {
217  KTextEditor::View *view = createView( parentWidget, widgetName );
218  insertChildClient( view );
219  view->show();
220  setWidget( view );
221  }
222 
223  connect(this,TQ_SIGNAL(sigQueryClose(bool *, bool*)),this,TQ_SLOT(slotQueryClose_save(bool *, bool*)));
224 
225  m_isasking = 0;
226 
227  // plugins
228  for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
229  {
230  if (config()->plugin (i))
231  loadPlugin (i);
232  }
233 }
234 
235 //
236 // KateDocument Destructor
237 //
238 KateDocument::~KateDocument()
239 {
240  // remove file from dirwatch
241  deactivateDirWatch ();
242 
243  if (!singleViewMode())
244  {
245  // clean up remaining views
246  m_views.setAutoDelete( true );
247  m_views.clear();
248  }
249 
250  delete m_editCurrentUndo;
251 
252  delete m_arbitraryHL;
253 
254  // cleanup the undo items, very important, truee :/
255  undoItems.setAutoDelete(true);
256  undoItems.clear();
257 
258  // clean up plugins
259  unloadAllPlugins ();
260 
261  delete m_config;
262  delete m_indenter;
263  KateFactory::self()->deregisterDocument (this);
264 }
265 //END
266 
267 //BEGIN Plugins
268 void KateDocument::unloadAllPlugins ()
269 {
270  for (uint i=0; i<m_plugins.count(); i++)
271  unloadPlugin (i);
272 }
273 
274 void KateDocument::enableAllPluginsGUI (KateView *view)
275 {
276  for (uint i=0; i<m_plugins.count(); i++)
277  enablePluginGUI (m_plugins[i], view);
278 }
279 
280 void KateDocument::disableAllPluginsGUI (KateView *view)
281 {
282  for (uint i=0; i<m_plugins.count(); i++)
283  disablePluginGUI (m_plugins[i], view);
284 }
285 
286 void KateDocument::loadPlugin (uint pluginIndex)
287 {
288  if (m_plugins[pluginIndex]) return;
289 
290  m_plugins[pluginIndex] = KTextEditor::createPlugin (TQFile::encodeName((KateFactory::self()->plugins())[pluginIndex]->library()), this);
291 
292  enablePluginGUI (m_plugins[pluginIndex]);
293 }
294 
295 void KateDocument::unloadPlugin (uint pluginIndex)
296 {
297  if (!m_plugins[pluginIndex]) return;
298 
299  disablePluginGUI (m_plugins[pluginIndex]);
300 
301  delete m_plugins[pluginIndex];
302  m_plugins[pluginIndex] = 0L;
303 }
304 
305 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
306 {
307  if (!plugin) return;
308  if (!KTextEditor::pluginViewInterface(plugin)) return;
309 
310  KXMLGUIFactory *factory = view->factory();
311  if ( factory )
312  factory->removeClient( view );
313 
314  KTextEditor::pluginViewInterface(plugin)->addView(view);
315 
316  if ( factory )
317  factory->addClient( view );
318 }
319 
320 void KateDocument::enablePluginGUI (KTextEditor::Plugin *plugin)
321 {
322  if (!plugin) return;
323  if (!KTextEditor::pluginViewInterface(plugin)) return;
324 
325  for (uint i=0; i< m_views.count(); i++)
326  enablePluginGUI (plugin, m_views.at(i));
327 }
328 
329 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin, KateView *view)
330 {
331  if (!plugin) return;
332  if (!KTextEditor::pluginViewInterface(plugin)) return;
333 
334  KXMLGUIFactory *factory = view->factory();
335  if ( factory )
336  factory->removeClient( view );
337 
338  KTextEditor::pluginViewInterface( plugin )->removeView( view );
339 
340  if ( factory )
341  factory->addClient( view );
342 }
343 
344 void KateDocument::disablePluginGUI (KTextEditor::Plugin *plugin)
345 {
346  if (!plugin) return;
347  if (!KTextEditor::pluginViewInterface(plugin)) return;
348 
349  for (uint i=0; i< m_views.count(); i++)
350  disablePluginGUI (plugin, m_views.at(i));
351 }
352 //END
353 
354 //BEGIN KTextEditor::Document stuff
355 
356 KTextEditor::View *KateDocument::createView( TQWidget *parent, const char *name )
357 {
358  KateView* newView = new KateView( this, parent, name);
359  connect(newView, TQ_SIGNAL(cursorPositionChanged()), TQ_SLOT(undoCancel()));
360  if ( s_fileChangedDialogsActivated )
361  connect( newView, TQ_SIGNAL(gotFocus( Kate::View * )), this, TQ_SLOT(slotModifiedOnDisk()) );
362  return newView;
363 }
364 
365 TQPtrList<KTextEditor::View> KateDocument::views () const
366 {
367  return m_textEditViews;
368 }
369 
370 void KateDocument::setActiveView( KateView *view )
371 {
372  if ( m_activeView == view ) return;
373 
374  m_activeView = view;
375 }
376 //END
377 
378 //BEGIN KTextEditor::ConfigInterfaceExtension stuff
379 
380 uint KateDocument::configPages () const
381 {
382  return 10;
383 }
384 
385 KTextEditor::ConfigPage *KateDocument::configPage (uint number, TQWidget *parent, const char * )
386 {
387  switch( number )
388  {
389  case 0:
390  return new KateViewDefaultsConfig (parent);
391 
392  case 1:
393  return new KateSchemaConfigPage (parent, this);
394 
395  case 2:
396  return new KateSelectConfigTab (parent);
397 
398  case 3:
399  return new KateEditConfigTab (parent);
400 
401  case 4:
402  return new KateIndentConfigTab (parent);
403 
404  case 5:
405  return new KateSaveConfigTab (parent);
406 
407  case 6:
408  return new KateHlConfigPage (parent, this);
409 
410  case 7:
411  return new KateFileTypeConfigTab (parent);
412 
413  case 8:
414  return new KateEditKeyConfiguration (parent, this);
415 
416  case 9:
417  return new KatePartPluginConfigPage (parent);
418 
419  default:
420  return 0;
421  }
422 
423  return 0;
424 }
425 
426 TQString KateDocument::configPageName (uint number) const
427 {
428  switch( number )
429  {
430  case 0:
431  return i18n ("Appearance");
432 
433  case 1:
434  return i18n ("Fonts & Colors");
435 
436  case 2:
437  return i18n ("Cursor & Selection");
438 
439  case 3:
440  return i18n ("Editing");
441 
442  case 4:
443  return i18n ("Indentation");
444 
445  case 5:
446  return i18n("Open/Save");
447 
448  case 6:
449  return i18n ("Highlighting");
450 
451  case 7:
452  return i18n("Filetypes");
453 
454  case 8:
455  return i18n ("Shortcuts");
456 
457  case 9:
458  return i18n ("Plugins");
459 
460  default:
461  return TQString ("");
462  }
463 
464  return TQString ("");
465 }
466 
467 TQString KateDocument::configPageFullName (uint number) const
468 {
469  switch( number )
470  {
471  case 0:
472  return i18n("Appearance");
473 
474  case 1:
475  return i18n ("Font & Color Schemas");
476 
477  case 2:
478  return i18n ("Cursor & Selection Behavior");
479 
480  case 3:
481  return i18n ("Editing Options");
482 
483  case 4:
484  return i18n ("Indentation Rules");
485 
486  case 5:
487  return i18n("File Opening & Saving");
488 
489  case 6:
490  return i18n ("Highlighting Rules");
491 
492  case 7:
493  return i18n("Filetype Specific Settings");
494 
495  case 8:
496  return i18n ("Shortcuts Configuration");
497 
498  case 9:
499  return i18n ("Plugin Manager");
500 
501  default:
502  return TQString ("");
503  }
504 
505  return TQString ("");
506 }
507 
508 TQPixmap KateDocument::configPagePixmap (uint number, int size) const
509 {
510  switch( number )
511  {
512  case 0:
513  return BarIcon("view_text",size);
514 
515  case 1:
516  return BarIcon("colorize", size);
517 
518  case 2:
519  return BarIcon("frame_edit", size);
520 
521  case 3:
522  return BarIcon("edit", size);
523 
524  case 4:
525  return BarIcon("format-justify-right", size);
526 
527  case 5:
528  return BarIcon("document-save", size);
529 
530  case 6:
531  return BarIcon("text-x-src", size);
532 
533  case 7:
534  return BarIcon("edit", size);
535 
536  case 8:
537  return BarIcon("key_enter", size);
538 
539  case 9:
540  return BarIcon("connect_established", size);
541 
542  default:
543  return BarIcon("edit", size);
544  }
545 
546  return BarIcon("edit", size);
547 }
548 //END
549 
550 //BEGIN KTextEditor::EditInterface stuff
551 
552 TQString KateDocument::text() const
553 {
554  TQString s;
555 
556  for (uint i = 0; i < m_buffer->count(); i++)
557  {
558  KateTextLine::Ptr textLine = m_buffer->plainLine(i);
559 
560  if (textLine)
561  {
562  s.append (textLine->string());
563 
564  if ((i+1) < m_buffer->count())
565  s.append('\n');
566  }
567  }
568 
569  return s;
570 }
571 
572 TQString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol ) const
573 {
574  return text(startLine, startCol, endLine, endCol, false);
575 }
576 
577 TQString KateDocument::text ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise) const
578 {
579  if ( blockwise && (startCol > endCol) )
580  return TQString ();
581 
582  TQString s;
583 
584  if (startLine == endLine)
585  {
586  if (startCol > endCol)
587  return TQString ();
588 
589  KateTextLine::Ptr textLine = m_buffer->plainLine(startLine);
590 
591  if ( !textLine )
592  return TQString ();
593 
594  return textLine->string(startCol, endCol-startCol);
595  }
596  else
597  {
598 
599  for (uint i = startLine; (i <= endLine) && (i < m_buffer->count()); i++)
600  {
601  KateTextLine::Ptr textLine = m_buffer->plainLine(i);
602 
603  if ( !blockwise )
604  {
605  if (i == startLine)
606  s.append (textLine->string(startCol, textLine->length()-startCol));
607  else if (i == endLine)
608  s.append (textLine->string(0, endCol));
609  else
610  s.append (textLine->string());
611  }
612  else
613  {
614  s.append( textLine->string( startCol, endCol-startCol));
615  }
616 
617  if ( i < endLine )
618  s.append('\n');
619  }
620  }
621 
622  return s;
623 }
624 
625 TQString KateDocument::textLine( uint line ) const
626 {
627  KateTextLine::Ptr l = m_buffer->plainLine(line);
628 
629  if (!l)
630  return TQString();
631 
632  return l->string();
633 }
634 
635 bool KateDocument::setText(const TQString &s)
636 {
637  if (!isReadWrite())
638  return false;
639 
640  TQPtrList<KTextEditor::Mark> m = marks ();
641  TQValueList<KTextEditor::Mark> msave;
642 
643  for (uint i=0; i < m.count(); i++)
644  msave.append (*m.at(i));
645 
646  editStart ();
647 
648  // delete the text
649  clear();
650 
651  // insert the new text
652  insertText (0, 0, s);
653 
654  editEnd ();
655 
656  for (uint i=0; i < msave.count(); i++)
657  setMark (msave[i].line, msave[i].type);
658 
659  return true;
660 }
661 
662 bool KateDocument::clear()
663 {
664  if (!isReadWrite())
665  return false;
666 
667  for (KateView * view = m_views.first(); view != 0L; view = m_views.next() ) {
668  view->clear();
669  view->tagAll();
670  view->update();
671  }
672 
673  clearMarks ();
674 
675  return removeText (0,0,lastLine()+1, 0);
676 }
677 
678 bool KateDocument::insertText( uint line, uint col, const TQString &s)
679 {
680  return insertText (line, col, s, false);
681 }
682 
683 bool KateDocument::insertText( uint line, uint col, const TQString &s, bool blockwise )
684 {
685  if (!isReadWrite())
686  return false;
687 
688  if (s.isEmpty())
689  return true;
690 
691  if (line == numLines())
692  editInsertLine(line,"");
693  else if (line > lastLine())
694  return false;
695 
696  editStart ();
697 
698  uint insertPos = col;
699  uint len = s.length();
700 
701  TQString buf;
702 
703  bool replacetabs = ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo );
704  uint tw = config()->tabWidth();
705  uint insertPosExpanded = insertPos;
706  KateTextLine::Ptr l = m_buffer->line( line );
707  if (l != 0)
708  insertPosExpanded = l->cursorX( insertPos, tw );
709 
710  for (uint pos = 0; pos < len; pos++)
711  {
712  TQChar ch = s[pos];
713 
714  if (ch == '\n')
715  {
716  editInsertText (line, insertPos, buf);
717 
718  if ( !blockwise )
719  {
720  editWrapLine (line, insertPos + buf.length());
721  insertPos = insertPosExpanded = 0;
722  }
723  else
724  {
725  if ( line == lastLine() )
726  editWrapLine (line, insertPos + buf.length());
727  }
728 
729  line++;
730  buf.truncate(0);
731  l = m_buffer->line( line );
732  if (l)
733  insertPosExpanded = l->cursorX( insertPos, tw );
734  }
735  else
736  {
737  if ( replacetabs && ch == '\t' )
738  {
739  uint tr = tw - ( insertPosExpanded+buf.length() )%tw;
740  for ( uint i=0; i < tr; i++ )
741  buf += ' ';
742  }
743  else
744  buf += ch; // append char to buffer
745  }
746  }
747 
748  editInsertText (line, insertPos, buf);
749 
750  editEnd ();
751  emit textInserted(line,insertPos);
752  return true;
753 }
754 
755 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol )
756 {
757  return removeText (startLine, startCol, endLine, endCol, false);
758 }
759 
760 bool KateDocument::removeText ( uint startLine, uint startCol, uint endLine, uint endCol, bool blockwise)
761 {
762  if (!isReadWrite())
763  return false;
764 
765  if ( blockwise && (startCol > endCol) )
766  return false;
767 
768  if ( startLine > endLine )
769  return false;
770 
771  if ( startLine > lastLine() )
772  return false;
773 
774  if (!blockwise) {
775  emit aboutToRemoveText(KateTextRange(startLine,startCol,endLine,endCol));
776  }
777  editStart ();
778 
779  if ( !blockwise )
780  {
781  if ( endLine > lastLine() )
782  {
783  endLine = lastLine()+1;
784  endCol = 0;
785  }
786 
787  if (startLine == endLine)
788  {
789  editRemoveText (startLine, startCol, endCol-startCol);
790  }
791  else if ((startLine+1) == endLine)
792  {
793  if ( (m_buffer->plainLine(startLine)->length()-startCol) > 0 )
794  editRemoveText (startLine, startCol, m_buffer->plainLine(startLine)->length()-startCol);
795 
796  editRemoveText (startLine+1, 0, endCol);
797  editUnWrapLine (startLine);
798  }
799  else
800  {
801  for (uint line = endLine; line >= startLine; line--)
802  {
803  if ((line > startLine) && (line < endLine))
804  {
805  editRemoveLine (line);
806  }
807  else
808  {
809  if (line == endLine)
810  {
811  if ( endLine <= lastLine() )
812  editRemoveText (line, 0, endCol);
813  }
814  else
815  {
816  if ( (m_buffer->plainLine(line)->length()-startCol) > 0 )
817  editRemoveText (line, startCol, m_buffer->plainLine(line)->length()-startCol);
818 
819  editUnWrapLine (startLine);
820  }
821  }
822 
823  if ( line == 0 )
824  break;
825  }
826  }
827  } // if ( ! blockwise )
828  else
829  {
830  if ( endLine > lastLine() )
831  endLine = lastLine ();
832 
833  for (uint line = endLine; line >= startLine; line--)
834  {
835 
836  editRemoveText (line, startCol, endCol-startCol);
837 
838  if ( line == 0 )
839  break;
840  }
841  }
842 
843  editEnd ();
844  emit textRemoved();
845  return true;
846 }
847 
848 bool KateDocument::insertLine( uint l, const TQString &str )
849 {
850  if (!isReadWrite())
851  return false;
852 
853  if (l > numLines())
854  return false;
855 
856  return editInsertLine (l, str);
857 }
858 
859 bool KateDocument::removeLine( uint line )
860 {
861  if (!isReadWrite())
862  return false;
863 
864  if (line > lastLine())
865  return false;
866 
867  return editRemoveLine (line);
868 }
869 
870 uint KateDocument::length() const
871 {
872  uint l = 0;
873 
874  for (uint i = 0; i < m_buffer->count(); i++)
875  {
876  KateTextLine::Ptr line = m_buffer->plainLine(i);
877 
878  if (line)
879  l += line->length();
880  }
881 
882  return l;
883 }
884 
885 uint KateDocument::numLines() const
886 {
887  return m_buffer->count();
888 }
889 
890 uint KateDocument::numVisLines() const
891 {
892  return m_buffer->countVisible ();
893 }
894 
895 int KateDocument::lineLength ( uint line ) const
896 {
897  KateTextLine::Ptr l = m_buffer->plainLine(line);
898 
899  if (!l)
900  return -1;
901 
902  return l->length();
903 }
904 //END
905 
906 //BEGIN KTextEditor::EditInterface internal stuff
907 //
908 // Starts an edit session with (or without) undo, update of view disabled during session
909 //
910 void KateDocument::editStart (bool withUndo)
911 {
912  editSessionNumber++;
913 
914  if (editSessionNumber > 1)
915  return;
916 
917  editIsRunning = true;
918  editWithUndo = withUndo;
919 
920  if (editWithUndo)
921  undoStart();
922  else
923  undoCancel();
924 
925  for (uint z = 0; z < m_views.count(); z++)
926  {
927  m_views.at(z)->editStart ();
928  }
929 
930  m_buffer->editStart ();
931 }
932 
933 void KateDocument::undoStart()
934 {
935  if (m_editCurrentUndo || (m_activeView && m_activeView->imComposeEvent())) return;
936 
937  // Make sure the buffer doesn't get bigger than requested
938  if ((config()->undoSteps() > 0) && (undoItems.count() > config()->undoSteps()))
939  {
940  undoItems.setAutoDelete(true);
941  undoItems.removeFirst();
942  undoItems.setAutoDelete(false);
943  docWasSavedWhenUndoWasEmpty = false;
944  }
945 
946  // new current undo item
947  m_editCurrentUndo = new KateUndoGroup(this);
948 }
949 
950 void KateDocument::undoEnd()
951 {
952  if (m_activeView && m_activeView->imComposeEvent())
953  return;
954 
955  if (m_editCurrentUndo)
956  {
957  bool changedUndo = false;
958 
959  if (m_editCurrentUndo->isEmpty())
960  delete m_editCurrentUndo;
961  else if (!m_undoDontMerge && undoItems.last() && undoItems.last()->merge(m_editCurrentUndo,m_undoComplexMerge))
962  delete m_editCurrentUndo;
963  else
964  {
965  undoItems.append(m_editCurrentUndo);
966  changedUndo = true;
967  }
968 
969  m_undoDontMerge = false;
970  m_undoIgnoreCancel = true;
971 
972  m_editCurrentUndo = 0L;
973 
974  // (Re)Start the single-shot timer to cancel the undo merge
975  // the user has 5 seconds to input more data, or undo merging gets canceled for the current undo item.
976  m_undoMergeTimer->start(5000, true);
977 
978  if (changedUndo)
979  emit undoChanged();
980  }
981 }
982 
983 void KateDocument::undoCancel()
984 {
985  if (m_undoIgnoreCancel) {
986  m_undoIgnoreCancel = false;
987  return;
988  }
989 
990  m_undoDontMerge = true;
991 
992  Q_ASSERT(!m_editCurrentUndo);
993 
994  // As you can see by the above assert, neither of these should really be required
995  delete m_editCurrentUndo;
996  m_editCurrentUndo = 0L;
997 }
998 
999 void KateDocument::undoSafePoint() {
1000  Q_ASSERT(m_editCurrentUndo);
1001  if (!m_editCurrentUndo) return;
1002  m_editCurrentUndo->safePoint();
1003 }
1004 
1005 //
1006 // End edit session and update Views
1007 //
1008 void KateDocument::editEnd ()
1009 {
1010  if (editSessionNumber == 0)
1011  return;
1012 
1013  // wrap the new/changed text, if something really changed!
1014  if (m_buffer->editChanged() && (editSessionNumber == 1))
1015  if (editWithUndo && config()->wordWrap())
1016  wrapText (m_buffer->editTagStart(), m_buffer->editTagEnd());
1017 
1018  editSessionNumber--;
1019 
1020  if (editSessionNumber > 0)
1021  return;
1022 
1023  // end buffer edit, will trigger hl update
1024  // this will cause some possible adjustment of tagline start/end
1025  m_buffer->editEnd ();
1026 
1027  if (editWithUndo)
1028  undoEnd();
1029 
1030  // edit end for all views !!!!!!!!!
1031  for (uint z = 0; z < m_views.count(); z++)
1032  m_views.at(z)->editEnd (m_buffer->editTagStart(), m_buffer->editTagEnd(), m_buffer->editTagFrom());
1033 
1034  if (m_buffer->editChanged())
1035  {
1036  setModified(true);
1037  emit textChanged ();
1038  }
1039 
1040  editIsRunning = false;
1041 }
1042 
1043 bool KateDocument::wrapText (uint startLine, uint endLine)
1044 {
1045  uint col = config()->wordWrapAt();
1046 
1047  if (col == 0)
1048  return false;
1049 
1050  editStart ();
1051 
1052  for (uint line = startLine; (line <= endLine) && (line < numLines()); line++)
1053  {
1054  KateTextLine::Ptr l = m_buffer->line(line);
1055 
1056  if (!l)
1057  return false;
1058 
1059  kdDebug (13020) << "try wrap line: " << line << endl;
1060 
1061  if (l->lengthWithTabs(m_buffer->tabWidth()) > col)
1062  {
1063  KateTextLine::Ptr nextl = m_buffer->line(line+1);
1064 
1065  kdDebug (13020) << "do wrap line: " << line << endl;
1066 
1067  const TQChar *text = l->text();
1068  uint eolPosition = l->length()-1;
1069 
1070  // take tabs into account here, too
1071  uint x = 0;
1072  const TQString & t = l->string();
1073  uint z2 = 0;
1074  for ( ; z2 < l->length(); z2++)
1075  {
1076  if (t[z2] == TQChar('\t'))
1077  x += m_buffer->tabWidth() - (x % m_buffer->tabWidth());
1078  else
1079  x++;
1080 
1081  if (x > col)
1082  break;
1083  }
1084 
1085  uint searchStart = kMin (z2, l->length()-1);
1086 
1087  // If where we are wrapping is an end of line and is a space we don't
1088  // want to wrap there
1089  if (searchStart == eolPosition && text[searchStart].isSpace())
1090  searchStart--;
1091 
1092  // Scan backwards looking for a place to break the line
1093  // We are not interested in breaking at the first char
1094  // of the line (if it is a space), but we are at the second
1095  // anders: if we can't find a space, try breaking on a word
1096  // boundry, using KateHighlight::canBreakAt().
1097  // This could be a priority (setting) in the hl/filetype/document
1098  int z = 0;
1099  uint nw = 0; // alternative position, a non word character
1100  for (z=searchStart; z > 0; z--)
1101  {
1102  if (text[z].isSpace()) break;
1103  if ( ! nw && highlight()->canBreakAt( text[z] , l->attribute(z) ) )
1104  nw = z;
1105  }
1106 
1107  if (z > 0)
1108  {
1109  // cu space
1110  editRemoveText (line, z, 1);
1111  }
1112  else
1113  {
1114  // There was no space to break at so break at a nonword character if
1115  // found, or at the wrapcolumn ( that needs be configurable )
1116  // Don't try and add any white space for the break
1117  if ( nw && nw < col ) nw++; // break on the right side of the character
1118  z = nw ? nw : col;
1119  }
1120 
1121  if (nextl && !nextl->isAutoWrapped())
1122  {
1123  editWrapLine (line, z, true);
1124  editMarkLineAutoWrapped (line+1, true);
1125 
1126  endLine++;
1127  }
1128  else
1129  {
1130  if (nextl && (nextl->length() > 0) && !nextl->getChar(0).isSpace() && ((l->length() < 1) || !l->getChar(l->length()-1).isSpace()))
1131  editInsertText (line+1, 0, TQString (" "));
1132 
1133  bool newLineAdded = false;
1134  editWrapLine (line, z, false, &newLineAdded);
1135 
1136  editMarkLineAutoWrapped (line+1, true);
1137 
1138  endLine++;
1139  }
1140  }
1141  }
1142 
1143  editEnd ();
1144 
1145  return true;
1146 }
1147 
1148 void KateDocument::editAddUndo (KateUndoGroup::UndoType type, uint line, uint col, uint len, const TQString &text)
1149 {
1150  if (editIsRunning && editWithUndo && m_editCurrentUndo) {
1151  m_editCurrentUndo->addItem(type, line, col, len, text);
1152 
1153  // Clear redo buffer
1154  if (redoItems.count()) {
1155  redoItems.setAutoDelete(true);
1156  redoItems.clear();
1157  redoItems.setAutoDelete(false);
1158  }
1159  }
1160 }
1161 
1162 bool KateDocument::editInsertText ( uint line, uint col, const TQString &str )
1163 {
1164  if (!isReadWrite())
1165  return false;
1166 
1167  TQString s = str;
1168 
1169  KateTextLine::Ptr l = m_buffer->line(line);
1170 
1171  if (!l)
1172  return false;
1173 
1174  if ( config()->configFlags() & KateDocumentConfig::cfReplaceTabsDyn && ! m_isInUndo )
1175  {
1176  uint tw = config()->tabWidth();
1177  int pos = 0;
1178  uint l = 0;
1179  while ( (pos = s.find('\t')) > -1 )
1180  {
1181  l = tw - ( (col + pos)%tw );
1182  s.replace( pos, 1, TQString().fill( ' ', l ) );
1183  }
1184  }
1185 
1186  editStart ();
1187 
1188  editAddUndo (KateUndoGroup::editInsertText, line, col, s.length(), s);
1189 
1190  l->insertText (col, s.length(), s.unicode());
1191 // removeTrailingSpace(line); // ### nessecary?
1192 
1193  m_buffer->changeLine(line);
1194 
1195  for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1196  it.current()->editTextInserted (line, col, s.length());
1197 
1198  editEnd ();
1199 
1200  return true;
1201 }
1202 
1203 bool KateDocument::editRemoveText ( uint line, uint col, uint len )
1204 {
1205  if (!isReadWrite())
1206  return false;
1207 
1208  KateTextLine::Ptr l = m_buffer->line(line);
1209 
1210  if (!l)
1211  return false;
1212 
1213  editStart ();
1214 
1215  editAddUndo (KateUndoGroup::editRemoveText, line, col, len, l->string().mid(col, len));
1216 
1217  l->removeText (col, len);
1218  removeTrailingSpace( line );
1219 
1220  m_buffer->changeLine(line);
1221 
1222  for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1223  it.current()->editTextRemoved (line, col, len);
1224 
1225  editEnd ();
1226 
1227  return true;
1228 }
1229 
1230 bool KateDocument::editMarkLineAutoWrapped ( uint line, bool autowrapped )
1231 {
1232  if (!isReadWrite())
1233  return false;
1234 
1235  KateTextLine::Ptr l = m_buffer->line(line);
1236 
1237  if (!l)
1238  return false;
1239 
1240  editStart ();
1241 
1242  editAddUndo (KateUndoGroup::editMarkLineAutoWrapped, line, autowrapped ? 1 : 0, 0, TQString::null);
1243 
1244  l->setAutoWrapped (autowrapped);
1245 
1246  m_buffer->changeLine(line);
1247 
1248  editEnd ();
1249 
1250  return true;
1251 }
1252 
1253 bool KateDocument::editWrapLine ( uint line, uint col, bool newLine, bool *newLineAdded)
1254 {
1255  if (!isReadWrite())
1256  return false;
1257 
1258  KateTextLine::Ptr l = m_buffer->line(line);
1259 
1260  if (!l)
1261  return false;
1262 
1263  editStart ();
1264 
1265  KateTextLine::Ptr nextLine = m_buffer->line(line+1);
1266 
1267  int pos = l->length() - col;
1268 
1269  if (pos < 0)
1270  pos = 0;
1271 
1272  editAddUndo (KateUndoGroup::editWrapLine, line, col, pos, (!nextLine || newLine) ? "1" : "0");
1273 
1274  if (!nextLine || newLine)
1275  {
1276  KateTextLine::Ptr textLine = new KateTextLine();
1277 
1278  textLine->insertText (0, pos, l->text()+col, l->attributes()+col);
1279  l->truncate(col);
1280 
1281  m_buffer->insertLine (line+1, textLine);
1282  m_buffer->changeLine(line);
1283 
1284  TQPtrList<KTextEditor::Mark> list;
1285  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1286  {
1287  if( it.current()->line >= line )
1288  {
1289  if ((col == 0) || (it.current()->line > line))
1290  list.append( it.current() );
1291  }
1292  }
1293 
1294  for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1295  {
1296  KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1297  mark->line++;
1298  m_marks.insert( mark->line, mark );
1299  }
1300 
1301  if( !list.isEmpty() )
1302  emit marksChanged();
1303 
1304  // yes, we added a new line !
1305  if (newLineAdded)
1306  (*newLineAdded) = true;
1307  }
1308  else
1309  {
1310  nextLine->insertText (0, pos, l->text()+col, l->attributes()+col);
1311  l->truncate(col);
1312 
1313  m_buffer->changeLine(line);
1314  m_buffer->changeLine(line+1);
1315 
1316  // no, no new line added !
1317  if (newLineAdded)
1318  (*newLineAdded) = false;
1319  }
1320 
1321  for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1322  it.current()->editLineWrapped (line, col, !nextLine || newLine);
1323 
1324  editEnd ();
1325 
1326  return true;
1327 }
1328 
1329 bool KateDocument::editUnWrapLine ( uint line, bool removeLine, uint length )
1330 {
1331  if (!isReadWrite())
1332  return false;
1333 
1334  KateTextLine::Ptr l = m_buffer->line(line);
1335  KateTextLine::Ptr nextLine = m_buffer->line(line+1);
1336 
1337  if (!l || !nextLine)
1338  return false;
1339 
1340  editStart ();
1341 
1342  uint col = l->length ();
1343 
1344  editAddUndo (KateUndoGroup::editUnWrapLine, line, col, length, removeLine ? "1" : "0");
1345 
1346  if (removeLine)
1347  {
1348  l->insertText (col, nextLine->length(), nextLine->text(), nextLine->attributes());
1349 
1350  m_buffer->changeLine(line);
1351  m_buffer->removeLine(line+1);
1352  }
1353  else
1354  {
1355  l->insertText (col, (nextLine->length() < length) ? nextLine->length() : length,
1356  nextLine->text(), nextLine->attributes());
1357  nextLine->removeText (0, (nextLine->length() < length) ? nextLine->length() : length);
1358 
1359  m_buffer->changeLine(line);
1360  m_buffer->changeLine(line+1);
1361  }
1362 
1363  TQPtrList<KTextEditor::Mark> list;
1364  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1365  {
1366  if( it.current()->line >= line+1 )
1367  list.append( it.current() );
1368 
1369  if ( it.current()->line == line+1 )
1370  {
1371  KTextEditor::Mark* mark = m_marks.take( line );
1372 
1373  if (mark)
1374  {
1375  it.current()->type |= mark->type;
1376  }
1377  }
1378  }
1379 
1380  for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1381  {
1382  KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1383  mark->line--;
1384  m_marks.insert( mark->line, mark );
1385  }
1386 
1387  if( !list.isEmpty() )
1388  emit marksChanged();
1389 
1390  for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1391  it.current()->editLineUnWrapped (line, col, removeLine, length);
1392 
1393  editEnd ();
1394 
1395  return true;
1396 }
1397 
1398 bool KateDocument::editInsertLine ( uint line, const TQString &s )
1399 {
1400  if (!isReadWrite())
1401  return false;
1402 
1403  if ( line > numLines() )
1404  return false;
1405 
1406  editStart ();
1407 
1408  editAddUndo (KateUndoGroup::editInsertLine, line, 0, s.length(), s);
1409 
1410  removeTrailingSpace( line ); // old line
1411 
1412  KateTextLine::Ptr tl = new KateTextLine();
1413  tl->insertText (0, s.length(), s.unicode(), 0);
1414  m_buffer->insertLine(line, tl);
1415  m_buffer->changeLine(line);
1416 
1417  removeTrailingSpace( line ); // new line
1418 
1419  TQPtrList<KTextEditor::Mark> list;
1420  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1421  {
1422  if( it.current()->line >= line )
1423  list.append( it.current() );
1424  }
1425 
1426  for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1427  {
1428  KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1429  mark->line++;
1430  m_marks.insert( mark->line, mark );
1431  }
1432 
1433  if( !list.isEmpty() )
1434  emit marksChanged();
1435 
1436  for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1437  it.current()->editLineInserted (line);
1438 
1439  editEnd ();
1440 
1441  return true;
1442 }
1443 
1444 bool KateDocument::editRemoveLine ( uint line )
1445 {
1446  if (!isReadWrite())
1447  return false;
1448 
1449  if ( line > lastLine() )
1450  return false;
1451 
1452  if ( numLines() == 1 )
1453  return editRemoveText (0, 0, m_buffer->line(0)->length());
1454 
1455  editStart ();
1456 
1457  editAddUndo (KateUndoGroup::editRemoveLine, line, 0, lineLength(line), textLine(line));
1458 
1459  m_buffer->removeLine(line);
1460 
1461  TQPtrList<KTextEditor::Mark> list;
1462  KTextEditor::Mark* rmark = 0;
1463  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
1464  {
1465  if ( (it.current()->line > line) )
1466  list.append( it.current() );
1467  else if ( (it.current()->line == line) )
1468  rmark = it.current();
1469  }
1470 
1471  if (rmark)
1472  delete (m_marks.take (rmark->line));
1473 
1474  for( TQPtrListIterator<KTextEditor::Mark> it( list ); it.current(); ++it )
1475  {
1476  KTextEditor::Mark* mark = m_marks.take( it.current()->line );
1477  mark->line--;
1478  m_marks.insert( mark->line, mark );
1479  }
1480 
1481  if( !list.isEmpty() )
1482  emit marksChanged();
1483 
1484  for( TQPtrListIterator<KateSuperCursor> it (m_superCursors); it.current(); ++it )
1485  it.current()->editLineRemoved (line);
1486 
1487  editEnd();
1488 
1489  return true;
1490 }
1491 //END
1492 
1493 //BEGIN KTextEditor::UndoInterface stuff
1494 
1495 uint KateDocument::undoCount () const
1496 {
1497  return undoItems.count ();
1498 }
1499 
1500 uint KateDocument::redoCount () const
1501 {
1502  return redoItems.count ();
1503 }
1504 
1505 uint KateDocument::undoSteps () const
1506 {
1507  return m_config->undoSteps();
1508 }
1509 
1510 void KateDocument::setUndoSteps(uint steps)
1511 {
1512  m_config->setUndoSteps (steps);
1513 }
1514 
1515 void KateDocument::undo()
1516 {
1517  m_isInUndo = true;
1518  if ((undoItems.count() > 0) && undoItems.last())
1519  {
1520  clearSelection ();
1521 
1522  undoItems.last()->undo();
1523  redoItems.append (undoItems.last());
1524  undoItems.removeLast ();
1525  updateModified();
1526 
1527  emit undoChanged ();
1528  }
1529  m_isInUndo = false;
1530 }
1531 
1532 void KateDocument::redo()
1533 {
1534  m_isInUndo = true;
1535  if ((redoItems.count() > 0) && redoItems.last())
1536  {
1537  clearSelection ();
1538 
1539  redoItems.last()->redo();
1540  undoItems.append (redoItems.last());
1541  redoItems.removeLast ();
1542  updateModified();
1543 
1544  emit undoChanged ();
1545  }
1546  m_isInUndo = false;
1547 }
1548 
1549 void KateDocument::updateModified()
1550 {
1551  /*
1552  How this works:
1553 
1554  After noticing that there where to many scenarios to take into
1555  consideration when using 'if's to toggle the "Modified" flag
1556  I came up with this baby, flexible and repetitive calls are
1557  minimal.
1558 
1559  A numeric unique pattern is generated by toggleing a set of bits,
1560  each bit symbolizes a different state in the Undo Redo structure.
1561 
1562  undoItems.isEmpty() != null BIT 1
1563  redoItems.isEmpty() != null BIT 2
1564  docWasSavedWhenUndoWasEmpty == true BIT 3
1565  docWasSavedWhenRedoWasEmpty == true BIT 4
1566  lastUndoGroupWhenSavedIsLastUndo BIT 5
1567  lastUndoGroupWhenSavedIsLastRedo BIT 6
1568  lastRedoGroupWhenSavedIsLastUndo BIT 7
1569  lastRedoGroupWhenSavedIsLastRedo BIT 8
1570 
1571  If you find a new pattern, please add it to the patterns array
1572  */
1573 
1574  unsigned char currentPattern = 0;
1575  const unsigned char patterns[] = {5,16,24,26,88,90,93,133,144,149,165};
1576  const unsigned char patternCount = sizeof(patterns);
1577  KateUndoGroup* undoLast = 0;
1578  KateUndoGroup* redoLast = 0;
1579 
1580  if (undoItems.isEmpty())
1581  {
1582  currentPattern |= 1;
1583  }
1584  else
1585  {
1586  undoLast = undoItems.last();
1587  }
1588 
1589  if (redoItems.isEmpty())
1590  {
1591  currentPattern |= 2;
1592  }
1593  else
1594  {
1595  redoLast = redoItems.last();
1596  }
1597 
1598  if (docWasSavedWhenUndoWasEmpty) currentPattern |= 4;
1599  if (docWasSavedWhenRedoWasEmpty) currentPattern |= 8;
1600  if (lastUndoGroupWhenSaved == undoLast) currentPattern |= 16;
1601  if (lastUndoGroupWhenSaved == redoLast) currentPattern |= 32;
1602  if (lastRedoGroupWhenSaved == undoLast) currentPattern |= 64;
1603  if (lastRedoGroupWhenSaved == redoLast) currentPattern |= 128;
1604 
1605  // This will print out the pattern information
1606 
1607  kdDebug(13020) << k_funcinfo
1608  << "Pattern:" << static_cast<unsigned int>(currentPattern) << endl;
1609 
1610  for (uint patternIndex = 0; patternIndex < patternCount; ++patternIndex)
1611  {
1612  if ( currentPattern == patterns[patternIndex] )
1613  {
1614  setModified( false );
1615  kdDebug(13020) << k_funcinfo << "setting modified to false!" << endl;
1616  break;
1617  }
1618  }
1619 }
1620 
1621 void KateDocument::clearUndo()
1622 {
1623  undoItems.setAutoDelete (true);
1624  undoItems.clear ();
1625  undoItems.setAutoDelete (false);
1626 
1627  lastUndoGroupWhenSaved = 0;
1628  docWasSavedWhenUndoWasEmpty = false;
1629 
1630  emit undoChanged ();
1631 }
1632 
1633 void KateDocument::clearRedo()
1634 {
1635  redoItems.setAutoDelete (true);
1636  redoItems.clear ();
1637  redoItems.setAutoDelete (false);
1638 
1639  lastRedoGroupWhenSaved = 0;
1640  docWasSavedWhenRedoWasEmpty = false;
1641 
1642  emit undoChanged ();
1643 }
1644 
1645 TQPtrList<KTextEditor::Cursor> KateDocument::cursors () const
1646 {
1647  return myCursors;
1648 }
1649 //END
1650 
1651 //BEGIN KTextEditor::SearchInterface stuff
1652 
1653 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const TQString &text, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool casesensitive, bool backwards)
1654 {
1655  if (text.isEmpty())
1656  return false;
1657 
1658  int line = startLine;
1659  int col = startCol;
1660 
1661  if (!backwards)
1662  {
1663  int searchEnd = lastLine();
1664 
1665  while (line <= searchEnd)
1666  {
1667  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1668 
1669  if (!textLine)
1670  return false;
1671 
1672  uint foundAt, myMatchLen;
1673  bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, false);
1674 
1675  if (found)
1676  {
1677  (*foundAtLine) = line;
1678  (*foundAtCol) = foundAt;
1679  (*matchLen) = myMatchLen;
1680  return true;
1681  }
1682 
1683  col = 0;
1684  line++;
1685  }
1686  }
1687  else
1688  {
1689  // backward search
1690  int searchEnd = 0;
1691 
1692  while (line >= searchEnd)
1693  {
1694  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1695 
1696  if (!textLine)
1697  return false;
1698 
1699  uint foundAt, myMatchLen;
1700  bool found = textLine->searchText (col, text, &foundAt, &myMatchLen, casesensitive, true);
1701 
1702  if (found)
1703  {
1704  /* if ((uint) line == startLine && foundAt + myMatchLen >= (uint) col
1705  && line == selectStart.line() && foundAt == (uint) selectStart.col()
1706  && line == selectEnd.line() && foundAt + myMatchLen == (uint) selectEnd.col())
1707  {
1708  // To avoid getting stuck at one match we skip a match if it is already
1709  // selected (most likely because it has just been found).
1710  if (foundAt > 0)
1711  col = foundAt - 1;
1712  else {
1713  if (--line >= 0)
1714  col = lineLength(line);
1715  }
1716  continue;
1717  }*/
1718 
1719  (*foundAtLine) = line;
1720  (*foundAtCol) = foundAt;
1721  (*matchLen) = myMatchLen;
1722  return true;
1723  }
1724 
1725  if (line >= 1)
1726  col = lineLength(line-1);
1727 
1728  line--;
1729  }
1730  }
1731 
1732  return false;
1733 }
1734 
1735 bool KateDocument::searchText (unsigned int startLine, unsigned int startCol, const TQRegExp &regexp, unsigned int *foundAtLine, unsigned int *foundAtCol, unsigned int *matchLen, bool backwards)
1736 {
1737  kdDebug(13020)<<"KateDocument::searchText( "<<startLine<<", "<<startCol<<", "<<TQString(regexp.pattern())<<", "<<backwards<<" )"<<endl;
1738  if (regexp.isEmpty() || !regexp.isValid())
1739  return false;
1740 
1741  int line = startLine;
1742  int col = startCol;
1743 
1744  if (!backwards)
1745  {
1746  int searchEnd = lastLine();
1747 
1748  while (line <= searchEnd)
1749  {
1750  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1751 
1752  if (!textLine)
1753  return false;
1754 
1755  uint foundAt, myMatchLen;
1756  bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, false);
1757 
1758  if (found)
1759  {
1760  // A special case which can only occur when searching with a regular expression consisting
1761  // only of a lookahead (e.g. ^(?=\{) for a function beginning without selecting '{').
1762  if (myMatchLen == 0 && (uint) line == startLine && foundAt == (uint) col)
1763  {
1764  if (col < lineLength(line))
1765  col++;
1766  else {
1767  line++;
1768  col = 0;
1769  }
1770  continue;
1771  }
1772 
1773  (*foundAtLine) = line;
1774  (*foundAtCol) = foundAt;
1775  (*matchLen) = myMatchLen;
1776  return true;
1777  }
1778 
1779  col = 0;
1780  line++;
1781  }
1782  }
1783  else
1784  {
1785  // backward search
1786  int searchEnd = 0;
1787 
1788  while (line >= searchEnd)
1789  {
1790  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
1791 
1792  if (!textLine)
1793  return false;
1794 
1795  uint foundAt, myMatchLen;
1796  bool found = textLine->searchText (col, regexp, &foundAt, &myMatchLen, true);
1797 
1798  if (found)
1799  {
1800  /*if ((uint) line == startLine && foundAt + myMatchLen >= (uint) col
1801  && line == selectStart.line() && foundAt == (uint) selectStart.col()
1802  && line == selectEnd.line() && foundAt + myMatchLen == (uint) selectEnd.col())
1803  {
1804  // To avoid getting stuck at one match we skip a match if it is already
1805  // selected (most likely because it has just been found).
1806  if (foundAt > 0)
1807  col = foundAt - 1;
1808  else {
1809  if (--line >= 0)
1810  col = lineLength(line);
1811  }
1812  continue;
1813  }*/
1814 
1815  (*foundAtLine) = line;
1816  (*foundAtCol) = foundAt;
1817  (*matchLen) = myMatchLen;
1818  return true;
1819  }
1820 
1821  if (line >= 1)
1822  col = lineLength(line-1);
1823 
1824  line--;
1825  }
1826  }
1827 
1828  return false;
1829 }
1830 //END
1831 
1832 //BEGIN KTextEditor::HighlightingInterface stuff
1833 
1834 uint KateDocument::hlMode ()
1835 {
1836  return KateHlManager::self()->findHl(highlight());
1837 }
1838 
1839 bool KateDocument::setHlMode (uint mode)
1840 {
1841  m_buffer->setHighlight (mode);
1842 
1843  if (true)
1844  {
1845  setDontChangeHlOnSave();
1846  return true;
1847  }
1848 
1849  return false;
1850 }
1851 
1852 void KateDocument::bufferHlChanged ()
1853 {
1854  // update all views
1855  makeAttribs(false);
1856 
1857  emit hlChanged();
1858 }
1859 
1860 uint KateDocument::hlModeCount ()
1861 {
1862  return KateHlManager::self()->highlights();
1863 }
1864 
1865 TQString KateDocument::hlModeName (uint mode)
1866 {
1867  return KateHlManager::self()->hlName (mode);
1868 }
1869 
1870 TQString KateDocument::hlModeSectionName (uint mode)
1871 {
1872  return KateHlManager::self()->hlSection (mode);
1873 }
1874 
1875 void KateDocument::setDontChangeHlOnSave()
1876 {
1877  hlSetByUser = true;
1878 }
1879 //END
1880 
1881 //BEGIN KTextEditor::ConfigInterface stuff
1882 void KateDocument::readConfig(TDEConfig *config)
1883 {
1884  config->setGroup("Kate Document Defaults");
1885 
1886  // read max loadable blocks, more blocks will be swapped out
1887  KateBuffer::setMaxLoadedBlocks (config->readNumEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks()));
1888 
1889  KateDocumentConfig::global()->readConfig (config);
1890 
1891  config->setGroup("Kate View Defaults");
1892  KateViewConfig::global()->readConfig (config);
1893 
1894  config->setGroup("Kate Renderer Defaults");
1895  KateRendererConfig::global()->readConfig (config);
1896 }
1897 
1898 void KateDocument::writeConfig(TDEConfig *config)
1899 {
1900  config->setGroup("Kate Document Defaults");
1901 
1902  // write max loadable blocks, more blocks will be swapped out
1903  config->writeEntry("Maximal Loaded Blocks", KateBuffer::maxLoadedBlocks());
1904 
1905  KateDocumentConfig::global()->writeConfig (config);
1906 
1907  config->setGroup("Kate View Defaults");
1908  KateViewConfig::global()->writeConfig (config);
1909 
1910  config->setGroup("Kate Renderer Defaults");
1911  KateRendererConfig::global()->writeConfig (config);
1912 }
1913 
1914 void KateDocument::readConfig()
1915 {
1916  TDEConfig *config = kapp->config();
1917  readConfig (config);
1918 }
1919 
1920 void KateDocument::writeConfig()
1921 {
1922  TDEConfig *config = kapp->config();
1923  writeConfig (config);
1924  config->sync();
1925 }
1926 
1927 void KateDocument::readSessionConfig(TDEConfig *tdeconfig)
1928 {
1929  // restore the url
1930  KURL url (tdeconfig->readEntry("URL"));
1931 
1932  // get the encoding
1933  TQString tmpenc=tdeconfig->readEntry("Encoding");
1934  if (!tmpenc.isEmpty() && (tmpenc != encoding()))
1935  setEncoding(tmpenc);
1936 
1937  // open the file if url valid
1938  if (!url.isEmpty() && url.isValid())
1939  openURL (url);
1940 
1941  // restore the hl stuff
1942  m_buffer->setHighlight(KateHlManager::self()->nameFind(tdeconfig->readEntry("Highlighting")));
1943 
1944  if (hlMode() > 0)
1945  hlSetByUser = true;
1946 
1947  // indent mode
1948  config()->setIndentationMode( (uint)tdeconfig->readNumEntry("Indentation Mode", config()->indentationMode() ) );
1949 
1950  // Restore Bookmarks
1951  TQValueList<int> marks = tdeconfig->readIntListEntry("Bookmarks");
1952  for( uint i = 0; i < marks.count(); i++ )
1953  addMark( marks[i], KateDocument::markType01 );
1954 }
1955 
1956 void KateDocument::writeSessionConfig(TDEConfig *tdeconfig)
1957 {
1958  if ( m_url.isLocalFile() && !TDEGlobal::dirs()->relativeLocation("tmp", m_url.path()).startsWith("/"))
1959  return;
1960  // save url
1961  tdeconfig->writeEntry("URL", m_url.prettyURL() );
1962 
1963  // save encoding
1964  tdeconfig->writeEntry("Encoding",encoding());
1965 
1966  // save hl
1967  tdeconfig->writeEntry("Highlighting", highlight()->name());
1968 
1969  tdeconfig->writeEntry("Indentation Mode", config()->indentationMode() );
1970 
1971  // Save Bookmarks
1972  TQValueList<int> marks;
1973  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks );
1974  it.current() && it.current()->type & KTextEditor::MarkInterface::markType01;
1975  ++it )
1976  marks << it.current()->line;
1977 
1978  tdeconfig->writeEntry( "Bookmarks", marks );
1979 }
1980 
1981 void KateDocument::configDialog()
1982 {
1983  KDialogBase *kd = new KDialogBase ( KDialogBase::IconList,
1984  i18n("Configure"),
1985  KDialogBase::Ok | KDialogBase::Cancel | KDialogBase::Help,
1986  KDialogBase::Ok,
1987  kapp->mainWidget() );
1988 
1989 #ifndef TQ_WS_WIN //TODO: reenable
1990  KWin::setIcons( kd->winId(), kapp->icon(), kapp->miniIcon() );
1991 #endif
1992 
1993  TQPtrList<KTextEditor::ConfigPage> editorPages;
1994 
1995  for (uint i = 0; i < KTextEditor::configInterfaceExtension (this)->configPages (); i++)
1996  {
1997  TQStringList path;
1998  path.clear();
1999  path << KTextEditor::configInterfaceExtension (this)->configPageName (i);
2000  TQVBox *page = kd->addVBoxPage(path, KTextEditor::configInterfaceExtension (this)->configPageFullName (i),
2001  KTextEditor::configInterfaceExtension (this)->configPagePixmap(i, TDEIcon::SizeMedium) );
2002 
2003  editorPages.append (KTextEditor::configInterfaceExtension (this)->configPage(i, page));
2004  }
2005 
2006  if (kd->exec())
2007  {
2008  KateDocumentConfig::global()->configStart ();
2009  KateViewConfig::global()->configStart ();
2010  KateRendererConfig::global()->configStart ();
2011 
2012  for (uint i=0; i<editorPages.count(); i++)
2013  {
2014  editorPages.at(i)->apply();
2015  }
2016 
2017  KateDocumentConfig::global()->configEnd ();
2018  KateViewConfig::global()->configEnd ();
2019  KateRendererConfig::global()->configEnd ();
2020 
2021  writeConfig ();
2022  }
2023 
2024  delete kd;
2025 }
2026 
2027 uint KateDocument::mark( uint line )
2028 {
2029  if( !m_marks[line] )
2030  return 0;
2031  return m_marks[line]->type;
2032 }
2033 
2034 void KateDocument::setMark( uint line, uint markType )
2035 {
2036  clearMark( line );
2037  addMark( line, markType );
2038 }
2039 
2040 void KateDocument::clearMark( uint line )
2041 {
2042  if( line > lastLine() )
2043  return;
2044 
2045  if( !m_marks[line] )
2046  return;
2047 
2048  KTextEditor::Mark* mark = m_marks.take( line );
2049  emit markChanged( *mark, MarkRemoved );
2050  emit marksChanged();
2051  delete mark;
2052  tagLines( line, line );
2053  repaintViews(true);
2054 }
2055 
2056 void KateDocument::addMark( uint line, uint markType )
2057 {
2058  if( line > lastLine())
2059  return;
2060 
2061  if( markType == 0 )
2062  return;
2063 
2064  if( m_marks[line] ) {
2065  KTextEditor::Mark* mark = m_marks[line];
2066 
2067  // Remove bits already set
2068  markType &= ~mark->type;
2069 
2070  if( markType == 0 )
2071  return;
2072 
2073  // Add bits
2074  mark->type |= markType;
2075  } else {
2076  KTextEditor::Mark *mark = new KTextEditor::Mark;
2077  mark->line = line;
2078  mark->type = markType;
2079  m_marks.insert( line, mark );
2080  }
2081 
2082  // Emit with a mark having only the types added.
2083  KTextEditor::Mark temp;
2084  temp.line = line;
2085  temp.type = markType;
2086  emit markChanged( temp, MarkAdded );
2087 
2088  emit marksChanged();
2089  tagLines( line, line );
2090  repaintViews(true);
2091 }
2092 
2093 void KateDocument::removeMark( uint line, uint markType )
2094 {
2095  if( line > lastLine() )
2096  return;
2097  if( !m_marks[line] )
2098  return;
2099 
2100  KTextEditor::Mark* mark = m_marks[line];
2101 
2102  // Remove bits not set
2103  markType &= mark->type;
2104 
2105  if( markType == 0 )
2106  return;
2107 
2108  // Subtract bits
2109  mark->type &= ~markType;
2110 
2111  // Emit with a mark having only the types removed.
2112  KTextEditor::Mark temp;
2113  temp.line = line;
2114  temp.type = markType;
2115  emit markChanged( temp, MarkRemoved );
2116 
2117  if( mark->type == 0 )
2118  m_marks.remove( line );
2119 
2120  emit marksChanged();
2121  tagLines( line, line );
2122  repaintViews(true);
2123 }
2124 
2125 TQPtrList<KTextEditor::Mark> KateDocument::marks()
2126 {
2127  TQPtrList<KTextEditor::Mark> list;
2128 
2129  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks );
2130  it.current(); ++it ) {
2131  list.append( it.current() );
2132  }
2133 
2134  return list;
2135 }
2136 
2137 void KateDocument::clearMarks()
2138 {
2139  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks );
2140  it.current(); ++it ) {
2141  KTextEditor::Mark* mark = it.current();
2142  emit markChanged( *mark, MarkRemoved );
2143  tagLines( mark->line, mark->line );
2144  }
2145 
2146  m_marks.clear();
2147 
2148  emit marksChanged();
2149  repaintViews(true);
2150 }
2151 
2152 void KateDocument::setPixmap( MarkInterface::MarkTypes type, const TQPixmap& pixmap )
2153 {
2154  m_markPixmaps.replace( type, new TQPixmap( pixmap ) );
2155 }
2156 
2157 void KateDocument::setDescription( MarkInterface::MarkTypes type, const TQString& description )
2158 {
2159  m_markDescriptions.replace( type, new TQString( description ) );
2160 }
2161 
2162 TQPixmap *KateDocument::markPixmap( MarkInterface::MarkTypes type )
2163 {
2164  return m_markPixmaps[type];
2165 }
2166 
2167 TQColor KateDocument::markColor( MarkInterface::MarkTypes type )
2168 {
2169  uint reserved = (0x1 << KTextEditor::MarkInterface::reservedMarkersCount()) - 1;
2170  if ((uint)type >= (uint)markType01 && (uint)type <= reserved) {
2171  return KateRendererConfig::global()->lineMarkerColor(type);
2172  } else {
2173  return TQColor();
2174  }
2175 }
2176 
2177 TQString KateDocument::markDescription( MarkInterface::MarkTypes type )
2178 {
2179  if( m_markDescriptions[type] )
2180  return *m_markDescriptions[type];
2181  return TQString::null;
2182 }
2183 
2184 void KateDocument::setMarksUserChangable( uint markMask )
2185 {
2186  m_editableMarks = markMask;
2187 }
2188 
2189 uint KateDocument::editableMarks()
2190 {
2191  return m_editableMarks;
2192 }
2193 //END
2194 
2195 //BEGIN KTextEditor::PrintInterface stuff
2196 bool KateDocument::printDialog ()
2197 {
2198  return KatePrinter::print (this);
2199 }
2200 
2201 bool KateDocument::print ()
2202 {
2203  return KatePrinter::print (this);
2204 }
2205 //END
2206 
2207 //BEGIN KTextEditor::DocumentInfoInterface (### unfinished)
2208 TQString KateDocument::mimeType()
2209 {
2210  KMimeType::Ptr result = KMimeType::defaultMimeTypePtr();
2211 
2212  // if the document has a URL, try KMimeType::findByURL
2213  if ( ! m_url.isEmpty() )
2214  result = KMimeType::findByURL( m_url );
2215 
2216  else if ( m_url.isEmpty() || ! m_url.isLocalFile() )
2217  result = mimeTypeForContent();
2218 
2219  return result->name();
2220 }
2221 
2222 // TODO implement this -- how to calculate?
2223 long KateDocument::fileSize()
2224 {
2225  return 0;
2226 }
2227 
2228 // TODO implement this
2229 TQString KateDocument::niceFileSize()
2230 {
2231  return "UNKNOWN";
2232 }
2233 
2234 KMimeType::Ptr KateDocument::mimeTypeForContent()
2235 {
2236  TQByteArray buf (1024);
2237  uint bufpos = 0;
2238 
2239  for (uint i=0; i < numLines(); i++)
2240  {
2241  TQString line = textLine( i );
2242  uint len = line.length() + 1;
2243 
2244  if (bufpos + len > 1024)
2245  len = 1024 - bufpos;
2246 
2247  memcpy(&buf[bufpos], (line + "\n").latin1(), len);
2248 
2249  bufpos += len;
2250 
2251  if (bufpos >= 1024)
2252  break;
2253  }
2254  buf.resize( bufpos );
2255 
2256  int accuracy = 0;
2257  return KMimeType::findByContent( buf, &accuracy );
2258 }
2259 //END KTextEditor::DocumentInfoInterface
2260 
2261 
2262 //BEGIN KParts::ReadWrite stuff
2263 
2264 bool KateDocument::openURL( const KURL &url )
2265 {
2266 // kdDebug(13020)<<"KateDocument::openURL( "<<url.prettyURL()<<")"<<endl;
2267  // no valid URL
2268  if ( !url.isValid() )
2269  return false;
2270 
2271  // could not close old one
2272  if ( !closeURL() )
2273  return false;
2274 
2275  // set my url
2276  m_url = url;
2277 
2278  if ( m_url.isLocalFile() )
2279  {
2280  // local mode, just like in kpart
2281 
2282  m_file = m_url.path();
2283 
2284  emit started( 0 );
2285 
2286  if (openFile())
2287  {
2288  emit completed();
2289  emit setWindowCaption( m_url.prettyURL() );
2290 
2291  return true;
2292  }
2293 
2294  return false;
2295  }
2296  else
2297  {
2298  // remote mode
2299 
2300  m_bTemp = true;
2301 
2302  m_tempFile = new KTempFile ();
2303  m_file = m_tempFile->name();
2304 
2305  m_job = TDEIO::get ( url, false, isProgressInfoEnabled() );
2306 
2307  // connect to slots
2308  connect( m_job, TQ_SIGNAL( data( TDEIO::Job*, const TQByteArray& ) ),
2309  TQ_SLOT( slotDataKate( TDEIO::Job*, const TQByteArray& ) ) );
2310 
2311  connect( m_job, TQ_SIGNAL( result( TDEIO::Job* ) ),
2312  TQ_SLOT( slotFinishedKate( TDEIO::Job* ) ) );
2313 
2314  TQWidget *w = widget ();
2315  if (!w && !m_views.isEmpty ())
2316  w = m_views.first();
2317 
2318  if (w)
2319  m_job->setWindow (w->topLevelWidget());
2320 
2321  emit started( m_job );
2322 
2323  return true;
2324  }
2325 }
2326 
2327 void KateDocument::slotDataKate ( TDEIO::Job *, const TQByteArray &data )
2328 {
2329 // kdDebug(13020) << "KateDocument::slotData" << endl;
2330 
2331  if (!m_tempFile || !m_tempFile->file())
2332  return;
2333 
2334  m_tempFile->file()->writeBlock (data);
2335 }
2336 
2337 void KateDocument::slotFinishedKate ( TDEIO::Job * job )
2338 {
2339 // kdDebug(13020) << "KateDocument::slotJobFinished" << endl;
2340 
2341  if (!m_tempFile)
2342  return;
2343 
2344  delete m_tempFile;
2345  m_tempFile = 0;
2346  m_job = 0;
2347 
2348  if (job->error())
2349  emit canceled( job->errorString() );
2350  else
2351  {
2352  if ( openFile(job) )
2353  emit setWindowCaption( m_url.prettyURL() );
2354  emit completed();
2355  }
2356 }
2357 
2358 void KateDocument::abortLoadKate()
2359 {
2360  if ( m_job )
2361  {
2362  kdDebug(13020) << "Aborting job " << m_job << endl;
2363  m_job->kill();
2364  m_job = 0;
2365  }
2366 
2367  delete m_tempFile;
2368  m_tempFile = 0;
2369 }
2370 
2371 bool KateDocument::openFile()
2372 {
2373  return openFile (0);
2374 }
2375 
2376 bool KateDocument::openFile(TDEIO::Job * job)
2377 {
2378  m_loading = true;
2379  // add new m_file to dirwatch
2380  activateDirWatch ();
2381 
2382  //
2383  // use metadata
2384  //
2385  if (job)
2386  {
2387  TQString metaDataCharset = job->queryMetaData("charset");
2388 
2389  // only overwrite config if nothing set
2390  if (!metaDataCharset.isEmpty () && (!m_config->isSetEncoding() || m_config->encoding().isEmpty()))
2391  setEncoding (metaDataCharset);
2392  }
2393 
2394  //
2395  // service type magic to get encoding right
2396  //
2397  TQString serviceType = m_extension->urlArgs().serviceType.simplifyWhiteSpace();
2398  int pos = serviceType.find(';');
2399  if (pos != -1)
2400  setEncoding (serviceType.mid(pos+1));
2401 
2402  // if the encoding is set here - on the command line/from the dialog/from TDEIO
2403  // we prevent file type and document variables from changing it
2404  bool encodingSticky = m_encodingSticky;
2405  m_encodingSticky = m_config->isSetEncoding();
2406 
2407  // Try getting the filetype here, so that variables does not have to be reset.
2408  int fileTypeFound = KateFactory::self()->fileTypeManager()->fileType (this);
2409  if ( fileTypeFound > -1 )
2410  updateFileType( fileTypeFound );
2411 
2412  // read dir config (if possible and wanted)
2413  if (!m_reloading)
2414  readDirConfig ();
2415 
2416  // do we have success ?
2417  bool success = m_buffer->openFile (m_file);
2418  //
2419  // yeah, success
2420  //
2421  m_loading = false; // done reading file.
2422  if (success)
2423  {
2424  /*if (highlight() && !m_url.isLocalFile()) {
2425  // The buffer's highlighting gets nuked by KateBuffer::clear()
2426  m_buffer->setHighlight(m_highlight);
2427  }*/
2428 
2429  // update our hl type if needed
2430  if (!hlSetByUser)
2431  {
2432  int hl (KateHlManager::self()->detectHighlighting (this));
2433 
2434  if (hl >= 0)
2435  m_buffer->setHighlight(hl);
2436  }
2437 
2438  // update file type if we haven't allready done so.
2439  if ( fileTypeFound < 0 )
2440  updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
2441 
2442  // read vars
2443  readVariables();
2444 
2445  // update the md5 digest
2446  createDigest( m_digest );
2447  }
2448 
2449  //
2450  // update views
2451  //
2452  for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
2453  {
2454  view->updateView(true);
2455  }
2456 
2457  //
2458  // emit the signal we need for example for kate app
2459  //
2460  emit fileNameChanged ();
2461 
2462  //
2463  // set doc name, dummy value as arg, don't need it
2464  //
2465  setDocName (TQString::null);
2466 
2467  //
2468  // to houston, we are not modified
2469  //
2470  if (m_modOnHd)
2471  {
2472  m_modOnHd = false;
2473  m_modOnHdReason = 0;
2474  emit modifiedOnDisc (this, m_modOnHd, 0);
2475  }
2476 
2477  //
2478  // display errors
2479  //
2480  if (s_openErrorDialogsActivated)
2481  {
2482  if (!success && m_buffer->loadingBorked())
2483  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()));
2484  else if (!success)
2485  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()));
2486  }
2487 
2488  // warn -> opened binary file!!!!!!!
2489  if (m_buffer->binary())
2490  {
2491  // this file can't be saved again without killing it
2492  setReadWrite( false );
2493 
2494  KMessageBox::information (widget()
2495  , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
2496  , i18n ("Binary File Opened")
2497  , "Binary File Opened Warning");
2498  }
2499 
2500  m_encodingSticky = encodingSticky;
2501 
2502  //
2503  // return the success
2504  //
2505  return success;
2506 }
2507 
2508 bool KateDocument::save()
2509 {
2510  bool l ( url().isLocalFile() );
2511 
2512  if ( ( l && config()->backupFlags() & KateDocumentConfig::LocalFiles )
2513  || ( ! l && config()->backupFlags() & KateDocumentConfig::RemoteFiles ) )
2514  {
2515  KURL u( url() );
2516  u.setFileName( config()->backupPrefix() + url().fileName() + config()->backupSuffix() );
2517 
2518  kdDebug () << "backup src file name: " << url() << endl;
2519  kdDebug () << "backup dst file name: " << u << endl;
2520 
2521  // get the right permissions, start with safe default
2522  mode_t perms = 0600;
2523  TDEIO::UDSEntry fentry;
2524  if (TDEIO::NetAccess::stat (url(), fentry, kapp->mainWidget()))
2525  {
2526  kdDebug () << "stating succesfull: " << url() << endl;
2527  KFileItem item (fentry, url());
2528  perms = item.permissions();
2529  }
2530 
2531  // first del existing file if any, than copy over the file we have
2532  // failure if a: the existing file could not be deleted, b: the file could not be copied
2533  if ( (!TDEIO::NetAccess::exists( u, false, kapp->mainWidget() ) || TDEIO::NetAccess::del( u, kapp->mainWidget() ))
2534  && TDEIO::NetAccess::file_copy( url(), u, perms, true, false, kapp->mainWidget() ) )
2535  {
2536  kdDebug(13020)<<"backing up successfull ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
2537  }
2538  else
2539  {
2540  kdDebug(13020)<<"backing up failed ("<<url().prettyURL()<<" -> "<<u.prettyURL()<<")"<<endl;
2541  // FIXME: notify user for real ;)
2542  }
2543  }
2544 
2545  return KParts::ReadWritePart::save();
2546 }
2547 
2548 bool KateDocument::saveFile()
2549 {
2550  //
2551  // we really want to save this file ?
2552  //
2553  if (m_buffer->loadingBorked() && (KMessageBox::warningContinueCancel(widget(),
2554  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))
2555  return false;
2556 
2557  //
2558  // warn -> try to save binary file!!!!!!!
2559  //
2560  if (m_buffer->binary() && (KMessageBox::warningContinueCancel (widget()
2561  , i18n ("The file %1 is a binary, saving it will result in a corrupt file.").arg(m_url.url())
2562  , i18n ("Trying to Save Binary File")
2563  , i18n("Save Nevertheless"), "Binary File Save Warning") != KMessageBox::Continue))
2564  return false;
2565 
2566  if ( !url().isEmpty() )
2567  {
2568  if (s_fileChangedDialogsActivated && m_modOnHd)
2569  {
2570  TQString str = reasonedMOHString() + "\n\n";
2571 
2572  if (!isModified())
2573  {
2574  if (KMessageBox::warningContinueCancel(0,
2575  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)
2576  return false;
2577  }
2578  else
2579  {
2580  if (KMessageBox::warningContinueCancel(0,
2581  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)
2582  return false;
2583  }
2584  }
2585  }
2586 
2587  //
2588  // can we encode it if we want to save it ?
2589  //
2590  if (!m_buffer->canEncode ()
2591  && (KMessageBox::warningContinueCancel(0,
2592  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))
2593  {
2594  return false;
2595  }
2596 
2597  // remove file from dirwatch
2598  deactivateDirWatch ();
2599 
2600  //
2601  // try to save
2602  //
2603  bool success = m_buffer->saveFile (m_file);
2604 
2605  // update the md5 digest
2606  createDigest( m_digest );
2607 
2608  // add m_file again to dirwatch
2609  activateDirWatch ();
2610 
2611  //
2612  // hurray, we had success, do stuff we need
2613  //
2614  if (success)
2615  {
2616  // update our hl type if needed
2617  if (!hlSetByUser)
2618  {
2619  int hl (KateHlManager::self()->detectHighlighting (this));
2620 
2621  if (hl >= 0)
2622  m_buffer->setHighlight(hl);
2623  }
2624 
2625  // read our vars
2626  readVariables();
2627  }
2628 
2629  //
2630  // we are not modified
2631  //
2632  if (success && m_modOnHd)
2633  {
2634  m_modOnHd = false;
2635  m_modOnHdReason = 0;
2636  emit modifiedOnDisc (this, m_modOnHd, 0);
2637  }
2638 
2639  //
2640  // display errors
2641  //
2642  if (!success)
2643  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()));
2644 
2645  //
2646  // return success
2647  //
2648  return success;
2649 }
2650 
2651 bool KateDocument::saveAs( const KURL &u )
2652 {
2653  TQString oldDir = url().directory();
2654 
2655  if ( KParts::ReadWritePart::saveAs( u ) )
2656  {
2657  // null means base on filename
2658  setDocName( TQString::null );
2659 
2660  if ( u.directory() != oldDir )
2661  readDirConfig();
2662 
2663  emit fileNameChanged();
2664  emit nameChanged((Kate::Document *) this);
2665 
2666  return true;
2667  }
2668 
2669  return false;
2670 }
2671 
2672 void KateDocument::readDirConfig ()
2673 {
2674  int depth = config()->searchDirConfigDepth ();
2675 
2676  if (m_url.isLocalFile() && (depth > -1))
2677  {
2678  TQString currentDir = TQFileInfo (m_file).dirPath();
2679 
2680  // only search as deep as specified or not at all ;)
2681  while (depth > -1)
2682  {
2683  kdDebug (13020) << "search for config file in path: " << currentDir << endl;
2684 
2685  // try to open config file in this dir
2686  TQFile f (currentDir + "/.kateconfig");
2687 
2688  if (f.open (IO_ReadOnly))
2689  {
2690  TQTextStream stream (&f);
2691 
2692  uint linesRead = 0;
2693  TQString line = stream.readLine();
2694  while ((linesRead < 32) && !line.isNull())
2695  {
2696  readVariableLine( line );
2697 
2698  line = stream.readLine();
2699 
2700  linesRead++;
2701  }
2702 
2703  break;
2704  }
2705 
2706  TQString newDir = TQFileInfo (currentDir).dirPath();
2707 
2708  // bail out on looping (for example reached /)
2709  if (currentDir == newDir)
2710  break;
2711 
2712  currentDir = newDir;
2713  --depth;
2714  }
2715  }
2716 }
2717 
2718 void KateDocument::activateDirWatch ()
2719 {
2720  // same file as we are monitoring, return
2721  if (m_file == m_dirWatchFile)
2722  return;
2723 
2724  // remove the old watched file
2725  deactivateDirWatch ();
2726 
2727  // add new file if needed
2728  if (m_url.isLocalFile() && !m_file.isEmpty())
2729  {
2730  KateFactory::self()->dirWatch ()->addFile (m_file);
2731  m_dirWatchFile = m_file;
2732  }
2733 }
2734 
2735 void KateDocument::deactivateDirWatch ()
2736 {
2737  if (!m_dirWatchFile.isEmpty())
2738  KateFactory::self()->dirWatch ()->removeFile (m_dirWatchFile);
2739 
2740  m_dirWatchFile = TQString::null;
2741 }
2742 
2743 bool KateDocument::closeURL()
2744 {
2745  abortLoadKate();
2746 
2747  //
2748  // file mod on hd
2749  //
2750  if ( !m_reloading && !url().isEmpty() )
2751  {
2752  if (s_fileChangedDialogsActivated && m_modOnHd)
2753  {
2754  if (!(KMessageBox::warningContinueCancel(
2755  widget(),
2756  reasonedMOHString() + "\n\n" + i18n("Do you really want to continue to close this file? Data loss may occur."),
2757  i18n("Possible Data Loss"), i18n("Close Nevertheless"),
2758  TQString("kate_close_modonhd_%1").arg( m_modOnHdReason ) ) == KMessageBox::Continue))
2759  return false;
2760  }
2761  }
2762 
2763  //
2764  // first call the normal tdeparts implementation
2765  //
2766  if (!KParts::ReadWritePart::closeURL ())
2767  return false;
2768 
2769  // remove file from dirwatch
2770  deactivateDirWatch ();
2771 
2772  //
2773  // empty url + filename
2774  //
2775  m_url = KURL ();
2776  m_file = TQString::null;
2777 
2778  // we are not modified
2779  if (m_modOnHd)
2780  {
2781  m_modOnHd = false;
2782  m_modOnHdReason = 0;
2783  emit modifiedOnDisc (this, m_modOnHd, 0);
2784  }
2785 
2786  // clear the buffer
2787  m_buffer->clear();
2788 
2789  // remove all marks
2790  clearMarks ();
2791 
2792  // clear undo/redo history
2793  clearUndo();
2794  clearRedo();
2795 
2796  // no, we are no longer modified
2797  setModified(false);
2798 
2799  // we have no longer any hl
2800  m_buffer->setHighlight(0);
2801 
2802  // update all our views
2803  for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
2804  {
2805  // Explicitly call the internal version because we don't want this to look like
2806  // an external request (and thus have the view not TQWidget::scroll()ed.
2807  view->setCursorPositionInternal(0, 0, 1, false);
2808  view->clearSelection();
2809  view->updateView(true);
2810  }
2811 
2812  // uh, filename changed
2813  emit fileNameChanged ();
2814 
2815  // update doc name
2816  setDocName (TQString::null);
2817 
2818  // success
2819  return true;
2820 }
2821 
2822 void KateDocument::setReadWrite( bool rw )
2823 {
2824  if (isReadWrite() != rw)
2825  {
2826  KParts::ReadWritePart::setReadWrite (rw);
2827 
2828  for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
2829  {
2830  view->slotUpdate();
2831  view->slotReadWriteChanged ();
2832  }
2833  }
2834 }
2835 
2836 void KateDocument::setModified(bool m) {
2837 
2838  if (isModified() != m) {
2839  KParts::ReadWritePart::setModified (m);
2840 
2841  for( KateView* view = m_views.first(); view != 0L; view = m_views.next() )
2842  {
2843  view->slotUpdate();
2844  }
2845 
2846  emit modifiedChanged ();
2847  emit modStateChanged ((Kate::Document *)this);
2848  }
2849  if ( m == false )
2850  {
2851  if ( ! undoItems.isEmpty() )
2852  {
2853  lastUndoGroupWhenSaved = undoItems.last();
2854  }
2855 
2856  if ( ! redoItems.isEmpty() )
2857  {
2858  lastRedoGroupWhenSaved = redoItems.last();
2859  }
2860 
2861  docWasSavedWhenUndoWasEmpty = undoItems.isEmpty();
2862  docWasSavedWhenRedoWasEmpty = redoItems.isEmpty();
2863  }
2864 }
2865 //END
2866 
2867 //BEGIN Kate specific stuff ;)
2868 
2869 void KateDocument::makeAttribs(bool needInvalidate)
2870 {
2871  for (uint z = 0; z < m_views.count(); z++)
2872  m_views.at(z)->renderer()->updateAttributes ();
2873 
2874  if (needInvalidate)
2875  m_buffer->invalidateHighlighting();
2876 
2877  tagAll ();
2878 }
2879 
2880 // the attributes of a hl have changed, update
2881 void KateDocument::internalHlChanged()
2882 {
2883  makeAttribs();
2884 }
2885 
2886 void KateDocument::addView(KTextEditor::View *view) {
2887  if (!view)
2888  return;
2889 
2890  m_views.append( (KateView *) view );
2891  m_textEditViews.append( view );
2892 
2893  // apply the view & renderer vars from the file type
2894  const KateFileType *t = 0;
2895  if ((m_fileType > -1) && (t = KateFactory::self()->fileTypeManager()->fileType(m_fileType)))
2896  readVariableLine (t->varLine, true);
2897 
2898  // apply the view & renderer vars from the file
2899  readVariables (true);
2900 
2901  m_activeView = (KateView *) view;
2902 }
2903 
2904 void KateDocument::removeView(KTextEditor::View *view) {
2905  if (!view)
2906  return;
2907 
2908  if (m_activeView == view)
2909  m_activeView = 0L;
2910 
2911  m_views.removeRef( (KateView *) view );
2912  m_textEditViews.removeRef( view );
2913 }
2914 
2915 void KateDocument::addSuperCursor(KateSuperCursor *cursor, bool privateC) {
2916  if (!cursor)
2917  return;
2918 
2919  m_superCursors.append( cursor );
2920 
2921  if (!privateC)
2922  myCursors.append( cursor );
2923 }
2924 
2925 void KateDocument::removeSuperCursor(KateSuperCursor *cursor, bool privateC) {
2926  if (!cursor)
2927  return;
2928 
2929  if (!privateC)
2930  myCursors.removeRef( cursor );
2931 
2932  m_superCursors.removeRef( cursor );
2933 }
2934 
2935 bool KateDocument::ownedView(KateView *view) {
2936  // do we own the given view?
2937  return (m_views.containsRef(view) > 0);
2938 }
2939 
2940 bool KateDocument::isLastView(int numViews) {
2941  return ((int) m_views.count() == numViews);
2942 }
2943 
2944 uint KateDocument::currentColumn( const KateTextCursor& cursor )
2945 {
2946  KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
2947 
2948  if (textLine)
2949  return textLine->cursorX(cursor.col(), config()->tabWidth());
2950  else
2951  return 0;
2952 }
2953 
2954 bool KateDocument::typeChars ( KateView *view, const TQString &chars )
2955 {
2956  KateTextLine::Ptr textLine = m_buffer->plainLine(view->cursorLine ());
2957 
2958  if (!textLine)
2959  return false;
2960 
2961  bool bracketInserted = false;
2962  TQString buf;
2963  TQChar c;
2964 
2965  for( uint z = 0; z < chars.length(); z++ )
2966  {
2967  TQChar ch = c = chars[z];
2968  if (ch.isPrint() || ch == '\t')
2969  {
2970  buf.append (ch);
2971 
2972  if (!bracketInserted && (config()->configFlags() & KateDocument::cfAutoBrackets))
2973  {
2974  TQChar end_ch;
2975  bool complete = true;
2976  TQChar prevChar = textLine->getChar(view->cursorColumnReal()-1);
2977  TQChar nextChar = textLine->getChar(view->cursorColumnReal());
2978  switch(ch) {
2979  case '(': end_ch = ')'; break;
2980  case '[': end_ch = ']'; break;
2981  case '{': end_ch = '}'; break;
2982  case '\'':end_ch = '\'';break;
2983  case '"': end_ch = '"'; break;
2984  default: complete = false;
2985  }
2986  if (complete)
2987  {
2988  if (view->hasSelection())
2989  { // there is a selection, enclose the selection
2990  buf.append (view->selection());
2991  buf.append (end_ch);
2992  bracketInserted = true;
2993  }
2994  else
2995  { // no selection, check whether we should better refuse to complete
2996  if ( ( (ch == '\'' || ch == '"') &&
2997  (prevChar.isLetterOrNumber() || prevChar == ch) )
2998  || nextChar.isLetterOrNumber()
2999  || (nextChar == end_ch && prevChar != ch) )
3000  {
3001  kdDebug(13020) << "AutoBracket refused before: " << nextChar << "\n";
3002  }
3003  else
3004  {
3005  buf.append (end_ch);
3006  bracketInserted = true;
3007  }
3008  }
3009  }
3010  }
3011  }
3012  }
3013 
3014  if (buf.isEmpty())
3015  return false;
3016 
3017  editStart ();
3018 
3019  if (!view->config()->persistentSelection() && view->hasSelection() )
3020  view->removeSelectedText();
3021 
3022  int oldLine = view->cursorLine ();
3023  int oldCol = view->cursorColumnReal ();
3024 
3025 
3026  if (config()->configFlags() & KateDocument::cfOvr)
3027  removeText (view->cursorLine(), view->cursorColumnReal(), view->cursorLine(), kMin( view->cursorColumnReal()+buf.length(), textLine->length() ) );
3028 
3029  insertText (view->cursorLine(), view->cursorColumnReal(), buf);
3030  m_indenter->processChar(c);
3031 
3032  editEnd ();
3033 
3034  if (bracketInserted)
3035  view->setCursorPositionInternal (view->cursorLine(), view->cursorColumnReal()-1);
3036 
3037  emit charactersInteractivelyInserted (oldLine, oldCol, chars);
3038 
3039  return true;
3040 }
3041 
3042 void KateDocument::newLine( KateTextCursor& c, KateViewInternal *v )
3043 {
3044  editStart();
3045 
3046  if( !v->view()->config()->persistentSelection() && v->view()->hasSelection() )
3047  v->view()->removeSelectedText();
3048 
3049  // temporary hack to get the cursor pos right !!!!!!!!!
3050  c = v->getCursor ();
3051 
3052  if (c.line() > (int)lastLine())
3053  c.setLine(lastLine());
3054 
3055  if ( c.line() < 0 )
3056  c.setLine( 0 );
3057 
3058  uint ln = c.line();
3059 
3060  KateTextLine::Ptr textLine = kateTextLine(c.line());
3061 
3062  if (c.col() > (int)textLine->length())
3063  c.setCol(textLine->length());
3064 
3065  if (m_indenter->canProcessNewLine ())
3066  {
3067  int pos = textLine->firstChar();
3068 
3069  // length should do the job better
3070  if (pos < 0)
3071  pos = textLine->length();
3072 
3073  if (c.col() < pos)
3074  c.setCol(pos); // place cursor on first char if before
3075 
3076  editWrapLine (c.line(), c.col());
3077 
3078  KateDocCursor cursor (c.line() + 1, pos, this);
3079  m_indenter->processNewline(cursor, true);
3080 
3081  c.setPos(cursor);
3082  }
3083  else
3084  {
3085  editWrapLine (c.line(), c.col());
3086  c.setPos(c.line() + 1, 0);
3087  }
3088 
3089  removeTrailingSpace( ln );
3090 
3091  editEnd();
3092 }
3093 
3094 void KateDocument::transpose( const KateTextCursor& cursor)
3095 {
3096  KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
3097 
3098  if (!textLine || (textLine->length() < 2))
3099  return;
3100 
3101  uint col = cursor.col();
3102 
3103  if (col > 0)
3104  col--;
3105 
3106  if ((textLine->length() - col) < 2)
3107  return;
3108 
3109  uint line = cursor.line();
3110  TQString s;
3111 
3112  //clever swap code if first character on the line swap right&left
3113  //otherwise left & right
3114  s.append (textLine->getChar(col+1));
3115  s.append (textLine->getChar(col));
3116  //do the swap
3117 
3118  // do it right, never ever manipulate a textline
3119  editStart ();
3120  editRemoveText (line, col, 2);
3121  editInsertText (line, col, s);
3122  editEnd ();
3123 }
3124 
3125 void KateDocument::backspace( KateView *view, const KateTextCursor& c )
3126 {
3127  if ( !view->config()->persistentSelection() && view->hasSelection() ) {
3128  view->removeSelectedText();
3129  return;
3130  }
3131 
3132  uint col = kMax( c.col(), 0 );
3133  uint line = kMax( c.line(), 0 );
3134 
3135  if ((col == 0) && (line == 0))
3136  return;
3137 
3138  KateTextLine::Ptr tl = m_buffer->plainLine(line);
3139  if (!tl)
3140  {
3141  return;
3142  }
3143 
3144  // Make sure to handle surrogate pairs correctly
3145  uint fromCol = col - 1;
3146  TQChar prevChar = tl->getChar(col - 1);
3147  if (prevChar.isLowSurrogate() && tl->getChar(col - 2).isHighSurrogate())
3148  {
3149  fromCol = col - 2;
3150  prevChar = tl->getChar(col - 2);
3151  }
3152 
3153  int complement = 0;
3154  if (col > 0)
3155  {
3156  if (config()->configFlags() & KateDocument::cfAutoBrackets)
3157  {
3158  // if inside empty (), {}, [], '', "" delete both
3159  TQChar nextChar = tl->getChar(col);
3160 
3161  if ( (prevChar == '"' && nextChar == '"') ||
3162  (prevChar == '\'' && nextChar == '\'') ||
3163  (prevChar == '(' && nextChar == ')') ||
3164  (prevChar == '[' && nextChar == ']') ||
3165  (prevChar == '{' && nextChar == '}') )
3166  {
3167  complement = 1;
3168  }
3169  }
3170  if (!(config()->configFlags() & KateDocument::cfBackspaceIndents))
3171  {
3172  // ordinary backspace
3173  removeText(line, fromCol, line, col+complement);
3174  }
3175  else
3176  {
3177  // backspace indents: erase to next indent position
3178  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3179 
3180  // don't forget this check!!!! really!!!!
3181  if (!textLine)
3182  return;
3183 
3184  int colX = textLine->cursorX(col, config()->tabWidth());
3185  int pos = textLine->firstChar();
3186  if (pos > 0)
3187  pos = textLine->cursorX(pos, config()->tabWidth());
3188 
3189  if (pos < 0 || pos >= (int)colX)
3190  {
3191  // only spaces on left side of cursor
3192  indent( view, line, -1);
3193  }
3194  else
3195  removeText(line, col-1, line, col+complement);
3196  }
3197  }
3198  else
3199  {
3200  // col == 0: wrap to previous line
3201  if (line >= 1)
3202  {
3203  KateTextLine::Ptr textLine = m_buffer->plainLine(line-1);
3204 
3205  // don't forget this check!!!! really!!!!
3206  if (!textLine)
3207  return;
3208 
3209  if (config()->wordWrap() && textLine->endingWith(TQString::fromLatin1(" ")))
3210  {
3211  // gg: in hard wordwrap mode, backspace must also eat the trailing space
3212  removeText (line-1, textLine->length()-1, line, 0);
3213  }
3214  else
3215  removeText (line-1, textLine->length(), line, 0);
3216  }
3217  }
3218 
3219  emit backspacePressed();
3220 }
3221 
3222 void KateDocument::del( KateView *view, const KateTextCursor& c )
3223 {
3224  if ( !view->config()->persistentSelection() && view->hasSelection() ) {
3225  view->removeSelectedText();
3226  return;
3227  }
3228 
3229  KateTextLine::Ptr tl = m_buffer->plainLine(c.line());
3230  if (!tl)
3231  {
3232  return;
3233  }
3234  uint lineLen = tl->length();
3235  uint col = (uint)c.col();
3236  if (col < lineLen)
3237  {
3238  // Make sure to handle surrogate pairs correctly
3239  uint toCol = col + 1;
3240  if (tl->getChar(col).isHighSurrogate() && tl->getChar(col + 1).isLowSurrogate())
3241  {
3242  toCol = col + 2;
3243  }
3244 
3245  removeText(c.line(), col, c.line(), toCol);
3246  }
3247  else if ( (uint)c.line() < lastLine() )
3248  {
3249  removeText(c.line(), c.col(), c.line()+1, 0);
3250  }
3251 }
3252 
3253 void KateDocument::paste ( KateView* view )
3254 {
3255  TQString s = TQApplication::clipboard()->text();
3256 
3257  if (s.isEmpty())
3258  return;
3259 
3260  uint lines = s.contains (TQChar ('\n'));
3261 
3262  m_undoDontMerge = true;
3263 
3264  editStart ();
3265 
3266  if (!view->config()->persistentSelection() && view->hasSelection() )
3267  view->removeSelectedText();
3268 
3269  uint line = view->cursorLine ();
3270  uint column = view->cursorColumnReal ();
3271 
3272  insertText ( line, column, s, view->blockSelectionMode() );
3273 
3274  editEnd();
3275 
3276  // move cursor right for block select, as the user is moved right internal
3277  // even in that case, but user expects other behavior in block selection
3278  // mode !
3279  if (view->blockSelectionMode())
3280  view->setCursorPositionInternal (line+lines, column);
3281 
3282  if (m_indenter->canProcessLine()
3283  && config()->configFlags() & KateDocumentConfig::cfIndentPastedText)
3284  {
3285  editStart();
3286 
3287  KateDocCursor begin(line, 0, this);
3288  KateDocCursor end(line + lines, 0, this);
3289 
3290  m_indenter->processSection (begin, end);
3291 
3292  editEnd();
3293  }
3294 
3295  if (!view->blockSelectionMode()) emit charactersSemiInteractivelyInserted (line, column, s);
3296  m_undoDontMerge = true;
3297 }
3298 
3299 void KateDocument::insertIndentChars ( KateView *view )
3300 {
3301  editStart ();
3302 
3303  TQString s;
3304  if (config()->configFlags() & KateDocument::cfSpaceIndent)
3305  {
3306  int width = config()->indentationWidth();
3307  s.fill (' ', width - (view->cursorColumnReal() % width));
3308  }
3309  else
3310  s.append ('\t');
3311 
3312  insertText (view->cursorLine(), view->cursorColumnReal(), s);
3313 
3314  editEnd ();
3315 }
3316 
3317 void KateDocument::indent ( KateView *v, uint line, int change)
3318 {
3319  editStart ();
3320 
3321  if (!hasSelection())
3322  {
3323  // single line
3324  optimizeLeadingSpace(line, config()->configFlags(), change);
3325  }
3326  else
3327  {
3328  int sl = v->selStartLine();
3329  int el = v->selEndLine();
3330  int ec = v->selEndCol();
3331 
3332  if ((ec == 0) && ((el-1) >= 0))
3333  {
3334  el--; /* */
3335  }
3336 
3337  if (config()->configFlags() & KateDocument::cfKeepIndentProfile && change < 0) {
3338  // unindent so that the existing indent profile doesn't get screwed
3339  // if any line we may unindent is already full left, don't do anything
3340  int adjustedChange = -change;
3341 
3342  for (line = sl; (int) line <= el && adjustedChange > 0; line++) {
3343  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3344  int firstChar = textLine->firstChar();
3345  if (firstChar >= 0 && (v->lineSelected(line) || v->lineHasSelected(line))) {
3346  int maxUnindent = textLine->cursorX(firstChar, config()->tabWidth()) / config()->indentationWidth();
3347  if (maxUnindent < adjustedChange)
3348  adjustedChange = maxUnindent;
3349  }
3350  }
3351 
3352  change = -adjustedChange;
3353  }
3354 
3355  const bool rts = config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn;
3356  for (line = sl; (int) line <= el; line++) {
3357  if ((v->lineSelected(line) || v->lineHasSelected(line))
3358  && (!rts || lineLength(line) > 0)) {
3359  optimizeLeadingSpace(line, config()->configFlags(), change);
3360  }
3361  }
3362  }
3363 
3364  editEnd ();
3365 }
3366 
3367 void KateDocument::align(KateView *view, uint line)
3368 {
3369  if (m_indenter->canProcessLine())
3370  {
3371  editStart ();
3372 
3373  if (!view->hasSelection())
3374  {
3375  KateDocCursor curLine(line, 0, this);
3376  m_indenter->processLine (curLine);
3377  editEnd ();
3378  activeView()->setCursorPosition (line, curLine.col());
3379  }
3380  else
3381  {
3382  m_indenter->processSection (view->selStart(), view->selEnd());
3383  editEnd ();
3384  }
3385  }
3386 }
3387 
3388 /*
3389  Optimize the leading whitespace for a single line.
3390  If change is > 0, it adds indentation units (indentationChars)
3391  if change is == 0, it only optimizes
3392  If change is < 0, it removes indentation units
3393  This will be used to indent, unindent, and optimal-fill a line.
3394  If excess space is removed depends on the flag cfKeepExtraSpaces
3395  which has to be set by the user
3396 */
3397 void KateDocument::optimizeLeadingSpace(uint line, int flags, int change)
3398 {
3399  KateTextLine::Ptr textline = m_buffer->plainLine(line);
3400 
3401  int first_char = textline->firstChar();
3402 
3403  int w = 0;
3404  if (flags & KateDocument::cfSpaceIndent)
3405  w = config()->indentationWidth();
3406  else
3407  w = config()->tabWidth();
3408 
3409  if (first_char < 0)
3410  first_char = textline->length();
3411 
3412  int space = textline->cursorX(first_char, config()->tabWidth()) + change * w;
3413  if (space < 0)
3414  space = 0;
3415 
3416  if (!(flags & KateDocument::cfKeepExtraSpaces))
3417  {
3418  uint extra = space % w;
3419 
3420  space -= extra;
3421  if (extra && change < 0) {
3422  // otherwise it unindents too much (e.g. 12 chars when indentation is 8 chars wide)
3423  space += w;
3424  }
3425  }
3426 
3427  //kdDebug(13020) << "replace With Op: " << line << " " << first_char << " " << space << endl;
3428  replaceWithOptimizedSpace(line, first_char, space, flags);
3429 }
3430 
3431 void KateDocument::replaceWithOptimizedSpace(uint line, uint upto_column, uint space, int flags)
3432 {
3433  uint length;
3434  TQString new_space;
3435 
3436  if (flags & KateDocument::cfSpaceIndent && ! (flags & KateDocumentConfig::cfMixedIndent) ) {
3437  length = space;
3438  new_space.fill(' ', length);
3439  }
3440  else {
3441  length = space / config()->tabWidth();
3442  new_space.fill('\t', length);
3443 
3444  TQString extra_space;
3445  extra_space.fill(' ', space % config()->tabWidth());
3446  length += space % config()->tabWidth();
3447  new_space += extra_space;
3448  }
3449 
3450  KateTextLine::Ptr textline = m_buffer->plainLine(line);
3451  uint change_from;
3452  for (change_from = 0; change_from < upto_column && change_from < length; change_from++) {
3453  if (textline->getChar(change_from) != new_space[change_from])
3454  break;
3455  }
3456 
3457  editStart();
3458 
3459  if (change_from < upto_column)
3460  removeText(line, change_from, line, upto_column);
3461 
3462  if (change_from < length)
3463  insertText(line, change_from, new_space.right(length - change_from));
3464 
3465  editEnd();
3466 }
3467 
3468 /*
3469  Remove a given string at the begining
3470  of the current line.
3471 */
3472 bool KateDocument::removeStringFromBegining(int line, TQString &str)
3473 {
3474  KateTextLine::Ptr textline = m_buffer->plainLine(line);
3475 
3476  int index = 0;
3477  bool there = false;
3478 
3479  if (textline->startingWith(str))
3480  there = true;
3481  else
3482  {
3483  index = textline->firstChar ();
3484 
3485  if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
3486  there = true;
3487  }
3488 
3489  if (there)
3490  {
3491  // Remove some chars
3492  removeText (line, index, line, index+str.length());
3493  }
3494 
3495  return there;
3496 }
3497 
3498 /*
3499  Remove a given string at the end
3500  of the current line.
3501 */
3502 bool KateDocument::removeStringFromEnd(int line, TQString &str)
3503 {
3504  KateTextLine::Ptr textline = m_buffer->plainLine(line);
3505 
3506  int index = 0;
3507  bool there = false;
3508 
3509  if(textline->endingWith(str))
3510  {
3511  index = textline->length() - str.length();
3512  there = true;
3513  }
3514  else
3515  {
3516  index = textline->lastChar ()-str.length()+1;
3517 
3518  if ((index >= 0) && (textline->length() >= (index + str.length())) && (textline->string(index, str.length()) == str))
3519  there = true;
3520  }
3521 
3522  if (there)
3523  {
3524  // Remove some chars
3525  removeText (line, index, line, index+str.length());
3526  }
3527 
3528  return there;
3529 }
3530 
3531 /*
3532  Add to the current line a comment line mark at
3533  the begining.
3534 */
3535 void KateDocument::addStartLineCommentToSingleLine( int line, int attrib )
3536 {
3537  if (highlight()->getCommentSingleLinePosition(attrib)==KateHighlighting::CSLPosColumn0)
3538  {
3539  TQString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
3540  insertText (line, 0, commentLineMark);
3541  }
3542  else
3543  {
3544  TQString commentLineMark=highlight()->getCommentSingleLineStart(attrib);
3545  KateTextLine::Ptr l = m_buffer->line(line);
3546  int pos=l->firstChar();
3547  if (pos >=0)
3548  insertText(line,pos,commentLineMark);
3549  }
3550 }
3551 
3552 /*
3553  Remove from the current line a comment line mark at
3554  the begining if there is one.
3555 */
3556 bool KateDocument::removeStartLineCommentFromSingleLine( int line, int attrib )
3557 {
3558  TQString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
3559  TQString longCommentMark = shortCommentMark + " ";
3560 
3561  editStart();
3562 
3563  // Try to remove the long comment mark first
3564  bool removed = (removeStringFromBegining(line, longCommentMark)
3565  || removeStringFromBegining(line, shortCommentMark));
3566 
3567  editEnd();
3568 
3569  return removed;
3570 }
3571 
3572 /*
3573  Add to the current line a start comment mark at the
3574  begining and a stop comment mark at the end.
3575 */
3576 void KateDocument::addStartStopCommentToSingleLine( int line, int attrib )
3577 {
3578  TQString startCommentMark = highlight()->getCommentStart( attrib ) + " ";
3579  TQString stopCommentMark = " " + highlight()->getCommentEnd( attrib );
3580 
3581  editStart();
3582 
3583  // Add the start comment mark
3584  insertText (line, 0, startCommentMark);
3585 
3586  // Go to the end of the line
3587  int col = m_buffer->plainLine(line)->length();
3588 
3589  // Add the stop comment mark
3590  insertText (line, col, stopCommentMark);
3591 
3592  editEnd();
3593 }
3594 
3595 /*
3596  Remove from the current line a start comment mark at
3597  the begining and a stop comment mark at the end.
3598 */
3599 bool KateDocument::removeStartStopCommentFromSingleLine( int line, int attrib )
3600 {
3601  TQString shortStartCommentMark = highlight()->getCommentStart( attrib );
3602  TQString longStartCommentMark = shortStartCommentMark + " ";
3603  TQString shortStopCommentMark = highlight()->getCommentEnd( attrib );
3604  TQString longStopCommentMark = " " + shortStopCommentMark;
3605 
3606  editStart();
3607 
3608 #ifdef __GNUC__
3609 #warning "that's a bad idea, can lead to stray endings, FIXME"
3610 #endif
3611  // Try to remove the long start comment mark first
3612  bool removedStart = (removeStringFromBegining(line, longStartCommentMark)
3613  || removeStringFromBegining(line, shortStartCommentMark));
3614 
3615  bool removedStop = false;
3616  if (removedStart)
3617  {
3618  // Try to remove the long stop comment mark first
3619  removedStop = (removeStringFromEnd(line, longStopCommentMark)
3620  || removeStringFromEnd(line, shortStopCommentMark));
3621  }
3622 
3623  editEnd();
3624 
3625  return (removedStart || removedStop);
3626 }
3627 
3628 /*
3629  Add to the current selection a start comment
3630  mark at the begining and a stop comment mark
3631  at the end.
3632 */
3633 void KateDocument::addStartStopCommentToSelection( KateView *view, int attrib )
3634 {
3635  TQString startComment = highlight()->getCommentStart( attrib );
3636  TQString endComment = highlight()->getCommentEnd( attrib );
3637 
3638  int sl = view->selStartLine();
3639  int el = view->selEndLine();
3640  int sc = view->selStartCol();
3641  int ec = view->selEndCol();
3642 
3643  if ((ec == 0) && ((el-1) >= 0))
3644  {
3645  el--;
3646  ec = m_buffer->plainLine (el)->length();
3647  }
3648 
3649  editStart();
3650 
3651  insertText (el, ec, endComment);
3652  insertText (sl, sc, startComment);
3653 
3654  editEnd ();
3655 
3656  // Set the new selection
3657  ec += endComment.length() + ( (el == sl) ? startComment.length() : 0 );
3658  view->setSelection(sl, sc, el, ec);
3659 }
3660 
3661 /*
3662  Add to the current selection a comment line
3663  mark at the begining of each line.
3664 */
3665 void KateDocument::addStartLineCommentToSelection( KateView *view, int attrib )
3666 {
3667  TQString commentLineMark = highlight()->getCommentSingleLineStart( attrib ) + " ";
3668 
3669  int sl = view->selStartLine();
3670  int el = view->selEndLine();
3671 
3672  if ((view->selEndCol() == 0) && ((el-1) >= 0))
3673  {
3674  el--;
3675  }
3676 
3677  editStart();
3678 
3679  // For each line of the selection
3680  for (int z = el; z >= sl; z--) {
3681  //insertText (z, 0, commentLineMark);
3682  addStartLineCommentToSingleLine(z, attrib );
3683  }
3684 
3685  editEnd ();
3686 
3687  // Set the new selection
3688 
3689  KateDocCursor end (view->selEnd());
3690  end.setCol(view->selEndCol() + ((el == view->selEndLine()) ? commentLineMark.length() : 0) );
3691 
3692  view->setSelection(view->selStartLine(), 0, end.line(), end.col());
3693 }
3694 
3695 bool KateDocument::nextNonSpaceCharPos(int &line, int &col)
3696 {
3697  for(; line < (int)m_buffer->count(); line++) {
3698  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3699 
3700  if (!textLine)
3701  break;
3702 
3703  col = textLine->nextNonSpaceChar(col);
3704  if(col != -1)
3705  return true; // Next non-space char found
3706  col = 0;
3707  }
3708  // No non-space char found
3709  line = -1;
3710  col = -1;
3711  return false;
3712 }
3713 
3714 bool KateDocument::previousNonSpaceCharPos(int &line, int &col)
3715 {
3716  while(true)
3717  {
3718  KateTextLine::Ptr textLine = m_buffer->plainLine(line);
3719 
3720  if (!textLine)
3721  break;
3722 
3723  col = textLine->previousNonSpaceChar(col);
3724  if(col != -1) return true;
3725  if(line == 0) return false;
3726  --line;
3727  col = textLine->length();
3728 }
3729  // No non-space char found
3730  line = -1;
3731  col = -1;
3732  return false;
3733 }
3734 
3735 /*
3736  Remove from the selection a start comment mark at
3737  the begining and a stop comment mark at the end.
3738 */
3739 bool KateDocument::removeStartStopCommentFromSelection( KateView *view, int attrib )
3740 {
3741  TQString startComment = highlight()->getCommentStart( attrib );
3742  TQString endComment = highlight()->getCommentEnd( attrib );
3743 
3744  int sl = kMax<int> (0, view->selStartLine());
3745  int el = kMin<int> (view->selEndLine(), lastLine());
3746  int sc = view->selStartCol();
3747  int ec = view->selEndCol();
3748 
3749  // The selection ends on the char before selectEnd
3750  if (ec != 0) {
3751  ec--;
3752  } else {
3753  if (el > 0) {
3754  el--;
3755  ec = m_buffer->plainLine(el)->length() - 1;
3756  }
3757  }
3758 
3759  int startCommentLen = startComment.length();
3760  int endCommentLen = endComment.length();
3761 
3762  // had this been perl or sed: s/^\s*$startComment(.+?)$endComment\s*/$1/
3763 
3764  bool remove = nextNonSpaceCharPos(sl, sc)
3765  && m_buffer->plainLine(sl)->stringAtPos(sc, startComment)
3766  && previousNonSpaceCharPos(el, ec)
3767  && ( (ec - endCommentLen + 1) >= 0 )
3768  && m_buffer->plainLine(el)->stringAtPos(ec - endCommentLen + 1, endComment);
3769 
3770  if (remove) {
3771  editStart();
3772 
3773  removeText (el, ec - endCommentLen + 1, el, ec + 1);
3774  removeText (sl, sc, sl, sc + startCommentLen);
3775 
3776  editEnd ();
3777  // set new selection not necessary, as the selection cursors are KateSuperCursors
3778  }
3779 
3780  return remove;
3781 }
3782 
3783 bool KateDocument::removeStartStopCommentFromRegion(const KateTextCursor &start,const KateTextCursor &end,int attrib)
3784 {
3785  TQString startComment = highlight()->getCommentStart( attrib );
3786  TQString endComment = highlight()->getCommentEnd( attrib );
3787  int startCommentLen = startComment.length();
3788  int endCommentLen = endComment.length();
3789 
3790  bool remove = m_buffer->plainLine(start.line())->stringAtPos(start.col(), startComment)
3791  && ( (end.col() - endCommentLen ) >= 0 )
3792  && m_buffer->plainLine(end.line())->stringAtPos(end.col() - endCommentLen , endComment);
3793  if (remove) {
3794  editStart();
3795  removeText(end.line(),end.col()-endCommentLen,end.line(),end.col());
3796  removeText(start.line(),start.col(),start.line(),start.col()+startCommentLen);
3797  editEnd();
3798  }
3799  return remove;
3800 }
3801 
3802 /*
3803  Remove from the begining of each line of the
3804  selection a start comment line mark.
3805 */
3806 bool KateDocument::removeStartLineCommentFromSelection( KateView *view, int attrib )
3807 {
3808  TQString shortCommentMark = highlight()->getCommentSingleLineStart( attrib );
3809  TQString longCommentMark = shortCommentMark + " ";
3810 
3811  int sl = view->selStartLine();
3812  int el = view->selEndLine();
3813 
3814  if ((view->selEndCol() == 0) && ((el-1) >= 0))
3815  {
3816  el--;
3817  }
3818 
3819  // Find out how many char will be removed from the last line
3820  int removeLength = 0;
3821  if (m_buffer->plainLine(el)->startingWith(longCommentMark))
3822  removeLength = longCommentMark.length();
3823  else if (m_buffer->plainLine(el)->startingWith(shortCommentMark))
3824  removeLength = shortCommentMark.length();
3825 
3826  bool removed = false;
3827 
3828  editStart();
3829 
3830  // For each line of the selection
3831  for (int z = el; z >= sl; z--)
3832  {
3833  // Try to remove the long comment mark first
3834  removed = (removeStringFromBegining(z, longCommentMark)
3835  || removeStringFromBegining(z, shortCommentMark)
3836  || removed);
3837  }
3838 
3839  editEnd();
3840  // updating selection already done by the KateSuperCursors
3841  return removed;
3842 }
3843 
3844 /*
3845  Comment or uncomment the selection or the current
3846  line if there is no selection.
3847 */
3848 void KateDocument::comment( KateView *v, uint line,uint column, int change)
3849 {
3850  // We need to check that we can sanely comment the selectino or region.
3851  // It is if the attribute of the first and last character of the range to
3852  // comment belongs to the same language definition.
3853  // for lines with no text, we need the attribute for the lines context.
3854  bool hassel = v->hasSelection();
3855  int startAttrib, endAttrib;
3856  if ( hassel )
3857  {
3858  KateTextLine::Ptr ln = kateTextLine( v->selStartLine() );
3859  int l = v->selStartLine(), c = v->selStartCol();
3860  startAttrib = nextNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
3861 
3862  ln = kateTextLine( v->selEndLine() );
3863  l = v->selEndLine(), c = v->selEndCol();
3864  endAttrib = previousNonSpaceCharPos( l, c ) ? kateTextLine( l )->attribute( c ) : 0;
3865  }
3866  else
3867  {
3868  KateTextLine::Ptr ln = kateTextLine( line );
3869  if ( ln->length() )
3870  {
3871  startAttrib = ln->attribute( ln->firstChar() );
3872  endAttrib = ln->attribute( ln->lastChar() );
3873  }
3874  else
3875  {
3876  int l = line, c = 0;
3877  if ( nextNonSpaceCharPos( l, c ) || previousNonSpaceCharPos( l, c ) )
3878  startAttrib = endAttrib = kateTextLine( l )->attribute( c );
3879  else
3880  startAttrib = endAttrib = 0;
3881  }
3882  }
3883 
3884  if ( ! highlight()->canComment( startAttrib, endAttrib ) )
3885  {
3886  kdDebug(13020)<<"canComment( "<<startAttrib<<", "<<endAttrib<<" ) returned false!"<<endl;
3887  return;
3888  }
3889 
3890  bool hasStartLineCommentMark = !(highlight()->getCommentSingleLineStart( startAttrib ).isEmpty());
3891  bool hasStartStopCommentMark = ( !(highlight()->getCommentStart( startAttrib ).isEmpty())
3892  && !(highlight()->getCommentEnd( endAttrib ).isEmpty()) );
3893 
3894  bool removed = false;
3895 
3896  if (change > 0) // comment
3897  {
3898  if ( !hassel )
3899  {
3900  if ( hasStartLineCommentMark )
3901  addStartLineCommentToSingleLine( line, startAttrib );
3902  else if ( hasStartStopCommentMark )
3903  addStartStopCommentToSingleLine( line, startAttrib );
3904  }
3905  else
3906  {
3907  // anders: prefer single line comment to avoid nesting probs
3908  // If the selection starts after first char in the first line
3909  // or ends before the last char of the last line, we may use
3910  // multiline comment markers.
3911  // TODO We should try to detect nesting.
3912  // - if selection ends at col 0, most likely she wanted that
3913  // line ignored
3914  if ( hasStartStopCommentMark &&
3915  ( !hasStartLineCommentMark || (
3916  ( v->selStartCol() > m_buffer->plainLine( v->selStartLine() )->firstChar() ) ||
3917  ( v->selEndCol() < ((int)m_buffer->plainLine( v->selEndLine() )->length()) )
3918  ) ) )
3919  addStartStopCommentToSelection( v, startAttrib );
3920  else if ( hasStartLineCommentMark )
3921  addStartLineCommentToSelection( v, startAttrib );
3922  }
3923  }
3924  else // uncomment
3925  {
3926  if ( !hassel )
3927  {
3928  removed = ( hasStartLineCommentMark
3929  && removeStartLineCommentFromSingleLine( line, startAttrib ) )
3930  || ( hasStartStopCommentMark
3931  && removeStartStopCommentFromSingleLine( line, startAttrib ) );
3932  if ((!removed) && foldingTree()) {
3933  kdDebug(13020)<<"easy approach for uncommenting did not work, trying harder (folding tree)"<<endl;
3934  int commentRegion=(highlight()->commentRegion(startAttrib));
3935  if (commentRegion){
3936  KateCodeFoldingNode *n=foldingTree()->findNodeForPosition(line,column);
3937  if (n) {
3938  KateTextCursor start,end;
3939  if ((n->nodeType()==commentRegion) && n->getBegin(foldingTree(), &start) && n->getEnd(foldingTree(), &end)) {
3940  kdDebug(13020)<<"Enclosing region found:"<<start.col()<<"/"<<start.line()<<"-"<<end.col()<<"/"<<end.line()<<endl;
3941  removeStartStopCommentFromRegion(start,end,startAttrib);
3942  } else {
3943  kdDebug(13020)<<"Enclosing region found, but not valid"<<endl;
3944  kdDebug(13020)<<"Region found: "<<n->nodeType()<<" region needed: "<<commentRegion<<endl;
3945  }
3946  //perhaps nested regions should be hadled here too...
3947  } else kdDebug(13020)<<"No enclosing region found"<<endl;
3948  } else kdDebug(13020)<<"No comment region specified for current hl"<<endl;
3949  }
3950  }
3951  else
3952  {
3953  // anders: this seems like it will work with above changes :)
3954  removed = ( hasStartLineCommentMark
3955  && removeStartLineCommentFromSelection( v, startAttrib ) )
3956  || ( hasStartStopCommentMark
3957  && removeStartStopCommentFromSelection( v, startAttrib ) );
3958  }
3959  }
3960 }
3961 
3962 void KateDocument::transform( KateView *v, const KateTextCursor &c,
3963  KateDocument::TextTransform t )
3964 {
3965  editStart();
3966  uint cl( c.line() ), cc( c.col() );
3967  bool selectionRestored = false;
3968 
3969  if ( hasSelection() )
3970  {
3971  // cache the selection and cursor, so we can be sure to restore.
3972  KateTextCursor selstart = v->selStart();
3973  KateTextCursor selend = v->selEnd();
3974 
3975  int ln = v->selStartLine();
3976  while ( ln <= selend.line() )
3977  {
3978  uint start, end;
3979  start = (ln == selstart.line() || v->blockSelectionMode()) ?
3980  selstart.col() : 0;
3981  end = (ln == selend.line() || v->blockSelectionMode()) ?
3982  selend.col() : lineLength( ln );
3983  if ( start > end )
3984  {
3985  uint t = start;
3986  start = end;
3987  end = t;
3988  }
3989  TQString s = text( ln, start, ln, end );
3990  TQString o = s;
3991 
3992  if ( t == Uppercase )
3993  s = s.upper();
3994  else if ( t == Lowercase )
3995  s = s.lower();
3996  else // Capitalize
3997  {
3998  KateTextLine::Ptr l = m_buffer->plainLine( ln );
3999  uint p ( 0 );
4000  while( p < s.length() )
4001  {
4002  // If bol or the character before is not in a word, up this one:
4003  // 1. if both start and p is 0, upper char.
4004  // 2. if blockselect or first line, and p == 0 and start-1 is not in a word, upper
4005  // 3. if p-1 is not in a word, upper.
4006  if ( ( ! start && ! p ) ||
4007  ( ( ln == selstart.line() || v->blockSelectionMode() ) &&
4008  ! p && ! highlight()->isInWord( l->getChar( start - 1 )) ) ||
4009  ( p && ! highlight()->isInWord( s.at( p-1 ) ) )
4010  )
4011  s[p] = s.at(p).upper();
4012  p++;
4013  }
4014  }
4015 
4016  if ( o != s )
4017  {
4018  removeText( ln, start, ln, end );
4019  insertText( ln, start, s );
4020  }
4021 
4022  ln++;
4023  }
4024 
4025  // restore selection
4026  v->setSelection( selstart, selend );
4027  selectionRestored = true;
4028 
4029  } else { // no selection
4030  TQString o = text( cl, cc, cl, cc + 1 );
4031  TQString s;
4032  int n ( cc );
4033  switch ( t ) {
4034  case Uppercase:
4035  s = o.upper();
4036  break;
4037  case Lowercase:
4038  s = o.lower();
4039  break;
4040  case Capitalize:
4041  {
4042  KateTextLine::Ptr l = m_buffer->plainLine( cl );
4043  while ( n > 0 && highlight()->isInWord( l->getChar( n-1 ), l->attribute( n-1 ) ) )
4044  n--;
4045  o = text( cl, n, cl, n + 1 );
4046  s = o.upper();
4047  }
4048  break;
4049  default:
4050  break;
4051  }
4052 
4053  if ( s != o )
4054  {
4055  removeText( cl, n, cl, n+1 );
4056  insertText( cl, n, s );
4057  }
4058  }
4059  editEnd();
4060 
4061  if ( ! selectionRestored )
4062  v->setCursorPosition( cl, cc );
4063 }
4064 
4065 void KateDocument::joinLines( uint first, uint last )
4066 {
4067 // if ( first == last ) last += 1;
4068  editStart();
4069  int line( first );
4070  while ( first < last )
4071  {
4072  // Normalize the whitespace in the joined lines by making sure there's
4073  // always exactly one space between the joined lines
4074  // This cannot be done in editUnwrapLine, because we do NOT want this
4075  // behaviour when deleting from the start of a line, just when explicitly
4076  // calling the join command
4077  KateTextLine::Ptr l = m_buffer->line( line );
4078  KateTextLine::Ptr tl = m_buffer->line( line + 1 );
4079 
4080  if ( !l || !tl )
4081  {
4082  editEnd();
4083  return;
4084  }
4085 
4086  int pos = tl->firstChar();
4087  if ( pos >= 0 )
4088  {
4089  if (pos != 0)
4090  editRemoveText( line + 1, 0, pos );
4091  if ( !( l->length() == 0 || l->getChar( l->length() - 1 ).isSpace() ) )
4092  editInsertText( line + 1, 0, " " );
4093  }
4094  else
4095  {
4096  // Just remove the whitespace and let Kate handle the rest
4097  editRemoveText( line + 1, 0, tl->length() );
4098  }
4099 
4100  editUnWrapLine( line );
4101  first++;
4102  }
4103  editEnd();
4104 }
4105 
4106 TQString KateDocument::getWord( const KateTextCursor& cursor ) {
4107  int start, end, len;
4108 
4109  KateTextLine::Ptr textLine = m_buffer->plainLine(cursor.line());
4110  len = textLine->length();
4111  start = end = cursor.col();
4112  if (start > len) // Probably because of non-wrapping cursor mode.
4113  return TQString("");
4114 
4115  while (start > 0 && highlight()->isInWord(textLine->getChar(start - 1), textLine->attribute(start - 1))) start--;
4116  while (end < len && highlight()->isInWord(textLine->getChar(end), textLine->attribute(end))) end++;
4117  len = end - start;
4118  return TQString(&textLine->text()[start], len);
4119 }
4120 
4121 void KateDocument::tagLines(int start, int end)
4122 {
4123  for (uint z = 0; z < m_views.count(); z++)
4124  m_views.at(z)->tagLines (start, end, true);
4125 }
4126 
4127 void KateDocument::tagLines(KateTextCursor start, KateTextCursor end)
4128 {
4129  // May need to switch start/end cols if in block selection mode
4130  if (blockSelectionMode() && start.col() > end.col()) {
4131  int sc = start.col();
4132  start.setCol(end.col());
4133  end.setCol(sc);
4134  }
4135 
4136  for (uint z = 0; z < m_views.count(); z++)
4137  m_views.at(z)->tagLines(start, end, true);
4138 }
4139 
4140 void KateDocument::repaintViews(bool paintOnlyDirty)
4141 {
4142  for (uint z = 0; z < m_views.count(); z++)
4143  m_views.at(z)->repaintText(paintOnlyDirty);
4144 }
4145 
4146 void KateDocument::tagAll()
4147 {
4148  for (uint z = 0; z < m_views.count(); z++)
4149  {
4150  m_views.at(z)->tagAll();
4151  m_views.at(z)->updateView (true);
4152  }
4153 }
4154 
4155 uint KateDocument::configFlags ()
4156 {
4157  return config()->configFlags();
4158 }
4159 
4160 void KateDocument::setConfigFlags (uint flags)
4161 {
4162  config()->setConfigFlags(flags);
4163 }
4164 
4165 inline bool isStartBracket( const TQChar& c ) { return c == '{' || c == '[' || c == '('; }
4166 inline bool isEndBracket ( const TQChar& c ) { return c == '}' || c == ']' || c == ')'; }
4167 inline bool isBracket ( const TQChar& c ) { return isStartBracket( c ) || isEndBracket( c ); }
4168 
4169 /*
4170  Bracket matching uses the following algorithm:
4171  If in overwrite mode, match the bracket currently underneath the cursor.
4172  Otherwise, if the character to the right of the cursor is an starting bracket,
4173  match it. Otherwise if the character to the left of the cursor is a
4174  ending bracket, match it. Otherwise, if the the character to the left
4175  of the cursor is an starting bracket, match it. Otherwise, if the character
4176  to the right of the cursor is an ending bracket, match it. Otherwise, don't
4177  match anything.
4178 */
4179 void KateDocument::newBracketMark( const KateTextCursor& cursor, KateBracketRange& bm, int maxLines )
4180 {
4181  bm.setValid(false);
4182 
4183  bm.start() = cursor;
4184 
4185  if( !findMatchingBracket( bm.start(), bm.end(), maxLines ) )
4186  return;
4187 
4188  bm.setValid(true);
4189 
4190  const int tw = config()->tabWidth();
4191  const int indentStart = m_buffer->plainLine(bm.start().line())->indentDepth(tw);
4192  const int indentEnd = m_buffer->plainLine(bm.end().line())->indentDepth(tw);
4193  bm.setIndentMin(kMin(indentStart, indentEnd));
4194 }
4195 
4196 bool KateDocument::findMatchingBracket( KateTextCursor& start, KateTextCursor& end, int maxLines )
4197 {
4198  KateTextLine::Ptr textLine = m_buffer->plainLine( start.line() );
4199  if( !textLine )
4200  return false;
4201 
4202  TQChar right = textLine->getChar( start.col() );
4203  TQChar left = textLine->getChar( start.col() - 1 );
4204  TQChar bracket;
4205 
4206  if ( config()->configFlags() & cfOvr ) {
4207  if( isBracket( right ) ) {
4208  bracket = right;
4209  } else {
4210  return false;
4211  }
4212  } else if ( isStartBracket( right ) ) {
4213  bracket = right;
4214  } else if ( isEndBracket( left ) ) {
4215  start.setCol(start.col() - 1);
4216  bracket = left;
4217  } else if ( isBracket( left ) ) {
4218  start.setCol(start.col() - 1);
4219  bracket = left;
4220  } else if ( isBracket( right ) ) {
4221  bracket = right;
4222  } else {
4223  return false;
4224  }
4225 
4226  TQChar opposite;
4227 
4228  switch( bracket ) {
4229  case '{': opposite = '}'; break;
4230  case '}': opposite = '{'; break;
4231  case '[': opposite = ']'; break;
4232  case ']': opposite = '['; break;
4233  case '(': opposite = ')'; break;
4234  case ')': opposite = '('; break;
4235  default: return false;
4236  }
4237 
4238  bool forward = isStartBracket( bracket );
4239  int startAttr = textLine->attribute( start.col() );
4240  uint count = 0;
4241  int lines = 0;
4242  end = start;
4243 
4244  while( true ) {
4245  /* Increment or decrement, check base cases */
4246  if( forward ) {
4247  end.setCol(end.col() + 1);
4248  if( end.col() >= lineLength( end.line() ) ) {
4249  if( end.line() >= (int)lastLine() )
4250  return false;
4251  end.setPos(end.line() + 1, 0);
4252  textLine = m_buffer->plainLine( end.line() );
4253  lines++;
4254  }
4255  } else {
4256  end.setCol(end.col() - 1);
4257  if( end.col() < 0 ) {
4258  if( end.line() <= 0 )
4259  return false;
4260  end.setLine(end.line() - 1);
4261  end.setCol(lineLength( end.line() ) - 1);
4262  textLine = m_buffer->plainLine( end.line() );
4263  lines++;
4264  }
4265  }
4266 
4267  if ((maxLines != -1) && (lines > maxLines))
4268  return false;
4269 
4270  /* Easy way to skip comments */
4271  if( textLine->attribute( end.col() ) != startAttr )
4272  continue;
4273 
4274  /* Check for match */
4275  TQChar c = textLine->getChar( end.col() );
4276  if( c == bracket ) {
4277  count++;
4278  } else if( c == opposite ) {
4279  if( count == 0 )
4280  return true;
4281  count--;
4282  }
4283 
4284  }
4285 }
4286 
4287 void KateDocument::guiActivateEvent( KParts::GUIActivateEvent *ev )
4288 {
4289  KParts::ReadWritePart::guiActivateEvent( ev );
4290  if ( ev->activated() )
4291  emit selectionChanged();
4292 }
4293 
4294 void KateDocument::setDocName (TQString name )
4295 {
4296  if ( name == m_docName )
4297  return;
4298 
4299  if ( !name.isEmpty() )
4300  {
4301  // TODO check for similarly named documents
4302  m_docName = name;
4303  updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
4304  emit nameChanged((Kate::Document *) this);
4305  return;
4306  }
4307 
4308  // if the name is set, and starts with FILENAME, it should not be changed!
4309  if ( ! url().isEmpty() && m_docName.startsWith( url().filename() ) ) return;
4310 
4311  int count = -1;
4312 
4313  for (uint z=0; z < KateFactory::self()->documents()->count(); z++)
4314  {
4315  if ( (KateFactory::self()->documents()->at(z) != this) && (KateFactory::self()->documents()->at(z)->url().filename() == url().filename()) )
4316  if ( KateFactory::self()->documents()->at(z)->m_docNameNumber > count )
4317  count = KateFactory::self()->documents()->at(z)->m_docNameNumber;
4318  }
4319 
4320  m_docNameNumber = count + 1;
4321 
4322  m_docName = url().filename();
4323 
4324  if (m_docName.isEmpty())
4325  m_docName = i18n ("Untitled");
4326 
4327  if (m_docNameNumber > 0)
4328  m_docName = TQString(m_docName + " (%1)").arg(m_docNameNumber+1);
4329 
4330  updateFileType (KateFactory::self()->fileTypeManager()->fileType (this));
4331  emit nameChanged ((Kate::Document *) this);
4332 }
4333 
4334 void KateDocument::slotModifiedOnDisk( Kate::View * /*v*/ )
4335 {
4336  if ( m_isasking < 0 )
4337  {
4338  m_isasking = 0;
4339  return;
4340  }
4341 
4342  if ( !s_fileChangedDialogsActivated || m_isasking )
4343  return;
4344 
4345  if (m_modOnHd && !url().isEmpty())
4346  {
4347  m_isasking = 1;
4348 
4349  KateModOnHdPrompt p( this, m_modOnHdReason, reasonedMOHString(), widget() );
4350  switch ( p.exec() )
4351  {
4352  case KateModOnHdPrompt::Save:
4353  {
4354  m_modOnHd = false;
4355  KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
4356  url().url(),TQString::null,widget(),i18n("Save File"));
4357 
4358  kdDebug(13020)<<"got "<<res.URLs.count()<<" URLs"<<endl;
4359  if( ! res.URLs.isEmpty() && ! res.URLs.first().isEmpty() && checkOverwrite( res.URLs.first() ) )
4360  {
4361  setEncoding( res.encoding );
4362 
4363  if( ! saveAs( res.URLs.first() ) )
4364  {
4365  KMessageBox::error( widget(), i18n("Save failed") );
4366  m_modOnHd = true;
4367  }
4368  else
4369  emit modifiedOnDisc( this, false, 0 );
4370  }
4371  else // the save as dialog was cancelled, we are still modified on disk
4372  {
4373  m_modOnHd = true;
4374  }
4375 
4376  m_isasking = 0;
4377  break;
4378  }
4379 
4380  case KateModOnHdPrompt::Reload:
4381  m_modOnHd = false;
4382  emit modifiedOnDisc( this, false, 0 );
4383  reloadFile();
4384  m_isasking = 0;
4385  break;
4386 
4387  case KateModOnHdPrompt::Ignore:
4388  m_modOnHd = false;
4389  emit modifiedOnDisc( this, false, 0 );
4390  m_isasking = 0;
4391  break;
4392 
4393  case KateModOnHdPrompt::Overwrite:
4394  m_modOnHd = false;
4395  emit modifiedOnDisc( this, false, 0 );
4396  m_isasking = 0;
4397  save();
4398  break;
4399 
4400  default: // cancel: ignore next focus event
4401  m_isasking = -1;
4402  }
4403  }
4404 }
4405 
4406 void KateDocument::setModifiedOnDisk( int reason )
4407 {
4408  m_modOnHdReason = reason;
4409  m_modOnHd = (reason > 0);
4410  emit modifiedOnDisc( this, (reason > 0), reason );
4411 }
4412 
4413 class KateDocumentTmpMark
4414 {
4415  public:
4416  TQString line;
4417  KTextEditor::Mark mark;
4418 };
4419 
4420 void KateDocument::reloadFile()
4421 {
4422  if ( !url().isEmpty() )
4423  {
4424  if (m_modOnHd && s_fileChangedDialogsActivated)
4425  {
4426  int i = KMessageBox::warningYesNoCancel
4427  (0, reasonedMOHString() + "\n\n" + i18n("What do you want to do?"),
4428  i18n("File Was Changed on Disk"), i18n("&Reload File"), i18n("&Ignore Changes"));
4429 
4430  if ( i != KMessageBox::Yes)
4431  {
4432  if (i == KMessageBox::No)
4433  {
4434  m_modOnHd = false;
4435  m_modOnHdReason = 0;
4436  emit modifiedOnDisc (this, m_modOnHd, 0);
4437  }
4438 
4439  return;
4440  }
4441  }
4442 
4443  TQValueList<KateDocumentTmpMark> tmp;
4444 
4445  for( TQIntDictIterator<KTextEditor::Mark> it( m_marks ); it.current(); ++it )
4446  {
4447  KateDocumentTmpMark m;
4448 
4449  m.line = textLine (it.current()->line);
4450  m.mark = *it.current();
4451 
4452  tmp.append (m);
4453  }
4454 
4455  uint mode = hlMode ();
4456  bool byUser = hlSetByUser;
4457 
4458  m_storedVariables.clear();
4459 
4460  m_reloading = true;
4461 
4462  TQValueList<int> lines, cols;
4463  for ( uint i=0; i < m_views.count(); i++ )
4464  {
4465  lines.append( m_views.at( i )->cursorLine() );
4466  cols.append( m_views.at( i )->cursorColumn() );
4467  }
4468 
4469  KateDocument::openURL( url() );
4470 
4471  for ( uint i=0; i < m_views.count(); i++ )
4472  m_views.at( i )->setCursorPositionInternal( lines[ i ], cols[ i ], m_config->tabWidth(), false );
4473 
4474  m_reloading = false;
4475 
4476  for ( TQValueList<int>::size_type z=0; z < tmp.size(); z++ )
4477  {
4478  if (z < numLines())
4479  {
4480  if (textLine(tmp[z].mark.line) == tmp[z].line)
4481  setMark (tmp[z].mark.line, tmp[z].mark.type);
4482  }
4483  }
4484 
4485  if (byUser)
4486  setHlMode (mode);
4487  }
4488 }
4489 
4490 void KateDocument::flush ()
4491 {
4492  closeURL ();
4493 }
4494 
4495 void KateDocument::setWordWrap (bool on)
4496 {
4497  config()->setWordWrap (on);
4498 }
4499 
4500 bool KateDocument::wordWrap ()
4501 {
4502  return config()->wordWrap ();
4503 }
4504 
4505 void KateDocument::setWordWrapAt (uint col)
4506 {
4507  config()->setWordWrapAt (col);
4508 }
4509 
4510 unsigned int KateDocument::wordWrapAt ()
4511 {
4512  return config()->wordWrapAt ();
4513 }
4514 
4515 void KateDocument::applyWordWrap ()
4516 {
4517  // dummy to make the API happy
4518 }
4519 
4520 void KateDocument::setPageUpDownMovesCursor (bool on)
4521 {
4522  config()->setPageUpDownMovesCursor (on);
4523 }
4524 
4525 bool KateDocument::pageUpDownMovesCursor ()
4526 {
4527  return config()->pageUpDownMovesCursor ();
4528 }
4529 
4530 void KateDocument::dumpRegionTree()
4531 {
4532  m_buffer->foldingTree()->debugDump();
4533 }
4534 //END
4535 
4536 //BEGIN KTextEditor::CursorInterface stuff
4537 
4538 KTextEditor::Cursor *KateDocument::createCursor ( )
4539 {
4540  return new KateSuperCursor (this, false, 0, 0, this);
4541 }
4542 
4543 void KateDocument::tagArbitraryLines(KateView* view, KateSuperRange* range)
4544 {
4545  if (view)
4546  view->tagLines(range->start(), range->end());
4547  else
4548  tagLines(range->start(), range->end());
4549 }
4550 
4551 void KateDocument::lineInfo (KateLineInfo *info, unsigned int line)
4552 {
4553  m_buffer->lineInfo(info,line);
4554 }
4555 
4556 KateCodeFoldingTree *KateDocument::foldingTree ()
4557 {
4558  return m_buffer->foldingTree();
4559 }
4560 
4561 void KateDocument::setEncoding (const TQString &e)
4562 {
4563  if ( m_encodingSticky )
4564  return;
4565 
4566  TQString ce = m_config->encoding().lower();
4567  if ( e.lower() == ce )
4568  return;
4569 
4570  m_config->setEncoding( e );
4571  if ( ! m_loading )
4572  reloadFile();
4573 }
4574 
4575 TQString KateDocument::encoding() const
4576 {
4577  return m_config->encoding();
4578 }
4579 
4580 void KateDocument::updateConfig ()
4581 {
4582  emit undoChanged ();
4583  tagAll();
4584 
4585  for (KateView * view = m_views.first(); view != 0L; view = m_views.next() )
4586  {
4587  view->updateDocumentConfig ();
4588  }
4589 
4590  // switch indenter if needed
4591  if (m_indenter->modeNumber() != m_config->indentationMode())
4592  {
4593  delete m_indenter;
4594  m_indenter = KateAutoIndent::createIndenter ( this, m_config->indentationMode() );
4595  }
4596 
4597  m_indenter->updateConfig();
4598 
4599  m_buffer->setTabWidth (config()->tabWidth());
4600 
4601  // plugins
4602  for (uint i=0; i<KateFactory::self()->plugins().count(); i++)
4603  {
4604  if (config()->plugin (i))
4605  loadPlugin (i);
4606  else
4607  unloadPlugin (i);
4608  }
4609 }
4610 
4611 //BEGIN Variable reader
4612 // "local variable" feature by anders, 2003
4613 /* TODO
4614  add config options (how many lines to read, on/off)
4615  add interface for plugins/apps to set/get variables
4616  add view stuff
4617 */
4618 TQRegExp KateDocument::kvLine = TQRegExp("kate:(.*)");
4619 TQRegExp KateDocument::kvLineWildcard = TQRegExp("kate-wildcard\\((.*)\\):(.*)");
4620 TQRegExp KateDocument::kvLineMime = TQRegExp("kate-mimetype\\((.*)\\):(.*)");
4621 TQRegExp KateDocument::kvVar = TQRegExp("([\\w\\-]+)\\s+([^;]+)");
4622 
4623 void KateDocument::readVariables(bool onlyViewAndRenderer)
4624 {
4625  if (!onlyViewAndRenderer)
4626  m_config->configStart();
4627 
4628  // views!
4629  KateView *v;
4630  for (v = m_views.first(); v != 0L; v= m_views.next() )
4631  {
4632  v->config()->configStart();
4633  v->renderer()->config()->configStart();
4634  }
4635  // read a number of lines in the top/bottom of the document
4636  for (uint i=0; i < kMin( 9U, numLines() ); ++i )
4637  {
4638  readVariableLine( textLine( i ), onlyViewAndRenderer );
4639  }
4640  if ( numLines() > 10 )
4641  {
4642  for ( uint i = kMax(10U, numLines() - 10); i < numLines(); ++i )
4643  {
4644  readVariableLine( textLine( i ), onlyViewAndRenderer );
4645  }
4646  }
4647 
4648  if (!onlyViewAndRenderer)
4649  m_config->configEnd();
4650 
4651  for (v = m_views.first(); v != 0L; v= m_views.next() )
4652  {
4653  v->config()->configEnd();
4654  v->renderer()->config()->configEnd();
4655  }
4656 }
4657 
4658 void KateDocument::readVariableLine( TQString t, bool onlyViewAndRenderer )
4659 {
4660  // simple check first, no regex
4661  // no kate inside, no vars, simple...
4662  if (t.find("kate") < 0)
4663  return;
4664 
4665  // found vars, if any
4666  TQString s;
4667 
4668  if ( kvLine.search( t ) > -1 )
4669  {
4670  s = kvLine.cap(1);
4671 
4672  kdDebug (13020) << "normal variable line kate: matched: " << s << endl;
4673  }
4674  else if (kvLineWildcard.search( t ) > -1) // regex given
4675  {
4676  TQStringList wildcards (TQStringList::split(';', kvLineWildcard.cap(1)));
4677  TQString nameOfFile = url().fileName();
4678 
4679  bool found = false;
4680  for (TQStringList::size_type i = 0; !found && i < wildcards.size(); ++i)
4681  {
4682  TQRegExp wildcard (wildcards[i], true/*TQt::CaseSensitive*/, true/*TQRegExp::Wildcard*/);
4683 
4684  found = wildcard.exactMatch (nameOfFile);
4685  }
4686 
4687  // nothing usable found...
4688  if (!found)
4689  return;
4690 
4691  s = kvLineWildcard.cap(2);
4692 
4693  kdDebug (13020) << "guarded variable line kate-wildcard: matched: " << s << endl;
4694  }
4695  else if (kvLineMime.search( t ) > -1) // mime-type given
4696  {
4697  TQStringList types (TQStringList::split(';', kvLineMime.cap(1)));
4698 
4699  // no matching type found
4700  if (!types.contains (mimeType ()))
4701  return;
4702 
4703  s = kvLineMime.cap(2);
4704 
4705  kdDebug (13020) << "guarded variable line kate-mimetype: matched: " << s << endl;
4706  }
4707  else // nothing found
4708  {
4709  return;
4710  }
4711 
4712  TQStringList vvl; // view variable names
4713  vvl << "dynamic-word-wrap" << "dynamic-word-wrap-indicators"
4714  << "line-numbers" << "icon-border" << "folding-markers"
4715  << "bookmark-sorting" << "auto-center-lines"
4716  << "icon-bar-color"
4717  // renderer
4718  << "background-color" << "selection-color"
4719  << "current-line-color" << "bracket-highlight-color"
4720  << "word-wrap-marker-color"
4721  << "font" << "font-size" << "scheme";
4722  int p( 0 );
4723 
4724  TQString var, val;
4725  while ( (p = kvVar.search( s, p )) > -1 )
4726  {
4727  p += kvVar.matchedLength();
4728  var = kvVar.cap( 1 );
4729  val = TQString(kvVar.cap( 2 )).stripWhiteSpace();
4730  bool state; // store booleans here
4731  int n; // store ints here
4732 
4733  // only apply view & renderer config stuff
4734  if (onlyViewAndRenderer)
4735  {
4736  if ( vvl.contains( var ) ) // FIXME define above
4737  setViewVariable( var, val );
4738  }
4739  else
4740  {
4741  // BOOL SETTINGS
4742  if ( var == "word-wrap" && checkBoolValue( val, &state ) )
4743  setWordWrap( state ); // ??? FIXME CHECK
4744  else if ( var == "block-selection" && checkBoolValue( val, &state ) )
4745  setBlockSelectionMode( state );
4746  // KateConfig::configFlags
4747  // FIXME should this be optimized to only a few calls? how?
4748  else if ( var == "backspace-indents" && checkBoolValue( val, &state ) )
4749  m_config->setConfigFlags( KateDocumentConfig::cfBackspaceIndents, state );
4750  else if ( var == "replace-tabs" && checkBoolValue( val, &state ) )
4751  m_config->setConfigFlags( KateDocumentConfig::cfReplaceTabsDyn, state );
4752  else if ( var == "remove-trailing-space" && checkBoolValue( val, &state ) )
4753  m_config->setConfigFlags( KateDocumentConfig::cfRemoveTrailingDyn, state );
4754  else if ( var == "wrap-cursor" && checkBoolValue( val, &state ) )
4755  m_config->setConfigFlags( KateDocumentConfig::cfWrapCursor, state );
4756  else if ( var == "auto-brackets" && checkBoolValue( val, &state ) )
4757  m_config->setConfigFlags( KateDocumentConfig::cfAutoBrackets, state );
4758  else if ( var == "overwrite-mode" && checkBoolValue( val, &state ) )
4759  m_config->setConfigFlags( KateDocumentConfig::cfOvr, state );
4760  else if ( var == "keep-indent-profile" && checkBoolValue( val, &state ) )
4761  m_config->setConfigFlags( KateDocumentConfig::cfKeepIndentProfile, state );
4762  else if ( var == "keep-extra-spaces" && checkBoolValue( val, &state ) )
4763  m_config->setConfigFlags( KateDocumentConfig::cfKeepExtraSpaces, state );
4764  else if ( var == "tab-indents" && checkBoolValue( val, &state ) )
4765  m_config->setConfigFlags( KateDocumentConfig::cfTabIndents, state );
4766  else if ( var == "show-tabs" && checkBoolValue( val, &state ) )
4767  m_config->setConfigFlags( KateDocumentConfig::cfShowTabs, state );
4768  else if ( var == "space-indent" && checkBoolValue( val, &state ) )
4769  m_config->setConfigFlags( KateDocumentConfig::cfSpaceIndent, state );
4770  else if ( var == "smart-home" && checkBoolValue( val, &state ) )
4771  m_config->setConfigFlags( KateDocumentConfig::cfSmartHome, state );
4772  else if ( var == "replace-trailing-space-save" && checkBoolValue( val, &state ) )
4773  m_config->setConfigFlags( KateDocumentConfig::cfRemoveSpaces, state );
4774  else if ( var == "auto-insert-doxygen" && checkBoolValue( val, &state) )
4775  m_config->setConfigFlags( KateDocumentConfig::cfDoxygenAutoTyping, state);
4776  else if ( var == "mixed-indent" && checkBoolValue( val, &state ) )
4777  m_config->setConfigFlags( KateDocumentConfig::cfMixedIndent, state );
4778 
4779  // INTEGER SETTINGS
4780  else if ( var == "tab-width" && checkIntValue( val, &n ) )
4781  m_config->setTabWidth( n );
4782  else if ( var == "indent-width" && checkIntValue( val, &n ) )
4783  m_config->setIndentationWidth( n );
4784  else if ( var == "indent-mode" )
4785  {
4786  if ( checkIntValue( val, &n ) )
4787  m_config->setIndentationMode( n );
4788  else
4789  m_config->setIndentationMode( KateAutoIndent::modeNumber( val) );
4790  }
4791  else if ( var == "word-wrap-column" && checkIntValue( val, &n ) && n > 0 ) // uint, but hard word wrap at 0 will be no fun ;)
4792  m_config->setWordWrapAt( n );
4793  else if ( var == "undo-steps" && checkIntValue( val, &n ) && n >= 0 )
4794  setUndoSteps( n );
4795 
4796  // STRING SETTINGS
4797  else if ( var == "eol" || var == "end-of-line" )
4798  {
4799  TQStringList l;
4800  l << "unix" << "dos" << "mac";
4801  if ( (n = l.findIndex( val.lower() )) != -1 )
4802  m_config->setEol( n );
4803  }
4804  else if ( var == "encoding" )
4805  m_config->setEncoding( val );
4806  else if ( var == "syntax" || var == "hl" )
4807  {
4808  for ( uint i=0; i < hlModeCount(); i++ )
4809  {
4810  if ( hlModeName( i ).lower() == val.lower() )
4811  {
4812  setHlMode( i );
4813  break;
4814  }
4815  }
4816  }
4817 
4818  // VIEW SETTINGS
4819  else if ( vvl.contains( var ) )
4820  setViewVariable( var, val );
4821  else
4822  {
4823  m_storedVariables.insert( var, val );
4824  emit variableChanged( var, val );
4825  }
4826  }
4827  }
4828 }
4829 
4830 void KateDocument::setViewVariable( TQString var, TQString val )
4831 {
4832  KateView *v;
4833  bool state;
4834  int n;
4835  TQColor c;
4836  for (v = m_views.first(); v != 0L; v= m_views.next() )
4837  {
4838  if ( var == "dynamic-word-wrap" && checkBoolValue( val, &state ) )
4839  v->config()->setDynWordWrap( state );
4840  else if ( var == "persistent-selection" && checkBoolValue( val, &state ) )
4841  v->config()->setPersistentSelection( state );
4842  //else if ( var = "dynamic-word-wrap-indicators" )
4843  else if ( var == "line-numbers" && checkBoolValue( val, &state ) )
4844  v->config()->setLineNumbers( state );
4845  else if (var == "icon-border" && checkBoolValue( val, &state ) )
4846  v->config()->setIconBar( state );
4847  else if (var == "folding-markers" && checkBoolValue( val, &state ) )
4848  v->config()->setFoldingBar( state );
4849  else if ( var == "auto-center-lines" && checkIntValue( val, &n ) )
4850  v->config()->setAutoCenterLines( n ); // FIXME uint, > N ??
4851  else if ( var == "icon-bar-color" && checkColorValue( val, c ) )
4852  v->renderer()->config()->setIconBarColor( c );
4853  // RENDERER
4854  else if ( var == "background-color" && checkColorValue( val, c ) )
4855  v->renderer()->config()->setBackgroundColor( c );
4856  else if ( var == "selection-color" && checkColorValue( val, c ) )
4857  v->renderer()->config()->setSelectionColor( c );
4858  else if ( var == "current-line-color" && checkColorValue( val, c ) )
4859  v->renderer()->config()->setHighlightedLineColor( c );
4860  else if ( var == "bracket-highlight-color" && checkColorValue( val, c ) )
4861  v->renderer()->config()->setHighlightedBracketColor( c );
4862  else if ( var == "word-wrap-marker-color" && checkColorValue( val, c ) )
4863  v->renderer()->config()->setWordWrapMarkerColor( c );
4864  else if ( var == "font" || ( var == "font-size" && checkIntValue( val, &n ) ) )
4865  {
4866  TQFont _f( *v->renderer()->config()->font( ) );
4867 
4868  if ( var == "font" )
4869  {
4870  _f.setFamily( val );
4871  _f.setFixedPitch( TQFont( val ).fixedPitch() );
4872  }
4873  else
4874  _f.setPointSize( n );
4875 
4876  v->renderer()->config()->setFont( _f );
4877  }
4878  else if ( var == "scheme" )
4879  {
4880  v->renderer()->config()->setSchema( KateFactory::self()->schemaManager()->number( val ) );
4881  }
4882  }
4883 }
4884 
4885 bool KateDocument::checkBoolValue( TQString val, bool *result )
4886 {
4887  val = val.stripWhiteSpace().lower();
4888  TQStringList l;
4889  l << "1" << "on" << "true";
4890  if ( l.contains( val ) )
4891  {
4892  *result = true;
4893  return true;
4894  }
4895  l.clear();
4896  l << "0" << "off" << "false";
4897  if ( l.contains( val ) )
4898  {
4899  *result = false;
4900  return true;
4901  }
4902  return false;
4903 }
4904 
4905 bool KateDocument::checkIntValue( TQString val, int *result )
4906 {
4907  bool ret( false );
4908  *result = val.toInt( &ret );
4909  return ret;
4910 }
4911 
4912 bool KateDocument::checkColorValue( TQString val, TQColor &c )
4913 {
4914  c.setNamedColor( val );
4915  return c.isValid();
4916 }
4917 
4918 // KTextEditor::variable
4919 TQString KateDocument::variable( const TQString &name ) const
4920 {
4921  if ( m_storedVariables.contains( name ) )
4922  return m_storedVariables[ name ];
4923 
4924  return "";
4925 }
4926 
4927 //END
4928 
4929 void KateDocument::slotModOnHdDirty (const TQString &path)
4930 {
4931  if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 1))
4932  {
4933  // compare md5 with the one we have (if we have one)
4934  if ( ! m_digest.isEmpty() )
4935  {
4936  TQCString tmp;
4937  if ( createDigest( tmp ) && tmp == m_digest )
4938  return;
4939  }
4940 
4941  m_modOnHd = true;
4942  m_modOnHdReason = 1;
4943 
4944  // reenable dialog if not running atm
4945  if (m_isasking == -1)
4946  m_isasking = false;
4947 
4948  emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
4949  }
4950 }
4951 
4952 void KateDocument::slotModOnHdCreated (const TQString &path)
4953 {
4954  if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 2))
4955  {
4956  m_modOnHd = true;
4957  m_modOnHdReason = 2;
4958 
4959  // reenable dialog if not running atm
4960  if (m_isasking == -1)
4961  m_isasking = false;
4962 
4963  emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
4964  }
4965 }
4966 
4967 void KateDocument::slotModOnHdDeleted (const TQString &path)
4968 {
4969  if ((path == m_dirWatchFile) && (!m_modOnHd || m_modOnHdReason != 3))
4970  {
4971  m_modOnHd = true;
4972  m_modOnHdReason = 3;
4973 
4974  // reenable dialog if not running atm
4975  if (m_isasking == -1)
4976  m_isasking = false;
4977 
4978  emit modifiedOnDisc (this, m_modOnHd, m_modOnHdReason);
4979  }
4980 }
4981 
4982 bool KateDocument::createDigest( TQCString &result )
4983 {
4984  bool ret = false;
4985  result = "";
4986  if ( url().isLocalFile() )
4987  {
4988  TQFile f ( url().path() );
4989  if ( f.open( IO_ReadOnly) )
4990  {
4991  KMD5 md5;
4992  ret = md5.update( f );
4993  md5.hexDigest( result );
4994  f.close();
4995  ret = true;
4996  }
4997  }
4998  return ret;
4999 }
5000 
5001 TQString KateDocument::reasonedMOHString() const
5002 {
5003  switch( m_modOnHdReason )
5004  {
5005  case 1:
5006  return i18n("The file '%1' was modified by another program.").arg( url().pathOrURL() );
5007  break;
5008  case 2:
5009  return i18n("The file '%1' was created by another program.").arg( url().pathOrURL() );
5010  break;
5011  case 3:
5012  return i18n("The file '%1' was deleted by another program.").arg( url().pathOrURL() );
5013  break;
5014  default:
5015  return TQString();
5016  }
5017 }
5018 
5019 void KateDocument::removeTrailingSpace( uint line )
5020 {
5021  // remove trailing spaces from left line if required
5022  if ( config()->configFlags() & KateDocumentConfig::cfRemoveTrailingDyn )
5023  {
5024  KateTextLine::Ptr ln = kateTextLine( line );
5025 
5026  if ( ! ln ) return;
5027 
5028  if ( line == activeView()->cursorLine()
5029  && activeView()->cursorColumnReal() >= (uint)kMax(0,ln->lastChar()) )
5030  return;
5031 
5032  if ( ln->length() )
5033  {
5034  uint p = ln->lastChar() + 1;
5035  uint l = ln->length() - p;
5036  if ( l )
5037  editRemoveText( line, p, l);
5038  }
5039  }
5040 }
5041 
5042 void KateDocument::updateFileType (int newType, bool user)
5043 {
5044  if (user || !m_fileTypeSetByUser)
5045  {
5046  const KateFileType *t = 0;
5047  if ((newType == -1) || (t = KateFactory::self()->fileTypeManager()->fileType (newType)))
5048  {
5049  m_fileType = newType;
5050 
5051  if (t)
5052  {
5053  m_config->configStart();
5054  // views!
5055  KateView *v;
5056  for (v = m_views.first(); v != 0L; v= m_views.next() )
5057  {
5058  v->config()->configStart();
5059  v->renderer()->config()->configStart();
5060  }
5061 
5062  readVariableLine( t->varLine );
5063 
5064  m_config->configEnd();
5065  for (v = m_views.first(); v != 0L; v= m_views.next() )
5066  {
5067  v->config()->configEnd();
5068  v->renderer()->config()->configEnd();
5069  }
5070  }
5071  }
5072  }
5073 }
5074 
5075 uint KateDocument::documentNumber () const
5076 {
5077  return KTextEditor::Document::documentNumber ();
5078 }
5079 
5080 long KateDocument::documentListPosition () const
5081 {
5082  return KTextEditor::Document::documentListPosition ();
5083 }
5084 
5085 void KateDocument::setDocumentListPosition (long pos)
5086 {
5087  KTextEditor::Document::setDocumentListPosition (pos);
5088 }
5089 
5090 
5091 
5092 void KateDocument::slotQueryClose_save(bool *handled, bool* abortClosing) {
5093  *handled=true;
5094  *abortClosing=true;
5095  if (m_url.isEmpty())
5096  {
5097  KEncodingFileDialog::Result res=KEncodingFileDialog::getSaveURLAndEncoding(config()->encoding(),
5098  TQString::null,TQString::null,0,i18n("Save File"));
5099 
5100  if( res.URLs.isEmpty() || !checkOverwrite( res.URLs.first() ) ) {
5101  *abortClosing=true;
5102  return;
5103  }
5104  setEncoding( res.encoding );
5105  saveAs( res.URLs.first() );
5106  *abortClosing=false;
5107  }
5108  else
5109  {
5110  save();
5111  *abortClosing=false;
5112  }
5113 
5114 }
5115 
5116 bool KateDocument::checkOverwrite( KURL u )
5117 {
5118  if( !u.isLocalFile() )
5119  return true;
5120 
5121  TQFileInfo info( u.path() );
5122  if( !info.exists() )
5123  return true;
5124 
5125  return KMessageBox::Cancel != KMessageBox::warningContinueCancel( 0,
5126  i18n( "A file named \"%1\" already exists. "
5127  "Are you sure you want to overwrite it?" ).arg( info.fileName() ),
5128  i18n( "Overwrite File?" ),
5129  i18n( "&Overwrite" ) );
5130 }
5131 
5132 void KateDocument::setDefaultEncoding (const TQString &encoding)
5133 {
5134  s_defaultEncoding = encoding;
5135 }
5136 
5137 //BEGIN KTextEditor::TemplateInterface
5138 bool KateDocument::insertTemplateTextImplementation ( uint line, uint column, const TQString &templateString, const TQMap<TQString,TQString> &initialValues, TQWidget *) {
5139  return (new KateTemplateHandler(this,line,column,templateString,initialValues))->initOk();
5140 }
5141 
5142 void KateDocument::testTemplateCode() {
5143  int col=activeView()->cursorColumn();
5144  int line=activeView()->cursorLine();
5145  insertTemplateText(line,col,"for ${index} \\${NOPLACEHOLDER} ${index} ${blah} ${fullname} \\$${Placeholder} \\${${PLACEHOLDER2}}\n next line:${ANOTHERPLACEHOLDER} $${DOLLARBEFOREPLACEHOLDER} {NOTHING} {\n${cursor}\n}",TQMap<TQString,TQString>());
5146 }
5147 
5148 bool KateDocument::invokeTabInterceptor(KKey key) {
5149  if (m_tabInterceptor) return (*m_tabInterceptor)(key);
5150  return false;
5151 }
5152 
5153 bool KateDocument::setTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
5154  if (m_tabInterceptor) return false;
5155  m_tabInterceptor=interceptor;
5156  return true;
5157 }
5158 
5159 bool KateDocument::removeTabInterceptor(KateKeyInterceptorFunctor *interceptor) {
5160  if (m_tabInterceptor!=interceptor) return false;
5161  m_tabInterceptor=0;
5162  return true;
5163 }
5164 //END KTextEditor::TemplateInterface
5165 
5166 //BEGIN DEPRECATED STUFF
5167  bool KateDocument::setSelection ( uint startLine, uint startCol, uint endLine, uint endCol )
5168 { if (m_activeView) return m_activeView->setSelection (startLine, startCol, endLine, endCol); return false; }
5169 
5170  bool KateDocument::clearSelection ()
5171  { if (m_activeView) return m_activeView->clearSelection(); return false; }
5172 
5173  bool KateDocument::hasSelection () const
5174  { if (m_activeView) return m_activeView->hasSelection (); return false; }
5175 
5176  TQString KateDocument::selection () const
5177  { if (m_activeView) return m_activeView->selection (); return TQString(""); }
5178 
5179  bool KateDocument::removeSelectedText ()
5180  { if (m_activeView) return m_activeView->removeSelectedText (); return false; }
5181 
5182  bool KateDocument::selectAll()
5183  { if (m_activeView) return m_activeView->selectAll (); return false; }
5184 
5185  int KateDocument::selStartLine()
5186  { if (m_activeView) return m_activeView->selStartLine (); return 0; }
5187 
5188  int KateDocument::selStartCol()
5189  { if (m_activeView) return m_activeView->selStartCol (); return 0; }
5190 
5191  int KateDocument::selEndLine()
5192  { if (m_activeView) return m_activeView->selEndLine (); return 0; }
5193 
5194  int KateDocument::selEndCol()
5195  { if (m_activeView) return m_activeView->selEndCol (); return 0; }
5196 
5197  bool KateDocument::blockSelectionMode ()
5198  { if (m_activeView) return m_activeView->blockSelectionMode (); return false; }
5199 
5200 bool KateDocument::setBlockSelectionMode (bool on)
5201  { if (m_activeView) return m_activeView->setBlockSelectionMode (on); return false; }
5202 
5203 bool KateDocument::toggleBlockSelectionMode ()
5204  { if (m_activeView) return m_activeView->toggleBlockSelectionMode (); return false; }
5205 //END DEPRECATED
5206 
5207 //END DEPRECATED STUFF
KDialogBase
KDialogBase::addVBoxPage
TQVBox * addVBoxPage(const TQString &itemName, const TQString &header=TQString::null, const TQPixmap &pixmap=TQPixmap())
KDialogBase::Help
Help
KDialogBase::Ok
Ok
KDialogBase::Cancel
Cancel
KKey
KMD5
KMD5::update
void update(const char *in, int len=-1)
KMD5::hexDigest
TQCString hexDigest()
KMessageBox::information
static void information(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const TQString &dontShowAgainName=TQString::null, int options=Notify)
KMessageBox::error
static void error(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, int options=Notify)
KMessageBox::warningYesNoCancel
static int warningYesNoCancel(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const KGuiItem &buttonYes=KStdGuiItem::yes(), const KGuiItem &buttonNo=KStdGuiItem::no(), const TQString &dontAskAgainName=TQString::null, int options=Notify)
KMessageBox::warningContinueCancel
static int warningContinueCancel(TQWidget *parent, const TQString &text, const TQString &caption=TQString::null, const KGuiItem &buttonContinue=KStdGuiItem::cont(), const TQString &dontAskAgainName=TQString::null, int options=Notify)
KParts::GUIActivateEvent
KParts::ReadOnlyPart::guiActivateEvent
virtual void guiActivateEvent(GUIActivateEvent *event)
KParts::ReadWritePart::setReadWrite
virtual void setReadWrite(bool readwrite=true)
KParts::ReadWritePart::saveAs
virtual bool saveAs(const KURL &url)
KParts::ReadWritePart::closeURL
virtual bool closeURL()
KParts::ReadWritePart::save
virtual bool save()
KParts::ReadWritePart::setModified
virtual void setModified()
KTempFile
KURL
KURL::path
TQString path() const
KURL::directory
TQString directory(bool _strip_trailing_slash_from_result=true, bool _ignore_trailing_slash_in_path=true) const
KURL::fileName
TQString fileName(bool _ignore_trailing_slash_in_path=true) const
KURL::filename
TQString filename(bool _ignore_trailing_slash_in_path=true) const
KURL::isLocalFile
bool isLocalFile() const
KURL::prettyURL
TQString prettyURL(int _trailing=0) const
KURL::isValid
bool isValid() const
KWin::setIcons
static void setIcons(WId win, const TQPixmap &icon, const TQPixmap &miniIcon)
KXMLGUIFactory
KXMLGUIFactory::removeClient
void removeClient(KXMLGUIClient *client)
KXMLGUIFactory::addClient
void addClient(KXMLGUIClient *client)
KateArbitraryHighlight
An arbitrary highlighting interface for Kate.
Definition: katearbitraryhighlight.h:61
KateAutoIndent::modeNumber
virtual uint modeNumber() const
Mode index of this mode.
Definition: kateautoindent.h:185
KateAutoIndent::createIndenter
static KateAutoIndent * createIndenter(KateDocument *doc, uint mode)
Static methods to create and list indention modes.
Definition: kateautoindent.cpp:38
KateBrowserExtension
Interface for embedding KateDocument into a browser.
Definition: katedocumenthelpers.h:37
KateBuffer
The KateBuffer class maintains a collections of lines.
Definition: katebuffer.h:342
KateBuffer::setMaxLoadedBlocks
static void setMaxLoadedBlocks(uint count)
modifier for max loaded blocks limit
Definition: katebuffer.cpp:79
KateBuffer::maxLoadedBlocks
static uint maxLoadedBlocks()
maximal loaded block count
Definition: katebuffer.h:352
KateDocCursor
Cursor class with a pointer to its document.
Definition: katecursor.h:93
KateModOnHdPrompt
This dialog will prompt the user for what do with a file that is modified on disk.
Definition: katedialogs.h:371
KateSuperCursor
Possible additional features:
Definition: katesupercursor.h:46
KateSuperRange
Represents a range of text, from the start() to the end().
Definition: katesupercursor.h:169
KateTextCursor
Simple cursor class with no document pointer.
Definition: katecursor.h:34
KateTextLine
The KateTextLine represents a line of text.
Definition: katetextline.h:42
KateUndoGroup
Class to manage a group of undo items.
Definition: kateundo.h:34
KateUndoGroup::UndoType
UndoType
Types for undo items.
Definition: kateundo.h:63
Kate::Document
This interface provides access to the Kate Document class.
Definition: document.h:190
Kate::View
The Kate::View text editor interface.
Definition: view.h:45
TDEConfigBase::readEntry
TQString readEntry(const TQString &pKey, const TQString &aDefault=TQString::null) const
TDEConfigBase::readNumEntry
int readNumEntry(const TQString &pKey, int nDefault=0) const
TDEConfigBase::readIntListEntry
TQValueList< int > readIntListEntry(const TQString &pKey) const
TDEConfigBase::sync
virtual void sync()
TDEConfigBase::writeEntry
void writeEntry(const TQString &pKey, const TQString &pValue, bool bPersistent=true, bool bGlobal=false, bool bNLS=false)
TDEConfigBase::setGroup
void setGroup(const TQString &group)
TDEConfig
TDEGlobal::dirs
static TDEStandardDirs * dirs()
TDEIcon::SizeMedium
SizeMedium
TDESharedPtr
TDESharedPtr::count
int count() const
TDEStandardDirs::relativeLocation
TQString relativeLocation(const char *type, const TQString &absPath)
endl
kndbgstream & endl(kndbgstream &s)
kdDebug
kdbgstream kdDebug(int area=0)
flush
kndbgstream & flush(kndbgstream &s)
KNotifyClient::instance
TDEInstance * instance()
KStdAction::clear
TDEAction * clear(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
KStdAction::saveAs
TDEAction * saveAs(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)
Kate
Kate namespace All classes in this namespace must stay BC during one major release series (e....
Definition: document.h:51
TDEStdAccel::forward
const TDEShortcut & forward()
TDEStdAccel::key
int key(StdAccel id)
TDEStdAccel::name
TQString name(StdAccel id)
TDEStdAccel::end
const TDEShortcut & end()
TDEStdAccel::save
const TDEShortcut & save()
tdelocale.h

kate

Skip menu "kate"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kate

Skip menu "kate"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kate by doxygen 1.9.1
This website is maintained by Timothy Pearson.