summaryrefslogtreecommitdiffstats
path: root/kate/part/kateviewhelpers.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kate/part/kateviewhelpers.cpp')
-rw-r--r--kate/part/kateviewhelpers.cpp1205
1 files changed, 1205 insertions, 0 deletions
diff --git a/kate/part/kateviewhelpers.cpp b/kate/part/kateviewhelpers.cpp
new file mode 100644
index 000000000..4ca753486
--- /dev/null
+++ b/kate/part/kateviewhelpers.cpp
@@ -0,0 +1,1205 @@
+/* This file is part of the KDE libraries
+ Copyright (C) 2002 John Firebaugh <jfirebaugh@kde.org>
+ Copyright (C) 2001 Anders Lund <anders@alweb.dk>
+ Copyright (C) 2001 Christoph Cullmann <cullmann@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License version 2 as published by the Free Software Foundation.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "kateviewhelpers.h"
+#include "kateviewhelpers.moc"
+
+#include "../interfaces/document.h"
+#include "../interfaces/katecmd.h"
+#include "kateattribute.h"
+#include "katecodefoldinghelpers.h"
+#include "kateconfig.h"
+#include "katedocument.h"
+#include "katefactory.h"
+#include "katerenderer.h"
+#include "kateview.h"
+#include "kateviewinternal.h"
+
+#include <kapplication.h>
+#include <kglobalsettings.h>
+#include <klocale.h>
+#include <knotifyclient.h>
+#include <kglobal.h>
+#include <kcharsets.h>
+#include <kpopupmenu.h>
+
+#include <qcursor.h>
+#include <qpainter.h>
+#include <qpopupmenu.h>
+#include <qstyle.h>
+#include <qtimer.h>
+#include <qwhatsthis.h>
+#include <qregexp.h>
+#include <qtextcodec.h>
+
+#include <math.h>
+
+#include <kdebug.h>
+
+//BEGIN KateScrollBar
+KateScrollBar::KateScrollBar (Orientation orientation, KateViewInternal* parent, const char* name)
+ : QScrollBar (orientation, parent->m_view, name)
+ , m_middleMouseDown (false)
+ , m_view(parent->m_view)
+ , m_doc(parent->m_doc)
+ , m_viewInternal(parent)
+ , m_topMargin(-1)
+ , m_bottomMargin(-1)
+ , m_savVisibleLines(0)
+ , m_showMarks(false)
+{
+ connect(this, SIGNAL(valueChanged(int)), SLOT(sliderMaybeMoved(int)));
+ connect(m_doc, SIGNAL(marksChanged()), this, SLOT(marksChanged()));
+
+ m_lines.setAutoDelete(true);
+}
+
+void KateScrollBar::mousePressEvent(QMouseEvent* e)
+{
+ if (e->button() == MidButton)
+ m_middleMouseDown = true;
+
+ QScrollBar::mousePressEvent(e);
+
+ redrawMarks();
+}
+
+void KateScrollBar::mouseReleaseEvent(QMouseEvent* e)
+{
+ QScrollBar::mouseReleaseEvent(e);
+
+ m_middleMouseDown = false;
+
+ redrawMarks();
+}
+
+void KateScrollBar::mouseMoveEvent(QMouseEvent* e)
+{
+ QScrollBar::mouseMoveEvent(e);
+
+ if (e->state() | LeftButton)
+ redrawMarks();
+}
+
+void KateScrollBar::paintEvent(QPaintEvent *e)
+{
+ QScrollBar::paintEvent(e);
+ redrawMarks();
+}
+
+void KateScrollBar::resizeEvent(QResizeEvent *e)
+{
+ QScrollBar::resizeEvent(e);
+ recomputeMarksPositions();
+}
+
+void KateScrollBar::styleChange(QStyle &s)
+{
+ QScrollBar::styleChange(s);
+ m_topMargin = -1;
+ recomputeMarksPositions();
+}
+
+void KateScrollBar::valueChange()
+{
+ QScrollBar::valueChange();
+ redrawMarks();
+}
+
+void KateScrollBar::rangeChange()
+{
+ QScrollBar::rangeChange();
+ recomputeMarksPositions();
+}
+
+void KateScrollBar::marksChanged()
+{
+ recomputeMarksPositions(true);
+}
+
+void KateScrollBar::redrawMarks()
+{
+ if (!m_showMarks)
+ return;
+
+ QPainter painter(this);
+ QRect rect = sliderRect();
+ for (QIntDictIterator<QColor> it(m_lines); it.current(); ++it)
+ {
+ if (it.currentKey() < rect.top() || it.currentKey() > rect.bottom())
+ {
+ painter.setPen(*it.current());
+ painter.drawLine(0, it.currentKey(), width(), it.currentKey());
+ }
+ }
+}
+
+void KateScrollBar::recomputeMarksPositions(bool forceFullUpdate)
+{
+ if (m_topMargin == -1)
+ watchScrollBarSize();
+
+ m_lines.clear();
+ m_savVisibleLines = m_doc->visibleLines();
+
+ int realHeight = frameGeometry().height() - m_topMargin - m_bottomMargin;
+
+ QPtrList<KTextEditor::Mark> marks = m_doc->marks();
+ KateCodeFoldingTree *tree = m_doc->foldingTree();
+
+ for (KTextEditor::Mark *mark = marks.first(); mark; mark = marks.next())
+ {
+ uint line = mark->line;
+
+ if (tree)
+ {
+ KateCodeFoldingNode *node = tree->findNodeForLine(line);
+
+ while (node)
+ {
+ if (!node->isVisible())
+ line = tree->getStartLine(node);
+ node = node->getParentNode();
+ }
+ }
+
+ line = m_doc->getVirtualLine(line);
+
+ double d = (double)line / (m_savVisibleLines - 1);
+ m_lines.insert(m_topMargin + (int)(d * realHeight),
+ new QColor(KateRendererConfig::global()->lineMarkerColor((KTextEditor::MarkInterface::MarkTypes)mark->type)));
+ }
+
+ if (forceFullUpdate)
+ update();
+ else
+ redrawMarks();
+}
+
+void KateScrollBar::watchScrollBarSize()
+{
+ int savMax = maxValue();
+ setMaxValue(0);
+ QRect rect = sliderRect();
+ setMaxValue(savMax);
+
+ m_topMargin = rect.top();
+ m_bottomMargin = frameGeometry().height() - rect.bottom();
+}
+
+void KateScrollBar::sliderMaybeMoved(int value)
+{
+ if (m_middleMouseDown)
+ emit sliderMMBMoved(value);
+}
+//END
+
+//BEGIN KateCmdLnWhatsThis
+class KateCmdLnWhatsThis : public QWhatsThis
+{
+ public:
+ KateCmdLnWhatsThis( KateCmdLine *parent )
+ : QWhatsThis( parent )
+ , m_parent( parent ) {;}
+
+ QString text( const QPoint & )
+ {
+ QString beg = "<qt background=\"white\"><div><table width=\"100%\"><tr><td bgcolor=\"brown\"><font color=\"white\"><b>Help: <big>";
+ QString mid = "</big></b></font></td></tr><tr><td>";
+ QString end = "</td></tr></table></div><qt>";
+
+ QString t = m_parent->text();
+ QRegExp re( "\\s*help\\s+(.*)" );
+ if ( re.search( t ) > -1 )
+ {
+ QString s;
+ // get help for command
+ QString name = re.cap( 1 );
+ if ( name == "list" )
+ {
+ return beg + i18n("Available Commands") + mid
+ + KateCmd::self()->cmds().join(" ")
+ + i18n("<p>For help on individual commands, do <code>'help &lt;command&gt;'</code></p>")
+ + end;
+ }
+ else if ( ! name.isEmpty() )
+ {
+ Kate::Command *cmd = KateCmd::self()->queryCommand( name );
+ if ( cmd )
+ {
+ if ( cmd->help( (Kate::View*)m_parent->parentWidget(), name, s ) )
+ return beg + name + mid + s + end;
+ else
+ return beg + name + mid + i18n("No help for '%1'").arg( name ) + end;
+ }
+ else
+ return beg + mid + i18n("No such command <b>%1</b>").arg(name) + end;
+ }
+ }
+
+ return beg + mid + i18n(
+ "<p>This is the Katepart <b>command line</b>.<br>"
+ "Syntax: <code><b>command [ arguments ]</b></code><br>"
+ "For a list of available commands, enter <code><b>help list</b></code><br>"
+ "For help for individual commands, enter <code><b>help &lt;command&gt;</b></code></p>")
+ + end;
+ }
+
+ private:
+ KateCmdLine *m_parent;
+};
+//END KateCmdLnWhatsThis
+
+//BEGIN KateCmdLineFlagCompletion
+/**
+ * This class provide completion of flags. It shows a short description of
+ * each flag, and flags are appended.
+ */
+class KateCmdLineFlagCompletion : public KCompletion
+{
+ public:
+ KateCmdLineFlagCompletion() {;}
+
+ QString makeCompletion( const QString & string )
+ {
+ return QString::null;
+ }
+
+};
+//END KateCmdLineFlagCompletion
+
+//BEGIN KateCmdLine
+KateCmdLine::KateCmdLine (KateView *view)
+ : KLineEdit (view)
+ , m_view (view)
+ , m_msgMode (false)
+ , m_histpos( 0 )
+ , m_cmdend( 0 )
+ , m_command( 0L )
+ , m_oldCompletionObject( 0L )
+{
+ connect (this, SIGNAL(returnPressed(const QString &)),
+ this, SLOT(slotReturnPressed(const QString &)));
+
+ completionObject()->insertItems (KateCmd::self()->cmds());
+ setAutoDeleteCompletionObject( false );
+ m_help = new KateCmdLnWhatsThis( this );
+}
+
+void KateCmdLine::slotReturnPressed ( const QString& text )
+{
+
+ // silently ignore leading space
+ uint n = 0;
+ while( text[n].isSpace() )
+ n++;
+
+ QString cmd = text.mid( n );
+
+ // Built in help: if the command starts with "help", [try to] show some help
+ if ( cmd.startsWith( "help" ) )
+ {
+ m_help->display( m_help->text( QPoint() ), mapToGlobal(QPoint(0,0)) );
+ clear();
+ KateCmd::self()->appendHistory( cmd );
+ m_histpos = KateCmd::self()->historyLength();
+ m_oldText = QString ();
+ return;
+ }
+
+ if (cmd.length () > 0)
+ {
+ Kate::Command *p = KateCmd::self()->queryCommand (cmd);
+
+ m_oldText = cmd;
+ m_msgMode = true;
+
+ if (p)
+ {
+ QString msg;
+
+ if (p->exec (m_view, cmd, msg))
+ {
+ KateCmd::self()->appendHistory( cmd );
+ m_histpos = KateCmd::self()->historyLength();
+ m_oldText = QString ();
+
+ if (msg.length() > 0)
+ setText (i18n ("Success: ") + msg);
+ else
+ setText (i18n ("Success"));
+ }
+ else
+ {
+ if (msg.length() > 0)
+ setText (i18n ("Error: ") + msg);
+ else
+ setText (i18n ("Command \"%1\" failed.").arg (cmd));
+ KNotifyClient::beep();
+ }
+ }
+ else
+ {
+ setText (i18n ("No such command: \"%1\"").arg (cmd));
+ KNotifyClient::beep();
+ }
+ }
+
+ // clean up
+ if ( m_oldCompletionObject )
+ {
+ KCompletion *c = completionObject();
+ setCompletionObject( m_oldCompletionObject );
+ m_oldCompletionObject = 0;
+ delete c;
+ c = 0;
+ }
+ m_command = 0;
+ m_cmdend = 0;
+
+ m_view->setFocus ();
+ QTimer::singleShot( 4000, this, SLOT(hideMe()) );
+}
+
+void KateCmdLine::hideMe () // unless i have focus ;)
+{
+ if ( isVisibleTo(parentWidget()) && ! hasFocus() ) {
+ m_view->toggleCmdLine ();
+ }
+}
+
+void KateCmdLine::focusInEvent ( QFocusEvent *ev )
+{
+ if (m_msgMode)
+ {
+ m_msgMode = false;
+ setText (m_oldText);
+ selectAll();
+ }
+
+ KLineEdit::focusInEvent (ev);
+}
+
+void KateCmdLine::keyPressEvent( QKeyEvent *ev )
+{
+ if (ev->key() == Key_Escape)
+ {
+ m_view->setFocus ();
+ hideMe();
+ }
+ else if ( ev->key() == Key_Up )
+ fromHistory( true );
+ else if ( ev->key() == Key_Down )
+ fromHistory( false );
+
+ uint cursorpos = cursorPosition();
+ KLineEdit::keyPressEvent (ev);
+
+ // during typing, let us see if we have a valid command
+ if ( ! m_cmdend || cursorpos <= m_cmdend )
+ {
+ QChar c;
+ if ( ! ev->text().isEmpty() )
+ c = ev->text()[0];
+
+ if ( ! m_cmdend && ! c.isNull() ) // we have no command, so lets see if we got one
+ {
+ if ( ! c.isLetterOrNumber() && c != '-' && c != '_' )
+ {
+ m_command = KateCmd::self()->queryCommand( text().stripWhiteSpace() );
+ if ( m_command )
+ {
+ //kdDebug(13025)<<"keypress in commandline: We have a command! "<<m_command<<". text is '"<<text()<<"'"<<endl;
+ // if the typed character is ":",
+ // we try if the command has flag completions
+ m_cmdend = cursorpos;
+ //kdDebug(13025)<<"keypress in commandline: Set m_cmdend to "<<m_cmdend<<endl;
+ }
+ else
+ m_cmdend = 0;
+ }
+ }
+ else // since cursor is inside the command name, we reconsider it
+ {
+ kdDebug(13025)<<"keypress in commandline: \\W -- text is "<<text()<<endl;
+ m_command = KateCmd::self()->queryCommand( text().stripWhiteSpace() );
+ if ( m_command )
+ {
+ //kdDebug(13025)<<"keypress in commandline: We have a command! "<<m_command<<endl;
+ QString t = text();
+ m_cmdend = 0;
+ bool b = false;
+ for ( ; m_cmdend < t.length(); m_cmdend++ )
+ {
+ if ( t[m_cmdend].isLetter() )
+ b = true;
+ if ( b && ( ! t[m_cmdend].isLetterOrNumber() && t[m_cmdend] != '-' && t[m_cmdend] != '_' ) )
+ break;
+ }
+
+ if ( c == ':' && cursorpos == m_cmdend )
+ {
+ // check if this command wants to complete flags
+ //kdDebug(13025)<<"keypress in commandline: Checking if flag completion is desired!"<<endl;
+ }
+ }
+ else
+ {
+ // clean up if needed
+ if ( m_oldCompletionObject )
+ {
+ KCompletion *c = completionObject();
+ setCompletionObject( m_oldCompletionObject );
+ m_oldCompletionObject = 0;
+ delete c;
+ c = 0;
+ }
+
+ m_cmdend = 0;
+ }
+ }
+
+ // if we got a command, check if it wants to do semething.
+ if ( m_command )
+ {
+ //kdDebug(13025)<<"Checking for CommandExtension.."<<endl;
+ Kate::CommandExtension *ce = dynamic_cast<Kate::CommandExtension*>(m_command);
+ if ( ce )
+ {
+ KCompletion *cmpl = ce->completionObject( text().left( m_cmdend ).stripWhiteSpace(), m_view );
+ if ( cmpl )
+ {
+ // save the old completion object and use what the command provides
+ // instead. We also need to prepend the current command name + flag string
+ // when completion is done
+ //kdDebug(13025)<<"keypress in commandline: Setting completion object!"<<endl;
+ if ( ! m_oldCompletionObject )
+ m_oldCompletionObject = completionObject();
+
+ setCompletionObject( cmpl );
+ }
+ }
+ }
+ }
+ else if ( m_command )// check if we should call the commands processText()
+ {
+ Kate::CommandExtension *ce = dynamic_cast<Kate::CommandExtension*>( m_command );
+ if ( ce && ce->wantsToProcessText( text().left( m_cmdend ).stripWhiteSpace() )
+ && ! ( ev->text().isNull() || ev->text().isEmpty() ) )
+ ce->processText( m_view, text() );
+ }
+}
+
+void KateCmdLine::fromHistory( bool up )
+{
+ if ( ! KateCmd::self()->historyLength() )
+ return;
+
+ QString s;
+
+ if ( up )
+ {
+ if ( m_histpos > 0 )
+ {
+ m_histpos--;
+ s = KateCmd::self()->fromHistory( m_histpos );
+ }
+ }
+ else
+ {
+ if ( m_histpos < ( KateCmd::self()->historyLength() - 1 ) )
+ {
+ m_histpos++;
+ s = KateCmd::self()->fromHistory( m_histpos );
+ }
+ else
+ {
+ m_histpos = KateCmd::self()->historyLength();
+ setText( m_oldText );
+ }
+ }
+ if ( ! s.isEmpty() )
+ {
+ // Select the argument part of the command, so that it is easy to overwrite
+ setText( s );
+ static QRegExp reCmd = QRegExp(".*[\\w\\-]+(?:[^a-zA-Z0-9_-]|:\\w+)(.*)");
+ if ( reCmd.search( text() ) == 0 )
+ setSelection( text().length() - reCmd.cap(1).length(), reCmd.cap(1).length() );
+ }
+}
+//END KateCmdLine
+
+//BEGIN KateIconBorder
+using namespace KTextEditor;
+
+static const char* const plus_xpm[] = {
+"11 11 3 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"...........",
+".+++++++++.",
+".+++++++++.",
+".++++.++++.",
+".++++.++++.",
+".++.....++.",
+".++++.++++.",
+".++++.++++.",
+".+++++++++.",
+".+++++++++.",
+"..........."};
+
+static const char* const minus_xpm[] = {
+"11 11 3 1",
+" c None",
+". c #000000",
+"+ c #FFFFFF",
+"...........",
+".+++++++++.",
+".+++++++++.",
+".+++++++++.",
+".+++++++++.",
+".++.....++.",
+".+++++++++.",
+".+++++++++.",
+".+++++++++.",
+".+++++++++.",
+"..........."};
+
+static const char * const bookmark_xpm[] = {
+"14 13 82 1",
+" c None",
+". c #F27D01",
+"+ c #EF7901",
+"@ c #F3940F",
+"# c #EE8F12",
+"$ c #F9C834",
+"% c #F5C33A",
+"& c #F09110",
+"* c #FCEE3E",
+"= c #FBEB3F",
+"- c #E68614",
+"; c #FA8700",
+"> c #F78703",
+", c #F4920E",
+"' c #F19113",
+") c #F6C434",
+"! c #FDF938",
+"~ c #FDF839",
+"{ c #F1BC3A",
+"] c #E18017",
+"^ c #DA7210",
+"/ c #D5680B",
+"( c #CA5404",
+"_ c #FD8F06",
+": c #FCB62D",
+"< c #FDE049",
+"[ c #FCE340",
+"} c #FBE334",
+"| c #FDF035",
+"1 c #FEF834",
+"2 c #FCEF36",
+"3 c #F8DF32",
+"4 c #F7DC3D",
+"5 c #F5CE3E",
+"6 c #DE861B",
+"7 c #C64C03",
+"8 c #F78C07",
+"9 c #F8B019",
+"0 c #FDE12D",
+"a c #FEE528",
+"b c #FEE229",
+"c c #FBD029",
+"d c #E18814",
+"e c #CB5605",
+"f c #EF8306",
+"g c #F3A00E",
+"h c #FBC718",
+"i c #FED31C",
+"j c #FED11D",
+"k c #F8B91C",
+"l c #E07D0D",
+"m c #CB5301",
+"n c #ED8A0E",
+"o c #F7A90D",
+"p c #FEC113",
+"q c #FEC013",
+"r c #F09B0E",
+"s c #D35E03",
+"t c #EF9213",
+"u c #F9A208",
+"v c #FEAA0C",
+"w c #FCA10B",
+"x c #FCA70B",
+"y c #FEAF0B",
+"z c #F39609",
+"A c #D86203",
+"B c #F08C0D",
+"C c #FA9004",
+"D c #F17F04",
+"E c #E36D04",
+"F c #E16F03",
+"G c #EE8304",
+"H c #F88C04",
+"I c #DC6202",
+"J c #E87204",
+"K c #E66A01",
+"L c #DC6001",
+"M c #D15601",
+"N c #DA5D01",
+"O c #D25200",
+"P c #DA5F00",
+"Q c #BC3C00",
+" .+ ",
+" @# ",
+" $% ",
+" &*=- ",
+" ;>,')!~{]^/( ",
+"_:<[}|11234567",
+" 890aaaaabcde ",
+" fghiiijklm ",
+" nopqpqrs ",
+" tuvwxyzA ",
+" BCDEFGHI ",
+" JKL MNO ",
+" P Q "};
+
+const int iconPaneWidth = 16;
+const int halfIPW = 8;
+
+KateIconBorder::KateIconBorder ( KateViewInternal* internalView, QWidget *parent )
+ : QWidget(parent, "", Qt::WStaticContents | Qt::WRepaintNoErase | Qt::WResizeNoErase )
+ , m_view( internalView->m_view )
+ , m_doc( internalView->m_doc )
+ , m_viewInternal( internalView )
+ , m_iconBorderOn( false )
+ , m_lineNumbersOn( false )
+ , m_foldingMarkersOn( false )
+ , m_dynWrapIndicatorsOn( false )
+ , m_dynWrapIndicators( 0 )
+ , m_cachedLNWidth( 0 )
+ , m_maxCharWidth( 0 )
+{
+ setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Minimum ) );
+
+ setBackgroundMode( NoBackground );
+
+ m_doc->setDescription( MarkInterface::markType01, i18n("Bookmark") );
+ m_doc->setPixmap( MarkInterface::markType01, QPixmap((const char**)bookmark_xpm) );
+
+ updateFont();
+}
+
+void KateIconBorder::setIconBorderOn( bool enable )
+{
+ if( enable == m_iconBorderOn )
+ return;
+
+ m_iconBorderOn = enable;
+
+ updateGeometry();
+
+ QTimer::singleShot( 0, this, SLOT(update()) );
+}
+
+void KateIconBorder::setLineNumbersOn( bool enable )
+{
+ if( enable == m_lineNumbersOn )
+ return;
+
+ m_lineNumbersOn = enable;
+ m_dynWrapIndicatorsOn = (m_dynWrapIndicators == 1) ? enable : m_dynWrapIndicators;
+
+ updateGeometry();
+
+ QTimer::singleShot( 0, this, SLOT(update()) );
+}
+
+void KateIconBorder::setDynWrapIndicators( int state )
+{
+ if (state == m_dynWrapIndicators )
+ return;
+
+ m_dynWrapIndicators = state;
+ m_dynWrapIndicatorsOn = (state == 1) ? m_lineNumbersOn : state;
+
+ updateGeometry ();
+
+ QTimer::singleShot( 0, this, SLOT(update()) );
+}
+
+void KateIconBorder::setFoldingMarkersOn( bool enable )
+{
+ if( enable == m_foldingMarkersOn )
+ return;
+
+ m_foldingMarkersOn = enable;
+
+ updateGeometry();
+
+ QTimer::singleShot( 0, this, SLOT(update()) );
+}
+
+QSize KateIconBorder::sizeHint() const
+{
+ int w = 0;
+
+ if (m_iconBorderOn)
+ w += iconPaneWidth + 1;
+
+ if (m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn)) {
+ w += lineNumberWidth();
+ }
+
+ if (m_foldingMarkersOn)
+ w += iconPaneWidth;
+
+ w += 4;
+
+ return QSize( w, 0 );
+}
+
+// This function (re)calculates the maximum width of any of the digit characters (0 -> 9)
+// for graceful handling of variable-width fonts as the linenumber font.
+void KateIconBorder::updateFont()
+{
+ const QFontMetrics *fm = m_view->renderer()->config()->fontMetrics();
+ m_maxCharWidth = 0;
+ // Loop to determine the widest numeric character in the current font.
+ // 48 is ascii '0'
+ for (int i = 48; i < 58; i++) {
+ int charWidth = fm->width( QChar(i) );
+ m_maxCharWidth = kMax(m_maxCharWidth, charWidth);
+ }
+}
+
+int KateIconBorder::lineNumberWidth() const
+{
+ int width = m_lineNumbersOn ? ((int)log10((double)(m_view->doc()->numLines())) + 1) * m_maxCharWidth + 4 : 0;
+
+ if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) {
+ width = kMax(style().scrollBarExtent().width() + 4, width);
+
+ if (m_cachedLNWidth != width || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) {
+ int w = style().scrollBarExtent().width();
+ int h = m_view->renderer()->config()->fontMetrics()->height();
+
+ QSize newSize(w, h);
+ if ((m_arrow.size() != newSize || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor()) && !newSize.isEmpty()) {
+ m_arrow.resize(newSize);
+
+ QPainter p(&m_arrow);
+ p.fillRect( 0, 0, w, h, m_view->renderer()->config()->iconBarColor() );
+
+ h = m_view->renderer()->config()->fontMetrics()->ascent();
+
+ p.setPen(m_view->renderer()->attribute(0)->textColor());
+ p.drawLine(w/2, h/2, w/2, 0);
+#if 1
+ p.lineTo(w/4, h/4);
+ p.lineTo(0, 0);
+ p.lineTo(0, h/2);
+ p.lineTo(w/2, h-1);
+ p.lineTo(w*3/4, h-1);
+ p.lineTo(w-1, h*3/4);
+ p.lineTo(w*3/4, h/2);
+ p.lineTo(0, h/2);
+#else
+ p.lineTo(w*3/4, h/4);
+ p.lineTo(w-1,0);
+ p.lineTo(w-1, h/2);
+ p.lineTo(w/2, h-1);
+ p.lineTo(w/4,h-1);
+ p.lineTo(0, h*3/4);
+ p.lineTo(w/4, h/2);
+ p.lineTo(w-1, h/2);
+#endif
+ }
+ }
+ }
+
+ return width;
+}
+
+void KateIconBorder::paintEvent(QPaintEvent* e)
+{
+ paintBorder(e->rect().x(), e->rect().y(), e->rect().width(), e->rect().height());
+}
+
+void KateIconBorder::paintBorder (int /*x*/, int y, int /*width*/, int height)
+{
+ static QPixmap minus_px ((const char**)minus_xpm);
+ static QPixmap plus_px ((const char**)plus_xpm);
+
+ uint h = m_view->renderer()->config()->fontStruct()->fontHeight;
+ uint startz = (y / h);
+ uint endz = startz + 1 + (height / h);
+ uint lineRangesSize = m_viewInternal->lineRanges.size();
+
+ // center the folding boxes
+ int m_px = (h - 11) / 2;
+ if (m_px < 0)
+ m_px = 0;
+
+ int lnWidth( 0 );
+ if ( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) ) // avoid calculating unless needed ;-)
+ {
+ lnWidth = lineNumberWidth();
+ if ( lnWidth != m_cachedLNWidth || m_oldBackgroundColor != m_view->renderer()->config()->iconBarColor() )
+ {
+ // we went from n0 ->n9 lines or vice verca
+ // this causes an extra updateGeometry() first time the line numbers
+ // are displayed, but sizeHint() is supposed to be const so we can't set
+ // the cached value there.
+ m_cachedLNWidth = lnWidth;
+ m_oldBackgroundColor = m_view->renderer()->config()->iconBarColor();
+ updateGeometry();
+ update ();
+ return;
+ }
+ }
+
+ int w( this->width() ); // sane value/calc only once
+
+ QPainter p ( this );
+ p.setFont ( *m_view->renderer()->config()->font() ); // for line numbers
+ // the line number color is for the line numbers, vertical separator lines
+ // and for for the code folding lines.
+ p.setPen ( m_view->renderer()->config()->lineNumberColor() );
+
+ KateLineInfo oldInfo;
+ if (startz < lineRangesSize)
+ {
+ if ((m_viewInternal->lineRanges[startz].line-1) < 0)
+ oldInfo.topLevel = true;
+ else
+ m_doc->lineInfo(&oldInfo,m_viewInternal->lineRanges[startz].line-1);
+ }
+
+ for (uint z=startz; z <= endz; z++)
+ {
+ int y = h * z;
+ int realLine = -1;
+
+ if (z < lineRangesSize)
+ realLine = m_viewInternal->lineRanges[z].line;
+
+ int lnX ( 0 );
+
+ p.fillRect( 0, y, w-4, h, m_view->renderer()->config()->iconBarColor() );
+ p.fillRect( w-4, y, 4, h, m_view->renderer()->config()->backgroundColor() );
+
+ // icon pane
+ if( m_iconBorderOn )
+ {
+ p.drawLine(lnX+iconPaneWidth, y, lnX+iconPaneWidth, y+h);
+
+ if( (realLine > -1) && (m_viewInternal->lineRanges[z].startCol == 0) )
+ {
+ uint mrk ( m_doc->mark( realLine ) ); // call only once
+
+ if ( mrk )
+ {
+ for( uint bit = 0; bit < 32; bit++ )
+ {
+ MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit);
+ if( mrk & markType )
+ {
+ QPixmap *px_mark (m_doc->markPixmap( markType ));
+
+ if (px_mark)
+ {
+ // center the mark pixmap
+ int x_px = (iconPaneWidth - px_mark->width()) / 2;
+ if (x_px < 0)
+ x_px = 0;
+
+ int y_px = (h - px_mark->height()) / 2;
+ if (y_px < 0)
+ y_px = 0;
+
+ p.drawPixmap( lnX+x_px, y+y_px, *px_mark);
+ }
+ }
+ }
+ }
+ }
+
+ lnX += iconPaneWidth + 1;
+ }
+
+ // line number
+ if( m_lineNumbersOn || (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) )
+ {
+ lnX +=2;
+
+ if (realLine > -1)
+ if (m_viewInternal->lineRanges[z].startCol == 0) {
+ if (m_lineNumbersOn)
+ p.drawText( lnX + 1, y, lnWidth-4, h, Qt::AlignRight|Qt::AlignVCenter, QString("%1").arg( realLine + 1 ) );
+ } else if (m_view->dynWordWrap() && m_dynWrapIndicatorsOn) {
+ p.drawPixmap(lnX + lnWidth - m_arrow.width() - 4, y, m_arrow);
+ }
+
+ lnX += lnWidth;
+ }
+
+ // folding markers
+ if( m_foldingMarkersOn )
+ {
+ if( realLine > -1 )
+ {
+ KateLineInfo info;
+ m_doc->lineInfo(&info,realLine);
+
+ if (!info.topLevel)
+ {
+ if (info.startsVisibleBlock && (m_viewInternal->lineRanges[z].startCol == 0))
+ {
+ if (oldInfo.topLevel)
+ p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1);
+ else
+ p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
+
+ p.drawPixmap(lnX+3,y+m_px,minus_px);
+ }
+ else if (info.startsInVisibleBlock)
+ {
+ if (m_viewInternal->lineRanges[z].startCol == 0)
+ {
+ if (oldInfo.topLevel)
+ p.drawLine(lnX+halfIPW,y+m_px,lnX+halfIPW,y+h-1);
+ else
+ p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
+
+ p.drawPixmap(lnX+3,y+m_px,plus_px);
+ }
+ else
+ {
+ p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
+ }
+
+ if (!m_viewInternal->lineRanges[z].wrap)
+ p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1);
+ }
+ else
+ {
+ p.drawLine(lnX+halfIPW,y,lnX+halfIPW,y+h-1);
+
+ if (info.endsBlock && !m_viewInternal->lineRanges[z].wrap)
+ p.drawLine(lnX+halfIPW,y+h-1,lnX+iconPaneWidth-2,y+h-1);
+ }
+ }
+
+ oldInfo = info;
+ }
+
+ lnX += iconPaneWidth;
+ }
+ }
+}
+
+KateIconBorder::BorderArea KateIconBorder::positionToArea( const QPoint& p ) const
+{
+ int x = 0;
+ if( m_iconBorderOn ) {
+ x += iconPaneWidth;
+ if( p.x() <= x )
+ return IconBorder;
+ }
+ if( m_lineNumbersOn || m_dynWrapIndicators ) {
+ x += lineNumberWidth();
+ if( p.x() <= x )
+ return LineNumbers;
+ }
+ if( m_foldingMarkersOn ) {
+ x += iconPaneWidth;
+ if( p.x() <= x )
+ return FoldingMarkers;
+ }
+ return None;
+}
+
+void KateIconBorder::mousePressEvent( QMouseEvent* e )
+{
+ m_lastClickedLine = m_viewInternal->yToKateLineRange(e->y()).line;
+
+ if ( positionToArea( e->pos() ) != IconBorder )
+ {
+ QMouseEvent forward( QEvent::MouseButtonPress,
+ QPoint( 0, e->y() ), e->button(), e->state() );
+ m_viewInternal->mousePressEvent( &forward );
+ }
+ e->accept();
+}
+
+void KateIconBorder::mouseMoveEvent( QMouseEvent* e )
+{
+ if ( positionToArea( e->pos() ) != IconBorder )
+ {
+ QMouseEvent forward( QEvent::MouseMove,
+ QPoint( 0, e->y() ), e->button(), e->state() );
+ m_viewInternal->mouseMoveEvent( &forward );
+ }
+}
+
+void KateIconBorder::mouseReleaseEvent( QMouseEvent* e )
+{
+ uint cursorOnLine = m_viewInternal->yToKateLineRange(e->y()).line;
+
+ if (cursorOnLine == m_lastClickedLine &&
+ cursorOnLine <= m_doc->lastLine() )
+ {
+ BorderArea area = positionToArea( e->pos() );
+ if( area == IconBorder) {
+ if (e->button() == LeftButton) {
+ if( m_doc->editableMarks() & KateViewConfig::global()->defaultMarkType() ) {
+ if( m_doc->mark( cursorOnLine ) & KateViewConfig::global()->defaultMarkType() )
+ m_doc->removeMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() );
+ else
+ m_doc->addMark( cursorOnLine, KateViewConfig::global()->defaultMarkType() );
+ } else {
+ showMarkMenu( cursorOnLine, QCursor::pos() );
+ }
+ }
+ else
+ if (e->button() == RightButton) {
+ showMarkMenu( cursorOnLine, QCursor::pos() );
+ }
+ }
+
+ if ( area == FoldingMarkers) {
+ KateLineInfo info;
+ m_doc->lineInfo(&info,cursorOnLine);
+ if ((info.startsVisibleBlock) || (info.startsInVisibleBlock)) {
+ emit toggleRegionVisibility(cursorOnLine);
+ }
+ }
+ }
+
+ QMouseEvent forward( QEvent::MouseButtonRelease,
+ QPoint( 0, e->y() ), e->button(), e->state() );
+ m_viewInternal->mouseReleaseEvent( &forward );
+}
+
+void KateIconBorder::mouseDoubleClickEvent( QMouseEvent* e )
+{
+ QMouseEvent forward( QEvent::MouseButtonDblClick,
+ QPoint( 0, e->y() ), e->button(), e->state() );
+ m_viewInternal->mouseDoubleClickEvent( &forward );
+}
+
+void KateIconBorder::showMarkMenu( uint line, const QPoint& pos )
+{
+ QPopupMenu markMenu;
+ QPopupMenu selectDefaultMark;
+
+ typedef QValueVector<int> MarkTypeVector;
+ MarkTypeVector vec( 33 );
+ int i=1;
+
+ for( uint bit = 0; bit < 32; bit++ ) {
+ MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes)(1<<bit);
+ if( !(m_doc->editableMarks() & markType) )
+ continue;
+
+ if( !m_doc->markDescription( markType ).isEmpty() ) {
+ markMenu.insertItem( m_doc->markDescription( markType ), i );
+ selectDefaultMark.insertItem( m_doc->markDescription( markType ), i+100);
+ } else {
+ markMenu.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i );
+ selectDefaultMark.insertItem( i18n("Mark Type %1").arg( bit + 1 ), i+100);
+ }
+
+ if( m_doc->mark( line ) & markType )
+ markMenu.setItemChecked( i, true );
+
+ if( markType & KateViewConfig::global()->defaultMarkType() )
+ selectDefaultMark.setItemChecked( i+100, true );
+
+ vec[i++] = markType;
+ }
+
+ if( markMenu.count() == 0 )
+ return;
+
+ if( markMenu.count() > 1 )
+ markMenu.insertItem( i18n("Set Default Mark Type" ), &selectDefaultMark);
+
+ int result = markMenu.exec( pos );
+ if( result <= 0 )
+ return;
+
+ if ( result > 100)
+ {
+ KateViewConfig::global()->setDefaultMarkType (vec[result-100]);
+ // flush config, otherwise it isn't nessecarily done
+ KConfig *config = kapp->config();
+ config->setGroup("Kate View Defaults");
+ KateViewConfig::global()->writeConfig( config );
+ }
+ else
+ {
+ MarkInterface::MarkTypes markType = (MarkInterface::MarkTypes) vec[result];
+ if( m_doc->mark( line ) & markType ) {
+ m_doc->removeMark( line, markType );
+ } else {
+ m_doc->addMark( line, markType );
+ }
+ }
+}
+//END KateIconBorder
+
+KateViewEncodingAction::KateViewEncodingAction(KateDocument *_doc, KateView *_view, const QString& text, QObject* parent, const char* name)
+ : KActionMenu (text, parent, name), doc(_doc), view (_view)
+{
+ connect(popupMenu(),SIGNAL(aboutToShow()),this,SLOT(slotAboutToShow()));
+}
+
+void KateViewEncodingAction::slotAboutToShow()
+{
+ QStringList modes (KGlobal::charsets()->descriptiveEncodingNames());
+
+ popupMenu()->clear ();
+ for (uint z=0; z<modes.size(); ++z)
+ {
+ popupMenu()->insertItem ( modes[z], this, SLOT(setMode(int)), 0, z);
+
+ bool found = false;
+ QTextCodec *codecForEnc = KGlobal::charsets()->codecForName(KGlobal::charsets()->encodingForName(modes[z]), found);
+
+ if (found && codecForEnc)
+ {
+ if (codecForEnc->name() == doc->config()->codec()->name())
+ popupMenu()->setItemChecked (z, true);
+ }
+ }
+}
+
+void KateViewEncodingAction::setMode (int mode)
+{
+ QStringList modes (KGlobal::charsets()->descriptiveEncodingNames());
+ doc->config()->setEncoding( KGlobal::charsets()->encodingForName( modes[mode] ) );
+ // now we don't want the encoding changed again unless the user does so using the menu.
+ doc->setEncodingSticky( true );
+ doc->reloadFile();
+}
+
+// kate: space-indent on; indent-width 2; replace-tabs on;