kateviewhelpers.cpp
00001 /* This file is part of the KDE libraries 00002 Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org> 00003 Copyright (C) 2001 Anders Lund <anders@alweb.dk> 00004 Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org> 00005 00006 This library is free software; you can redistribute it and/or 00007 modify it under the terms of the GNU Library General Public 00008 License version 2 as published by the Free Software Foundation. 00009 00010 This library is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00013 Library General Public License for more details. 00014 00015 You should have received a copy of the GNU Library General Public License 00016 along with this library; see the file COPYING.LIB. If not, write to 00017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 00018 Boston, MA 02110-1301, USA. 00019 */ 00020 00021 #include "kateviewhelpers.h" 00022 #include "kateviewhelpers.moc" 00023 00024 #include "../interfaces/document.h" 00025 #include "../interfaces/katecmd.h" 00026 #include "kateattribute.h" 00027 #include "katecodefoldinghelpers.h" 00028 #include "kateconfig.h" 00029 #include "katedocument.h" 00030 #include "katefactory.h" 00031 #include "katerenderer.h" 00032 #include "kateview.h" 00033 #include "kateviewinternal.h" 00034 00035 #include <kapplication.h> 00036 #include <kglobalsettings.h> 00037 #include <klocale.h> 00038 #include <knotifyclient.h> 00039 #include <kglobal.h> 00040 #include <kcharsets.h> 00041 #include <kpopupmenu.h> 00042 00043 #include <tqcursor.h> 00044 #include <tqpainter.h> 00045 #include <tqpopupmenu.h> 00046 #include <tqstyle.h> 00047 #include <tqtimer.h> 00048 #include <tqwhatsthis.h> 00049 #include <tqregexp.h> 00050 #include <tqtextcodec.h> 00051 00052 #include <math.h> 00053 00054 #include <kdebug.h> 00055 00056 //BEGIN KateScrollBar 00057 KateScrollBar::KateScrollBar (Orientation orientation, KateViewInternal* parent, const char* name) 00058 : TQScrollBar (orientation, parent->m_view, name) 00059 , m_middleMouseDown (false) 00060 , m_view(parent->m_view) 00061 , m_doc(parent->m_doc) 00062 , m_viewInternal(parent) 00063 , m_topMargin(-1) 00064 , m_bottomMargin(-1) 00065 , m_savVisibleLines(0) 00066 , m_showMarks(false) 00067 { 00068 connect(this, TQT_SIGNAL(valueChanged(int)), TQT_SLOT(sliderMaybeMoved(int))); 00069 connect(m_doc, TQT_SIGNAL(marksChanged()), this, TQT_SLOT(marksChanged())); 00070 00071 m_lines.setAutoDelete(true); 00072 } 00073 00074 void KateScrollBar::mousePressEvent(TQMouseEvent* e) 00075 { 00076 if (e->button() == Qt::MidButton) 00077 m_middleMouseDown = true; 00078 00079 TQScrollBar::mousePressEvent(e); 00080 00081 redrawMarks(); 00082 } 00083 00084 void KateScrollBar::mouseReleaseEvent(TQMouseEvent* e) 00085 { 00086 TQScrollBar::mouseReleaseEvent(e); 00087 00088 m_middleMouseDown = false; 00089 00090 redrawMarks(); 00091 } 00092 00093 void KateScrollBar::mouseMoveEvent(TQMouseEvent* e) 00094 { 00095 TQScrollBar::mouseMoveEvent(e); 00096 00097 if (e->state() | Qt::LeftButton) 00098 redrawMarks(); 00099 } 00100 00101 void KateScrollBar::paintEvent(TQPaintEvent *e) 00102 { 00103 TQScrollBar::paintEvent(e); 00104 redrawMarks(); 00105 } 00106 00107 void KateScrollBar::resizeEvent(TQResizeEvent *e) 00108 { 00109 TQScrollBar::resizeEvent(e); 00110 recomputeMarksPositions(); 00111 } 00112 00113 void KateScrollBar::styleChange(TQStyle &s) 00114 { 00115 TQScrollBar::styleChange(s); 00116 m_topMargin = -1; 00117 recomputeMarksPositions(); 00118 } 00119 00120 void KateScrollBar::valueChange() 00121 { 00122 TQScrollBar::valueChange(); 00123 redrawMarks(); 00124 } 00125 00126 void KateScrollBar::rangeChange() 00127 { 00128 TQScrollBar::rangeChange(); 00129 recomputeMarksPositions(); 00130 } 00131 00132 void KateScrollBar::marksChanged() 00133 { 00134 recomputeMarksPositions(true); 00135 } 00136 00137 void KateScrollBar::redrawMarks() 00138 { 00139 if (!m_showMarks) 00140 return; 00141 00142 TQPainter painter(this); 00143 TQRect rect = sliderRect(); 00144 for (TQIntDictIterator<TQColor> it(m_lines); it.current(); ++it) 00145 { 00146 if (it.currentKey() < rect.top() || it.currentKey() > rect.bottom()) 00147 { 00148 painter.setPen(*it.current()); 00149 painter.drawLine(0, it.currentKey(), width(), it.currentKey()); 00150 } 00151 } 00152 } 00153 00154 void KateScrollBar::recomputeMarksPositions(bool forceFullUpdate) 00155 { 00156 if (m_topMargin == -1) 00157 watchScrollBarSize(); 00158 00159 m_lines.clear(); 00160 m_savVisibleLines = m_doc->visibleLines(); 00161 00162 int realHeight = frameGeometry().height() - m_topMargin - m_bottomMargin; 00163 00164 TQPtrList<KTextEditor::Mark> marks = m_doc->marks(); 00165 KateCodeFoldingTree *tree = m_doc->foldingTree(); 00166 00167 for (KTextEditor::Mark *mark = marks.first(); mark; mark = marks.next()) 00168 { 00169 uint line = mark->line; 00170 00171 if (tree) 00172 { 00173 KateCodeFoldingNode *node = tree->findNodeForLine(line); 00174 00175 while (node) 00176 { 00177 if (!node->isVisible()) 00178 line = tree->getStartLine(node); 00179 node = node->getParentNode(); 00180 } 00181 } 00182 00183 line = m_doc->getVirtualLine(line); 00184 00185 double d = (double)line / (m_savVisibleLines - 1); 00186 m_lines.insert(m_topMargin + (int)(d * realHeight), 00187 new TQColor(KateRendererConfig::global()->lineMarkerColor((KTextEditor::MarkInterface::MarkTypes)mark->type))); 00188 } 00189 00190 if (forceFullUpdate) 00191 update(); 00192 else 00193 redrawMarks(); 00194 } 00195 00196 void KateScrollBar::watchScrollBarSize() 00197 { 00198 int savMax = maxValue(); 00199 setMaxValue(0); 00200 TQRect rect = sliderRect(); 00201 setMaxValue(savMax); 00202 00203 m_topMargin = rect.top(); 00204 m_bottomMargin = frameGeometry().height() - rect.bottom(); 00205 } 00206 00207 void KateScrollBar::sliderMaybeMoved(int value) 00208 { 00209 if (m_middleMouseDown) 00210 emit sliderMMBMoved(value); 00211 } 00212 //END 00213 00214 //BEGIN KateCmdLnWhatsThis 00215 class KateCmdLnWhatsThis : public TQWhatsThis 00216 { 00217 public: 00218 KateCmdLnWhatsThis( KateCmdLine *parent ) 00219 : TQWhatsThis( parent ) 00220 , m_parent( parent ) {;} 00221 00222 TQString text( const TQPoint & ) 00223 { 00224 TQString beg = "<qt background=\"white\"><div><table width=\"100%\"><tr><td bgcolor=\"brown\"><font color=\"white\"><b>Help: <big>"; 00225 TQString mid = "</big></b></font></td></tr><tr><td>"; 00226 TQString end = "</td></tr></table></div><qt>"; 00227 00228 TQString t = m_parent->text(); 00229 TQRegExp re( "\\s*help\\s+(.*)" ); 00230 if ( re.search( t ) > -1 ) 00231 { 00232 TQString s; 00233 // get help for command 00234 TQString name = re.cap( 1 ); 00235 if ( name == "list" ) 00236 { 00237 return beg + i18n("Available Commands") + mid 00238 + KateCmd::self()->cmds().join(" ") 00239 + i18n("<p>For help on individual commands, do <code>'help <command>'</code></p>") 00240 + end; 00241 } 00242 else if ( ! name.isEmpty() ) 00243 { 00244 Kate::Command *cmd = KateCmd::self()->queryCommand( name ); 00245 if ( cmd ) 00246 { 00247 if ( cmd->help( (Kate::View*)m_parent->parentWidget(), name, s ) ) 00248 return beg + name + mid + s + end; 00249 else 00250 return beg + name + mid + i18n("No help for '%1'").arg( name ) + end; 00251 } 00252 else 00253 return beg + mid + i18n("No such command <b>%1</b>").arg(name) + end; 00254 } 00255 } 00256 00257 return beg + mid + i18n( 00258 "<p>This is the Katepart <b>command line</b>.<br>" 00259 "Syntax: <code><b>command [ arguments ]</b></code><br>" 00260 "For a list of available commands, enter <code><b>help list</b></code><br>" 00261 "For help for individual commands, enter <code><b>help <command></b></code></p>") 00262 + end; 00263 } 00264 00265 private: 00266 KateCmdLine *m_parent; 00267 }; 00268 //END KateCmdLnWhatsThis 00269 00270 //BEGIN KateCmdLineFlagCompletion 00275 class KateCmdLineFlagCompletion : public KCompletion 00276 { 00277 public: 00278 KateCmdLineFlagCompletion() {;} 00279 00280 TQString makeCompletion( const TQString & string ) 00281 { 00282 return TQString::null; 00283 } 00284 00285 }; 00286 //END KateCmdLineFlagCompletion 00287 00288 //BEGIN KateCmdLine 00289 KateCmdLine::KateCmdLine (KateView *view) 00290 : KLineEdit (view) 00291 , m_view (view) 00292 , m_msgMode (false) 00293 , m_histpos( 0 ) 00294 , m_cmdend( 0 ) 00295 , m_command( 0L ) 00296 , m_oldCompletionObject( 0L ) 00297 { 00298 connect (this, TQT_SIGNAL(returnPressed(const TQString &)), 00299 this, TQT_SLOT(slotReturnPressed(const TQString &))); 00300 00301 completionObject()->insertItems (KateCmd::self()->cmds()); 00302 setAutoDeleteCompletionObject( false ); 00303 m_help = new KateCmdLnWhatsThis( this ); 00304 } 00305 00306 void KateCmdLine::slotReturnPressed ( const TQString& text ) 00307 { 00308 00309 // silently ignore leading space 00310 uint n = 0; 00311 while( text[n].isSpace() ) 00312 n++; 00313 00314 TQString cmd = text.mid( n ); 00315 00316 // Built in help: if the command starts with "help", [try to] show some help 00317 if ( cmd.startsWith( "help" ) ) 00318 { 00319 m_help->display( m_help->text( TQPoint() ), mapToGlobal(TQPoint(0,0)) ); 00320 clear(); 00321 KateCmd::self()->appendHistory( cmd ); 00322 m_histpos = KateCmd::self()->historyLength(); 00323 m_oldText = TQString (); 00324 return; 00325 } 00326 00327 if (cmd.length () > 0) 00328 { 00329 Kate::Command *p = KateCmd::self()->queryCommand (cmd); 00330 00331 m_oldText = cmd; 00332 m_msgMode = true; 00333 00334 if (p) 00335 { 00336 TQString msg; 00337 00338 if (p->exec (m_view, cmd, msg)) 00339 { 00340 KateCmd::self()->appendHistory( cmd ); 00341 m_histpos = KateCmd::self()->historyLength(); 00342 m_oldText = TQString (); 00343 00344 if (msg.length() > 0) 00345 setText (i18n ("Success: ") + msg); 00346 else 00347 setText (i18n ("Success")); 00348 } 00349 else 00350 { 00351 if (msg.length() > 0) 00352 setText (i18n ("Error: ") + msg); 00353 else 00354 setText (i18n ("Command \"%1\" failed.").arg (cmd)); 00355 KNotifyClient::beep(); 00356 } 00357 } 00358 else 00359 { 00360 setText (i18n ("No such command: \"%1\"").arg (cmd)); 00361 KNotifyClient::beep(); 00362 } 00363 } 00364 00365 // clean up 00366 if ( m_oldCompletionObject ) 00367 { 00368 KCompletion *c = completionObject(); 00369 setCompletionObject( m_oldCompletionObject ); 00370 m_oldCompletionObject = 0; 00371 delete c; 00372 c = 0; 00373 } 00374 m_command = 0; 00375 m_cmdend = 0; 00376 00377 m_view->setFocus (); 00378 TQTimer::singleShot( 4000, this, TQT_SLOT(hideMe()) ); 00379 } 00380 00381 void KateCmdLine::hideMe () // unless i have focus ;) 00382 { 00383 if ( isVisibleTo(parentWidget()) && ! hasFocus() ) { 00384 m_view->toggleCmdLine (); 00385 } 00386 } 00387 00388 void KateCmdLine::focusInEvent ( TQFocusEvent *ev ) 00389 { 00390 if (m_msgMode) 00391 { 00392 m_msgMode = false; 00393 setText (m_oldText); 00394 selectAll(); 00395 } 00396 00397 KLineEdit::focusInEvent (ev); 00398 } 00399 00400 void KateCmdLine::keyPressEvent( TQKeyEvent *ev ) 00401 { 00402 if (ev->key() == Key_Escape) 00403 { 00404 m_view->setFocus (); 00405 hideMe(); 00406 } 00407 else if ( ev->key() == Key_Up ) 00408 fromHistory( true ); 00409 else if ( ev->key() == Key_Down ) 00410 fromHistory( false ); 00411 00412 uint cursorpos = cursorPosition(); 00413 KLineEdit::keyPressEvent (ev); 00414 00415 // during typing, let us see if we have a valid command 00416 if ( ! m_cmdend || cursorpos <= m_cmdend ) 00417 { 00418 TQChar c; 00419 if ( ! ev->text().isEmpty() ) 00420 c = ev->text()[0]; 00421 00422 if ( ! m_cmdend && ! c.isNull() ) // we have no command, so lets see if we got one 00423 { 00424 if ( ! c.isLetterOrNumber() && c != '-' && c != '_' ) 00425 { 00426 m_command = KateCmd::self()->queryCommand( text().stripWhiteSpace() ); 00427 if ( m_command ) 00428 { 00429 //kdDebug(13025)<<"keypress in commandline: We have a command! "<<m_command<<". text is '"<<text()<<"'"<<endl; 00430 // if the typed character is ":", 00431 // we try if the command has flag completions 00432 m_cmdend = cursorpos; 00433 //kdDebug(13025)<<"keypress in commandline: Set m_cmdend to "<<m_cmdend<<endl; 00434 } 00435 else 00436 m_cmdend = 0; 00437 } 00438 } 00439 else // since cursor is inside the command name, we reconsider it 00440 { 00441 kdDebug(13025)<<"keypress in commandline: \\W -- text is "<<text()<<endl; 00442 m_command = KateCmd::self()->queryCommand( text().stripWhiteSpace() ); 00443 if ( m_command ) 00444 { 00445 //kdDebug(13025)<<"keypress in commandline: We have a command! "<<m_command<<endl; 00446 TQString t = text(); 00447 m_cmdend = 0; 00448 bool b = false; 00449 for ( ; m_cmdend < t.length(); m_cmdend++ ) 00450 { 00451 if ( t[m_cmdend].isLetter() ) 00452 b = true; 00453 if ( b && ( ! t[m_cmdend].isLetterOrNumber() && t[m_cmdend] != '-' && t[m_cmdend] != '_' ) ) 00454 break; 00455 } 00456 00457 if ( c == ':' && cursorpos == m_cmdend ) 00458 { 00459 // check if this command wants to complete flags 00460 //kdDebug(13025)<<"keypress in commandline: Checking if flag completion is desired!"<<endl; 00461 } 00462 } 00463 else 00464 { 00465 // clean up if needed 00466 if ( m_oldCompletionObject ) 00467 { 00468 KCompletion *c = completionObject(); 00469 setCompletionObject( m_oldCompletionObject ); 00470 m_oldCompletionObject = 0; 00471 delete c; 00472 c = 0; 00473 } 00474 00475 m_cmdend = 0; 00476 } 00477 } 00478 00479 // if we got a command, check if it wants to do semething. 00480 if ( m_command ) 00481 { 00482 //kdDebug(13025)<<"Checking for CommandExtension.."<<endl; 00483 Kate::CommandExtension *ce = dynamic_cast<Kate::CommandExtension*>(m_command); 00484 if ( ce ) 00485 { 00486 KCompletion *cmpl = ce->completionObject( text().left( m_cmdend ).stripWhiteSpace(), m_view ); 00487 if ( cmpl ) 00488 { 00489 // save the old completion object and use what the command provides 00490 // instead. We also need to prepend the current command name + flag string 00491 // when completion is done 00492 //kdDebug(13025)<<"keypress in commandline: Setting completion object!"<<endl; 00493 if ( ! m_oldCompletionObject ) 00494 m_oldCompletionObject = completionObject(); 00495 00496 setCompletionObject( cmpl ); 00497 } 00498 } 00499 } 00500 } 00501 else if ( m_command )// check if we should call the commands processText() 00502 { 00503 Kate::CommandExtension *ce = dynamic_cast<Kate::CommandExtension*>( m_command ); 00504 if ( ce && ce->wantsToProcessText( text().left( m_cmdend ).stripWhiteSpace() ) 00505 && ! ( ev->text().isNull() || ev->text().isEmpty() ) ) 00506 ce->processText( m_view, text() ); 00507 } 00508 } 00509 00510 void KateCmdLine::fromHistory( bool up ) 00511 { 00512 if ( ! KateCmd::self()->historyLength() ) 00513 return; 00514 00515 TQString s; 00516 00517 if ( up ) 00518 { 00519 if ( m_histpos > 0 ) 00520 { 00521 m_histpos--; 00522 s = KateCmd::self()->fromHistory( m_histpos ); 00523 } 00524 } 00525 else 00526 { 00527 if ( m_histpos < ( KateCmd::self()->historyLength() - 1 ) ) 00528 { 00529 m_histpos++; 00530 s = KateCmd::self()->fromHistory( m_histpos ); 00531 } 00532 else 00533 { 00534 m_histpos = KateCmd::self()->historyLength(); 00535 setText( m_oldText ); 00536 } 00537 } 00538 if ( ! s.isEmpty() ) 00539 { 00540 // Select the argument part of the command, so that it is easy to overwrite 00541 setText( s ); 00542 static TQRegExp reCmd = TQRegExp(".*[\\w\\-]+(?:[^a-zA-Z0-9_-]|:\\w+)(.*)"); 00543 if ( reCmd.search( text() ) == 0 ) 00544 setSelection( text().length() - reCmd.cap(1).length(), reCmd.cap(1).length() ); 00545 } 00546 } 00547 //END KateCmdLine 00548 00549 //BEGIN KateIconBorder 00550 using namespace KTextEditor; 00551 00552 static const char* const plus_xpm[] = { 00553 "11 11 3 1", 00554 " c None", 00555 ". c #000000", 00556 "+ c #FFFFFF", 00557 "...........", 00558 ".+++++++++.", 00559 ".+++++++++.", 00560 ".++++.++++.", 00561 ".++++.++++.", 00562 ".++.....++.", 00563 ".++++.++++.", 00564 ".++++.++++.", 00565 ".+++++++++.", 00566 ".+++++++++.", 00567 "..........."}; 00568 00569 static const char* const minus_xpm[] = { 00570 "11 11 3 1", 00571 " c None", 00572 ". c #000000", 00573 "+ c #FFFFFF", 00574 "...........", 00575 ".+++++++++.", 00576 ".+++++++++.", 00577 ".+++++++++.", 00578 ".+++++++++.", 00579 ".++.....++.", 00580 ".+++++++++.", 00581 ".+++++++++.", 00582 ".+++++++++.", 00583 ".+++++++++.", 00584 "..........."}; 00585 00586 static const char * const bookmark_xpm[] = { 00587 "14 13 82 1", 00588 " c None", 00589 ". c #F27D01", 00590 "+ c #EF7901", 00591 "@ c #F3940F", 00592 "# c #EE8F12", 00593 "$ c #F9C834", 00594 "% c #F5C33A", 00595 "& c #F09110", 00596 "* c #FCEE3E", 00597 "= c #FBEB3F", 00598 "- c #E68614", 00599 "; c #FA8700", 00600 "> c #F78703", 00601 ", c #F4920E", 00602 "' c #F19113", 00603 ") c #F6C434", 00604 "! c #FDF938", 00605 "~ c #FDF839", 00606 "{ c #F1BC3A", 00607 "] c #E18017", 00608 "^ c #DA7210", 00609 "/ c #D5680B", 00610 "( c #CA5404", 00611 "_ c #FD8F06", 00612 ": c #FCB62D", 00613 "< c #FDE049", 00614 "[ c #FCE340", 00615 "} c #FBE334", 00616 "| c #FDF035", 00617 "1 c #FEF834", 00618 "2 c #FCEF36", 00619 "3 c #F8DF32", 00620 "4 c #F7DC3D", 00621 "5 c #F5CE3E", 00622 "6 c #DE861B", 00623 "7 c #C64C03", 00624 "8 c #F78C07", 00625 "9 c #F8B019", 00626 "0 c #FDE12D", 00627 "a c #FEE528", 00628 "b c #FEE229", 00629 "c c #FBD029", 00630 "d c #E18814", 00631 "e c #CB5605", 00632 "f c #EF8306", 00633 "g c #F3A00E", 00634 "h c #FBC718", 00635 "i c #FED31C", 00636 "j c #FED11D", 00637 "k c #F8B91C", 00638 "l c #E07D0D", 00639 "m c #CB5301", 00640 "n c #ED8A0E", 00641 "o c #F7A90D", 00642 "p c #FEC113", 00643 "q c #FEC013", 00644 "r c #F09B0E", 00645 "s c #D35E03", 00646 "t c #EF9213", 00647 "u c #F9A208", 00648 "v c #FEAA0C", 00649 "w c #FCA10B", 00650 "x c #FCA70B", 00651 "y c #FEAF0B", 00652 "z c #F39609", 00653 "A c #D86203", 00654 "B c #F08C0D", 00655 "C c #FA9004", 00656 "D c #F17F04", 00657 "E c #E36D04", 00658 "F c #E16F03", 00659 "G c #EE8304", 00660 "H c #F88C04", 00661 "I c #DC6202", 00662 "J c #E87204", 00663 "K c #E66A01", 00664 "L c #DC6001", 00665 "M c #D15601", 00666 "N c #DA5D01", 00667 "O c #D25200", 00668 "P c #DA5F00", 00669 "Q c #BC3C00", 00670 " .+ ", 00671 " @# ", 00672 " $% ", 00673 " &*=- ", 00674 " ;>,')!~{]^/( ", 00675 "_:<[}|11234567", 00676 " 890aaaaabcde ", 00677 " fghiiijklm ", 00678 " nopqpqrs ", 00679 " tuvwxyzA ", 00680 " BCDEFGHI ", 00681 " JKL MNO ", 00682 " P Q "}; 00683 00684 const int iconPaneWidth = 16; 00685 const int halfIPW = 8; 00686 00687 KateIconBorder::KateIconBorder ( KateViewInternal* internalView, TQWidget *parent ) 00688 : TQWidget(parent, "", (WFlags)(WStaticContents | WRepaintNoErase | WResizeNoErase) ) 00689 , m_view( internalView->m_view ) 00690 , m_doc( internalView->m_doc ) 00691 , m_viewInternal( internalView ) 00692 , m_iconBorderOn( false ) 00693 , m_lineNumbersOn( false ) 00694 , m_foldingMarkersOn( false ) 00695 , m_dynWrapIndicatorsOn( false ) 00696 , m_dynWrapIndicators( 0 ) 00697 , m_cachedLNWidth( 0 ) 00698 , m_maxCharWidth( 0 ) 00699 { 00700 setSizePolicy( TQSizePolicy( TQSizePolicy::Fixed, TQSizePolicy::Minimum ) ); 00701 00702 setBackgroundMode( NoBackground ); 00703 00704 m_doc->setDescription( MarkInterface::markType01, i18n("Bookmark") ); 00705 m_doc->setPixmap( MarkInterface::markType01, TQPixmap((const char**)bookmark_xpm) ); 00706 00707 updateFont(); 00708 } 00709 00710 void KateIconBorder::setIconBorderOn( bool enable ) 00711 { 00712 if( enable == m_iconBorderOn ) 00713 return; 00714 00715 m_iconBorderOn = enable; 00716 00717 updateGeometry(); 00718 00719 TQTimer::singleShot( 0, this, TQT_SLOT(update()) ); 00720 } 00721 00722 void KateIconBorder::setLineNumbersOn( bool enable ) 00723 { 00724 if( enable == m_lineNumbersOn ) 00725 return; 00726 00727 m_lineNumbersOn = enable; 00728 m_dynWrapIndicatorsOn = (m_dynWrapIndicators == 1) ? enable : m_dynWrapIndicators; 00729 00730 updateGeometry(); 00731 00732 TQTimer::singleShot( 0, this, TQT_SLOT(update()) ); 00733 } 00734 00735 void KateIconBorder::setDynWrapIndicators( int state ) 00736 { 00737 if (state == m_dynWrapIndicators ) 00738 return; 00739 00740 m_dynWrapIndicators = state; 00741 m_dynWrapIndicatorsOn = (state == 1) ? m_lineNumbersOn : state; 00742 00743 updateGeometry (); 00744 00745 TQTimer::singleShot( 0, this, TQT_SLOT(update()) ); 00746 } 00747 00748 void KateIconBorder::setFoldingMarkersOn( bool enable ) 00749 { 00750 if( enable == m_foldingMarkersOn ) 00751 return; 00752 00753 m_foldingMarkersOn = enable; 00754 00755 updateGeometry(); 00756 00757 TQTimer::singleShot( 0, this, TQT_SLOT(update()) ); 00758 } 00759 00760 TQSize KateIconBorder::sizeHint() const 00761 { 00762 int w = 0; 00763 00764 if (m_iconBorderOn) 00765 w += iconPaneWidth + 1; 00766 00767 if (m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn)) { 00768 w += lineNumberWidth(); 00769 } 00770 00771 if (m_foldingMarkersOn) 00772 w += iconPaneWidth; 00773 00774 w += 4; 00775 00776 return TQSize( w, 0 ); 00777 } 00778 00779 // This function (re)calculates the maximum width of any of the digit characters (0 -> 9) 00780 // for graceful handling of variable-width fonts as the linenumber font. 00781 void KateIconBorder::updateFont() 00782 { 00783 const TQFontMetrics *fm = m_view->renderer()->config()->fontMetrics(); 00784 m_maxCharWidth = 0; 00785 // Loop to determine the widest numeric character in the current font. 00786 // 48 is ascii '0' 00787 for (int i = 48; i < 58; i++) { 00788 int charWidth = fm->width( TQChar(i) ); 00789 m_maxCharWidth = kMax(m_maxCharWidth, charWidth); 00790 } 00791 } 00792 00793 int KateIconBorder::lineNumberWidth() const 00794 { 00795 int width = m_lineNumbersOn ? ((int)log10((double)(m_view->doc()->numLines())) + 1) * m_maxCharWidth + 4 : 0; 00796 00797 if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) { 00798 width = kMax(style().scrollBarExtent().width() + 4, width); 00799 00800 if (m_cachedLNWidth != width || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) { 00801 int w = style().scrollBarExtent().width(); 00802 int h = m_view->renderer()->config()->fontMetrics()->height(); 00803 00804 TQSize newSize(w, h); 00805 if ((m_arrow.size() != newSize || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) && !newSize.isEmpty()) { 00806 m_arrow.resize(newSize); 00807 00808 TQPainter p(&m_arrow); 00809 p.fillRect( 0, 0, w, h, m_view->renderer()->config()->iconBarColor() ); 00810 00811 h = m_view->renderer()->config()->fontMetrics()->ascent(); 00812 00813 p.setPen(m_view->renderer()->attribute(0)->textColor()); 00814 p.drawLine(w/2, h/2, w/2, 0); 00815 #if 1 00816 p.lineTo(w/4, h/4); 00817 p.lineTo(0, 0); 00818 p.lineTo(0, h/2); 00819 p.lineTo(w/2, h-1); 00820 p.lineTo(w*3/4, h-1); 00821 p.lineTo(w-1, h*3/4); 00822 p.lineTo(w*3/4, h/2); 00823 p.lineTo(0, h/2); 00824 #else 00825 p.lineTo(w*3/4, h/4); 00826 p.lineTo(w-1,0); 00827 p.lineTo(w-1, h/2); 00828 p.lineTo(w/2, h-1); 00829 p.lineTo(w/4,h-1); 00830 p.lineTo(0, h*3/4); 00831 p.lineTo(w/4, h/2); 00832 p.lineTo(w-1, h/2); 00833 #endif 00834 } 00835 } 00836 } 00837 00838 return width; 00839 } 00840 00841 void KateIconBorder::paintEvent(TQPaintEvent* e) 00842 { 00843 paintBorder(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height()); 00844 } 00845 00846 void KateIconBorder::paintBorder (int /*x*/, int y, int /*width*/, int height) 00847 { 00848 static TQPixmap minus_px ((const char**)minus_xpm); 00849 static TQPixmap plus_px ((const char**)plus_xpm); 00850 00851 uint h = m_view->renderer()->config()->fontStruct()->fontHeight; 00852 uint startz = (y / h); 00853 uint endz = startz + 1 + (height / h); 00854 uint lineRangesSize = m_viewInternal->lineRanges.size(); 00855 00856 // center the folding boxes 00857 int m_px = (h - 11) / 2; 00858 if (m_px < 0) 00859 m_px = 0; 00860 00861 int lnWidth( 0 ); 00862 if ( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) ) // avoid calculating unless needed ;-) 00863 { 00864 lnWidth = lineNumberWidth(); 00865 if ( lnWidth != m_cachedLNWidth || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor() ) 00866 { 00867 // we went from n0 ->n9 lines or vice verca 00868 // this causes an extra updateGeometry() first time the line numbers 00869 // are displayed, but sizeHint() is supposed to be const so we can't set 00870 // the cached value there. 00871 m_cachedLNWidth = lnWidth; 00872 m_oldBackgroundColor = m_view->renderer()->config()->iconBarColor(); 00873 updateGeometry(); 00874 update (); 00875 return; 00876 } 00877 } 00878 00879 int w( this->width() ); // sane value/calc only once 00880 00881 TQPainter p ( this ); 00882 p.setFont ( *m_view->renderer()->config()->font() ); // for line numbers 00883 // the line number color is for the line numbers, vertical separator lines 00884 // and for for the code folding lines. 00885 p.setPen ( m_view->renderer()->config()->lineNumberColor() ); 00886 00887 KateLineInfo oldInfo; 00888 if (startz < lineRangesSize) 00889 { 00890 if ((m_viewInternal->lineRanges[startz].line-1) < 0) 00891 oldInfo.topLevel = true; 00892 else 00893 m_doc->lineInfo(&oldInfo,m_viewInternal->lineRanges[startz].line-1); 00894 } 00895 00896 for (uint z=startz; z <= endz; z++) 00897 { 00898 int y = h * z; 00899 int realLine = -1; 00900 00901 if (z < lineRangesSize) 00902 realLine = m_viewInternal->lineRanges[z].line; 00903 00904 int lnX ( 0 ); 00905 00906 p.fillRect( 0, y, w-4, h, m_view->renderer()->config()->iconBarColor() ); 00907 p.fillRect( w-4, y, 4, h, m_view->renderer()->config()->backgroundColor() ); 00908 00909 // icon pane 00910 if( m_iconBorderOn ) 00911 { 00912 p.drawLine(lnX+iconPaneWidth, y, lnX+iconPaneWidth, y+h); 00913 00914 if( (realLine > -1) && (m_viewInternal->lineRanges[z].startCol == 0) ) 00915 { 00916 uint mrk ( m_doc->mark( realLine ) ); // call only once 00917 00918 if ( mrk ) 00919 { 00920 for( uint bit = 0; bit < 32; bit++ ) 00921 { 00922 MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit); 00923 if( mrk & markType ) 00924 { 00925 TQPixmap *px_mark (m_doc->markPixmap( markType )); 00926 00927 if (px_mark) 00928 { 00929 // center the mark pixmap 00930 int x_px = (iconPaneWidth - px_mark->width()) / 2; 00931 if (x_px < 0) 00932 x_px = 0; 00933 00934 int y_px = (h - px_mark->height()) / 2; 00935 if (y_px < 0) 00936 y_px = 0; 00937 00938 p.drawPixmap( lnX+x_px, y+y_px, *px_mark); 00939 } 00940 } 00941 } 00942 } 00943 } 00944 00945 lnX += iconPaneWidth + 1; 00946 } 00947 00948 // line number 00949 if( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) ) 00950 { 00951 lnX +=2; 00952 00953 if (realLine > -1) 00954 if (m_viewInternal->lineRanges[z].startCol == 0) { 00955 if (m_lineNumbersOn) 00956 p.drawText( lnX + 1, y, lnWidth-4, h, Qt::AlignRight|Qt::AlignVCenter, TQString("%1").arg( realLine + 1 ) ); 00957 } else if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) { 00958 p.drawPixmap(lnX + lnWidth - m_arrow.width() - 4, y, m_arrow); 00959 } 00960 00961 lnX += lnWidth; 00962 } 00963 00964 // folding markers 00965 if( m_foldingMarkersOn ) 00966 { 00967 if( realLine > -1 ) 00968 { 00969 KateLineInfo info; 00970 m_doc->lineInfo(&info,realLine); 00971 00972 if (!info.topLevel) 00973 { 00974 if (info.startsVisibleBlock && (m_viewInternal->lineRanges[z].startCol == 0)) 00975 { 00976 if (oldInfo.topLevel) 00977 p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1); 00978 else 00979 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); 00980 00981 p.drawPixmap(lnX+3,y+m_px,minus_px); 00982 } 00983 else if (info.startsInVisibleBlock) 00984 { 00985 if (m_viewInternal->lineRanges[z].startCol == 0) 00986 { 00987 if (oldInfo.topLevel) 00988 p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1); 00989 else 00990 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); 00991 00992 p.drawPixmap(lnX+3,y+m_px,plus_px); 00993 } 00994 else 00995 { 00996 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); 00997 } 00998 00999 if (!m_viewInternal->lineRanges[z].wrap) 01000 p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1); 01001 } 01002 else 01003 { 01004 p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1); 01005 01006 if (info.endsBlock && !m_viewInternal->lineRanges[z].wrap) 01007 p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1); 01008 } 01009 } 01010 01011 oldInfo = info; 01012 } 01013 01014 lnX += iconPaneWidth; 01015 } 01016 } 01017 } 01018 01019 KateIconBorder::BorderArea KateIconBorder::positionToArea( const TQPoint& p ) const 01020 { 01021 int x = 0; 01022 if( m_iconBorderOn ) { 01023 x += iconPaneWidth; 01024 if( p.x() <= x ) 01025 return IconBorder; 01026 } 01027 if( m_lineNumbersOn || m_dynWrapIndicators ) { 01028 x += lineNumberWidth(); 01029 if( p.x() <= x ) 01030 return LineNumbers; 01031 } 01032 if( m_foldingMarkersOn ) { 01033 x += iconPaneWidth; 01034 if( p.x() <= x ) 01035 return FoldingMarkers; 01036 } 01037 return None; 01038 } 01039 01040 void KateIconBorder::mousePressEvent( TQMouseEvent* e ) 01041 { 01042 m_lastClickedLine = m_viewInternal->yToKateLineRange(e->y()).line; 01043 01044 if ( positionToArea( e->pos() ) != IconBorder ) 01045 { 01046 TQMouseEvent forward( TQEvent::MouseButtonPress, 01047 TQPoint( 0, e->y() ), e->button(), e->state() ); 01048 m_viewInternal->mousePressEvent( &forward ); 01049 } 01050 e->accept(); 01051 } 01052 01053 void KateIconBorder::mouseMoveEvent( TQMouseEvent* e ) 01054 { 01055 if ( positionToArea( e->pos() ) != IconBorder ) 01056 { 01057 TQMouseEvent forward( TQEvent::MouseMove, 01058 TQPoint( 0, e->y() ), e->button(), e->state() ); 01059 m_viewInternal->mouseMoveEvent( &forward ); 01060 } 01061 } 01062 01063 void KateIconBorder::mouseReleaseEvent( TQMouseEvent* e ) 01064 { 01065 uint cursorOnLine = m_viewInternal->yToKateLineRange(e->y()).line; 01066 01067 if (cursorOnLine == m_lastClickedLine && 01068 cursorOnLine <= m_doc->lastLine() ) 01069 { 01070 BorderArea area = positionToArea( e->pos() ); 01071 if( area == IconBorder) { 01072 if (e->button() == Qt::LeftButton) { 01073 if( m_doc->editableMarks() & KateViewConfig::global()->defaultMarkType() ) { 01074 if( m_doc->mark( cursorOnLine ) & KateViewConfig::global()->defaultMarkType() ) 01075 m_doc->removeMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() ); 01076 else 01077 m_doc->addMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() ); 01078 } else { 01079 showMarkMenu( cursorOnLine, TQCursor::pos() ); 01080 } 01081 } 01082 else 01083 if (e->button() == Qt::RightButton) { 01084 showMarkMenu( cursorOnLine, TQCursor::pos() ); 01085 } 01086 } 01087 01088 if ( area == FoldingMarkers) { 01089 KateLineInfo info; 01090 m_doc->lineInfo(&info,cursorOnLine); 01091 if ((info.startsVisibleBlock) || (info.startsInVisibleBlock)) { 01092 emit toggleRegionVisibility(cursorOnLine); 01093 } 01094 } 01095 } 01096 01097 TQMouseEvent forward( TQEvent::MouseButtonRelease, 01098 TQPoint( 0, e->y() ), e->button(), e->state() ); 01099 m_viewInternal->mouseReleaseEvent( &forward ); 01100 } 01101 01102 void KateIconBorder::mouseDoubleClickEvent( TQMouseEvent* e ) 01103 { 01104 TQMouseEvent forward( TQEvent::MouseButtonDblClick, 01105 TQPoint( 0, e->y() ), e->button(), e->state() ); 01106 m_viewInternal->mouseDoubleClickEvent( &forward ); 01107 } 01108 01109 void KateIconBorder::showMarkMenu( uint line, const TQPoint& pos ) 01110 { 01111 TQPopupMenu markMenu; 01112 TQPopupMenu selectDefaultMark; 01113 01114 typedef TQValueVector<int> MarkTypeVector; 01115 MarkTypeVector vec( 33 ); 01116 int i=1; 01117 01118 for( uint bit = 0; bit < 32; bit++ ) { 01119 MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit); 01120 if( !(m_doc->editableMarks() & markType) ) 01121 continue; 01122 01123 if( !m_doc->markDescription( markType ).isEmpty() ) { 01124 markMenu.insertItem( m_doc->markDescription( markType ), i ); 01125 selectDefaultMark.insertItem( m_doc->markDescription( markType ), i+100); 01126 } else { 01127 markMenu.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i ); 01128 selectDefaultMark.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i+100); 01129 } 01130 01131 if( m_doc->mark( line ) & markType ) 01132 markMenu.setItemChecked( i, true ); 01133 01134 if( markType & KateViewConfig::global()->defaultMarkType() ) 01135 selectDefaultMark.setItemChecked( i+100, true ); 01136 01137 vec[i++] = markType; 01138 } 01139 01140 if( markMenu.count() == 0 ) 01141 return; 01142 01143 if( markMenu.count() > 1 ) 01144 markMenu.insertItem( i18n("Set Default Mark Type" ), &selectDefaultMark); 01145 01146 int result = markMenu.exec( pos ); 01147 if( result <= 0 ) 01148 return; 01149 01150 if ( result > 100) 01151 { 01152 KateViewConfig::global()->setDefaultMarkType (vec[result-100]); 01153 // flush config, otherwise it isn't nessecarily done 01154 KConfig *config = kapp->config(); 01155 config->setGroup("Kate View Defaults"); 01156 KateViewConfig::global()->writeConfig( config ); 01157 } 01158 else 01159 { 01160 MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes) vec[result]; 01161 if( m_doc->mark( line ) & markType ) { 01162 m_doc->removeMark( line, markType ); 01163 } else { 01164 m_doc->addMark( line, markType ); 01165 } 01166 } 01167 } 01168 //END KateIconBorder 01169 01170 KateViewEncodingAction::KateViewEncodingAction(KateDocument *_doc, KateView *_view, const TQString& text, TQObject* parent, const char* name) 01171 : KActionMenu (text, parent, name), doc(_doc), view (_view) 01172 { 01173 connect(popupMenu(),TQT_SIGNAL(aboutToShow()),this,TQT_SLOT(slotAboutToShow())); 01174 } 01175 01176 void KateViewEncodingAction::slotAboutToShow() 01177 { 01178 TQStringList modes (KGlobal::charsets()->descriptiveEncodingNames()); 01179 01180 popupMenu()->clear (); 01181 for (uint z=0; z<modes.size(); ++z) 01182 { 01183 popupMenu()->insertItem ( modes[z], this, TQT_SLOT(setMode(int)), 0, z); 01184 01185 bool found = false; 01186 TQTextCodec *codecForEnc = KGlobal::charsets()->codecForName(KGlobal::charsets()->encodingForName(modes[z]), found); 01187 01188 if (found && codecForEnc) 01189 { 01190 if (codecForEnc->name() == doc->config()->codec()->name()) 01191 popupMenu()->setItemChecked (z, true); 01192 } 01193 } 01194 } 01195 01196 void KateViewEncodingAction::setMode (int mode) 01197 { 01198 TQStringList modes (KGlobal::charsets()->descriptiveEncodingNames()); 01199 doc->config()->setEncoding( KGlobal::charsets()->encodingForName( modes[mode] ) ); 01200 // now we don't want the encoding changed again unless the user does so using the menu. 01201 doc->setEncodingSticky( true ); 01202 doc->reloadFile(); 01203 } 01204 01205 // kate: space-indent on; indent-width 2; replace-tabs on;