Prepare for QTextEdit transition: Add KTextEdit::charAt() for wordAtPoint().
[kdbg.git] / kdbg / textvw.cpp
blobcc7973018a600b2b465bb4ae88603298c69966d0
1 // $Id$
3 // Copyright by Johannes Sixt
4 // This file is under GPL, the GNU General Public Licence
6 #include <qpainter.h>
7 #include <qkeycode.h>
8 #include "textvw.h"
9 #include "textvw.moc"
10 #ifdef HAVE_CONFIG_H
11 #include "config.h"
12 #endif
13 #include "mydebug.h"
15 #define DEFAULT_WIDTH 100
16 #define DEFAULT_LINEHEIGHT 1
18 KTextView::KTextView(QWidget* parent, const char* name, WFlags f) :
19 TableView(parent, name, f),
20 m_width(DEFAULT_WIDTH),
21 m_height(DEFAULT_LINEHEIGHT),
22 m_tabWidth(0),
23 m_curRow(-1)
25 setNumCols(1);
26 setBackgroundColor(colorGroup().base());
29 KTextView::~KTextView()
34 * Update cell width and hight; returns whether there is a change
35 * Cell geometry: There are 2 pixels to the left and to the right
36 * and 1 pixel _below_ the line
38 bool KTextView::updateCellSize(const QString& text)
40 QPainter p(this);
41 setupPainter(&p);
42 QRect r = p.boundingRect(0,0, 0,0,
43 AlignLeft | SingleLine | DontClip | ExpandTabs,
44 text, text.length());
46 bool update = false;
47 int w = r.width() + 4;
48 if (w > m_width) {
49 m_width = w;
50 update = true;
52 int h = r.height() + 1;
53 if (h > m_height) {
54 m_height = h;
55 update = true;
57 return update;
60 void KTextView::insertLine(const QString& text)
62 m_texts.push_back(text);
63 setNumRows(m_texts.size());
65 updateCellSize(text);
67 if (autoUpdate()) {
68 updateTableSize();
69 repaint();
74 * TODO: This function doesn't shrink the line length if the longest line
75 * is replaced by a shorter one.
77 void KTextView::replaceLine(int line, const QString& text)
79 if (line < 0 || line >= int(m_texts.size()))
80 return;
82 m_texts[line] = text;
84 bool update = updateCellSize(text);
86 if (autoUpdate()) {
87 if (update) {
88 updateTableSize();
90 repaint();
94 void KTextView::setCursorPosition(int row, int)
96 activateLine(row);
99 void KTextView::cursorPosition(int* row, int* col)
101 *row = m_curRow;
102 *col = 0;
105 int KTextView::cellWidth(int /*col*/) const
107 return m_width;
110 int KTextView::cellHeight(int /*row*/) const
112 return m_height;
115 int KTextView::textCol() const
117 // by default, the text is in column 0
118 return 0;
121 void KTextView::paintCell(QPainter* p, int row, int /*col*/)
123 if (row >= m_texts.size()) {
124 return;
126 if (row == m_curRow) {
127 // paint background
128 p->fillRect(0,0, m_width,m_height, QBrush(colorGroup().background()));
130 const QString& text = m_texts[row];
131 p->drawText(2,0, m_width-4, m_height,
132 AlignLeft | SingleLine | DontClip | ExpandTabs,
133 text, text.length());
136 void KTextView::keyPressEvent(QKeyEvent* ev)
138 int oldRow = m_curRow;
140 // go to line 0 if no current line
141 if (m_curRow < 0) {
142 activateLine(0);
144 else
146 int numVisibleRows, newRow, newX;
148 switch (ev->key()) {
149 case Key_Up:
150 if (m_curRow > 0) {
151 activateLine(m_curRow-1);
153 break;
154 case Key_Down:
155 if (m_curRow < numRows()-1) {
156 activateLine(m_curRow+1);
158 break;
159 case Key_PageUp:
160 /* this method doesn't work for variable height lines */
161 numVisibleRows = lastRowVisible()-topCell();
162 newRow = m_curRow - QMAX(numVisibleRows,1);
163 if (newRow < 0)
164 newRow = 0;
165 activateLine(newRow);
166 break;
167 case Key_PageDown:
168 /* this method doesn't work for variable height lines */
169 numVisibleRows = lastRowVisible()-topCell();
170 newRow = m_curRow + QMAX(numVisibleRows,1);
171 if (newRow >= numRows())
172 newRow = numRows()-1;
173 activateLine(newRow);
174 break;
176 // scroll left and right by a few pixels
177 case Key_Left:
178 newX = xOffset() - viewWidth()/10;
179 setXOffset(QMAX(newX, 0));
180 break;
181 case Key_Right:
182 newX = xOffset() + viewWidth()/10;
183 setXOffset(QMIN(newX, maxXOffset()));
184 break;
186 default:
187 QWidget::keyPressEvent(ev);
188 return;
191 // make row visible
192 if (m_curRow != oldRow && !rowIsVisible(m_curRow)) {
193 // if the old row was visible, we scroll the view by some pixels
194 // if the old row was not visible, we place active row at the top
195 if (oldRow >= 0 && rowIsVisible(oldRow)) {
196 int diff = m_curRow - oldRow;
197 int newTop = topCell() + diff;
198 setTopCell(QMAX(newTop,0));
199 } else {
200 setTopCell(m_curRow);
203 ev->accept();
206 void KTextView::mousePressEvent(QMouseEvent* ev)
208 int row = findRow(ev->y());
209 activateLine(row);
212 void KTextView::focusInEvent(QFocusEvent*)
215 * The base class does a repaint(), which causes flicker. So we do
216 * nothing here.
220 void KTextView::focusOutEvent(QFocusEvent*)
223 * The base class does a repaint(), which causes flicker. So we do
224 * nothing here.
228 void KTextView::activateLine(int row)
230 if (row == m_curRow)
231 return;
233 int col = textCol();
235 int oldRow = m_curRow;
236 // note that row may be < 0
237 m_curRow = row;
238 // must change m_curRow first, so that updateCell(oldRow) erases the old line!
239 if (oldRow >= 0) {
240 updateCell(oldRow, col);
242 if (row >= 0) {
243 updateCell(row, col);
245 emit lineChanged();
248 /* This is needed to make the kcontrol's color setup working */
249 void KTextView::paletteChange(const QPalette& oldPal)
251 setBackgroundColor(colorGroup().base());
252 TableView::paletteChange(oldPal);
254 // recompute window size
255 m_width = DEFAULT_WIDTH;
256 m_height = DEFAULT_LINEHEIGHT;
257 for (int i = 0; i < m_texts.size(); i++) {
258 updateCellSize(m_texts[i]);
260 updateTableSize();
263 void KTextView::setTabWidth(int numChars)
265 QFontMetrics fm = font();
266 int newTabWidth = fm.width('x') * numChars;
267 if (newTabWidth == m_tabWidth)
268 return;
269 m_tabWidth = newTabWidth;
271 // recompute window width
272 m_width = DEFAULT_WIDTH;
273 for (int i = 0; i < m_texts.size(); i++) {
274 updateCellSize(m_texts[i]);
277 updateTableSize();
278 if (autoUpdate()) {
279 repaint();
283 void KTextView::setupPainter(QPainter* p)
285 p->setTabStops(m_tabWidth);
288 int KTextView::charAt(const QPoint& p, int* para)
290 if (findCol(p.x()) != textCol())
291 return *para = -1;
292 int row = findRow(p.y());
293 *para = row;
294 if (row < 0)
295 return -1;
297 // find top-left corner of text cell
298 int top, left;
299 if (!colXPos(textCol(), &left))
300 return -1;
301 if (!rowYPos(row, &top))
302 return -1;
304 // get the bounding rect of the text
305 QPainter painter(this);
306 setupPainter(&painter);
307 const QString& text = m_texts[row];
308 QRect bound =
309 painter.boundingRect(left+2, top, 0,0,
310 AlignLeft | SingleLine | DontClip | ExpandTabs,
311 text, text.length());
312 if (!bound.contains(p))
313 return -1; /* p is outside text */
315 for (uint n = 0; n < text.length(); n++)
318 * If p is in the rectangle that has n+1 characters, than n
319 * is the character we are looking for
321 bound =
322 painter.boundingRect(left+2, top, 0,0,
323 AlignLeft | SingleLine | DontClip | ExpandTabs,
324 text, n+1);
325 if (bound.contains(p))
326 return n;
328 return -1;