kexitableview.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2002 Till Busch <till@bux.at>
3 Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
4 Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
5 Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
6 Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
7
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Library General Public
10 License as published by the Free Software Foundation; either
11 version 2 of the License, or (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Library General Public License for more details.
17
18 You should have received a copy of the GNU Library General Public License
19 along with this program; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22
23 Original Author: Till Busch <till@bux.at>
24 Original Project: buX (www.bux.at)
25*/
26
27#include <tqpainter.h>
28#include <tqkeycode.h>
29#include <tqlineedit.h>
30#include <tqcombobox.h>
31#include <tqwmatrix.h>
32#include <tqtimer.h>
33#include <tqpopupmenu.h>
34#include <tqcursor.h>
35#include <tqstyle.h>
36#include <tqlayout.h>
37#include <tqlabel.h>
38#include <tqwhatsthis.h>
39
40#include <tdeglobal.h>
41#include <tdelocale.h>
42#include <kdebug.h>
43#include <tdeapplication.h>
44#include <kiconloader.h>
45#include <tdemessagebox.h>
46
47#ifndef KEXI_NO_PRINT
48# include <kprinter.h>
49#endif
50
51#include "kexitableview.h"
52#include <kexiutils/utils.h>
53#include <kexiutils/validator.h>
54
55#include "kexicelleditorfactory.h"
56#include "kexitableviewheader.h"
57#include "kexitableview_p.h"
58#include <widget/utils/kexirecordmarker.h>
59#include <widget/utils/kexidisplayutils.h>
60#include <kexidb/cursor.h>
61
62KexiTableView::Appearance::Appearance(TQWidget *widget)
63 : alternateBackgroundColor( TDEGlobalSettings::alternateBackgroundColor() )
64{
65 //set defaults
66 if (tqApp) {
67 TQPalette p = widget ? widget->palette() : tqApp->palette();
68 baseColor = p.active().base();
69 textColor = p.active().text();
70 borderColor = TQColor(200,200,200);
71 emptyAreaColor = p.active().color(TQColorGroup::Base);
72 rowHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), baseColor, 33, 66);
73 rowMouseOverHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), baseColor, 10, 90);
74 rowMouseOverAlternateHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), alternateBackgroundColor, 10, 90);
75 rowHighlightingTextColor = textColor;
76 rowMouseOverHighlightingTextColor = textColor;
77 }
78 backgroundAltering = true;
79 rowMouseOverHighlightingEnabled = true;
80 rowHighlightingEnabled = true;
81 persistentSelections = true;
82 navigatorEnabled = true;
83 fullRowSelection = false;
84 gridEnabled = true;
85}
86
87//-----------------------------------------
88
90class KexiTableView::WhatsThis : public TQWhatsThis
91{
92 public:
93 WhatsThis(KexiTableView* tv) : TQWhatsThis(tv), m_tv(tv)
94 {
95 Q_ASSERT(tv);
96 }
97 virtual ~WhatsThis()
98 {
99 }
100 virtual TQString text( const TQPoint & pos)
101 {
102 const int leftMargin = m_tv->verticalHeaderVisible() ? m_tv->verticalHeader()->width() : 0;
103 //const int topMargin = m_tv->horizontalHeaderVisible() ? m_tv->d->pTopHeader->height() : 0;
104 //const int bottomMargin = m_tv->d->appearance.navigatorEnabled ? m_tv->m_navPanel->height() : 0;
105 if (KexiUtils::hasParent(m_tv->verticalHeader(), m_tv->childAt(pos))) {
106 return i18n("Contains a pointer to the currently selected row");
107 }
108 else if (KexiUtils::hasParent(m_tv->m_navPanel, m_tv->childAt(pos))) {
109 return i18n("Row navigator");
110// return TQWhatsThis::textFor(m_tv->m_navPanel, TQPoint( pos.x(), pos.y() - m_tv->height() + bottomMargin ));
111 }
112 KexiDB::Field *f = m_tv->field( m_tv->columnAt(pos.x()-leftMargin) );
113 if (!f)
114 return TQString();
115 return f->description().isEmpty() ? f->captionOrName() : f->description();
116 }
117 protected:
118 KexiTableView *m_tv;
119};
120
121//-----------------------------------------
122
123KexiTableViewCellToolTip::KexiTableViewCellToolTip( KexiTableView * tableView )
124 : TQToolTip(tableView->viewport())
125 , m_tableView(tableView)
126{
127}
128
129KexiTableViewCellToolTip::~KexiTableViewCellToolTip()
130{
131 remove(parentWidget());
132}
133
134void KexiTableViewCellToolTip::maybeTip( const TQPoint & p )
135{
136 const TQPoint cp( m_tableView->viewportToContents( p ) );
137 const int row = m_tableView->rowAt( cp.y(), true/*ignoreEnd*/ );
138 const int col = m_tableView->columnAt( cp.x() );
139
140 //show tooltip if needed
141 if (col>=0 && row>=0) {
142 KexiTableEdit *editor = m_tableView->tableEditorWidget( col );
143 const bool insertRowSelected = m_tableView->isInsertingEnabled() && row==m_tableView->rows();
144 KexiTableItem *item = insertRowSelected ? m_tableView->m_insertItem : m_tableView->itemAt( row );
145 if (editor && item && (col < (int)item->count())) {
146 int w = m_tableView->columnWidth( col );
147 int h = m_tableView->rowHeight();
148 int x = 0;
149 int y_offset = 0;
150 int align = TQt::SingleLine | TQt::AlignVCenter;
151 TQString txtValue;
152 TQVariant cellValue;
153 KexiTableViewColumn *tvcol = m_tableView->column(col);
154 if (!m_tableView->getVisibleLookupValue(cellValue, editor, item, tvcol))
155 cellValue = insertRowSelected ? editor->displayedField()->defaultValue() : item->at(col); //display default value if available
156 const bool focused = m_tableView->selectedItem() == item && col == m_tableView->currentColumn();
157 editor->setupContents( 0, focused, cellValue, txtValue, align, x, y_offset, w, h );
158 TQRect realRect(m_tableView->columnPos(col)-m_tableView->contentsX(),
159 m_tableView->rowPos(row)-m_tableView->contentsY(), w, h); //m_tableView->cellGeometry( row, col ));
160 if (editor->showToolTipIfNeeded(
161 txtValue.isEmpty() ? item->at(col) : TQVariant(txtValue),
162 realRect, m_tableView->fontMetrics(), focused))
163 {
164 TQString squeezedTxtValue;
165 if (txtValue.length() > 50)
166 squeezedTxtValue = txtValue.left(100) + "...";
167 else
168 squeezedTxtValue = txtValue;
169 tip( realRect, squeezedTxtValue );
170 }
171 }
172 }
173}
174
175//-----------------------------------------
176
177KexiTableView::KexiTableView(KexiTableViewData* data, TQWidget* parent, const char* name)
178: TQScrollView(parent, name, /*TQt::WRepaintNoErase | */TQt::WStaticContents /*| TQt::WResizeNoErase*/)
182{
183//not needed KexiTableView::initCellEditorFactories();
184
185 d = new KexiTableViewPrivate(this);
186
187 connect( kapp, TQ_SIGNAL( settingsChanged(int) ), TQ_SLOT( slotSettingsChanged(int) ) );
188 slotSettingsChanged(TDEApplication::SETTINGS_SHORTCUTS);
189
190 m_data = new KexiTableViewData(); //to prevent crash because m_data==0
191 m_owner = true; //-this will be deleted if needed
192
193 setResizePolicy(Manual);
194 viewport()->setBackgroundMode(TQt::NoBackground);
195// viewport()->setFocusPolicy(TQWidget::StrongFocus);
196 viewport()->setFocusPolicy(TQWidget::WheelFocus);
197 setFocusPolicy(TQWidget::WheelFocus); //<--- !!!!! important (was NoFocus),
198 // otherwise TQApplication::setActiveWindow() won't activate
199 // this widget when needed!
200// setFocusProxy(viewport());
201 viewport()->installEventFilter(this);
202
203 //setup colors defaults
204 setBackgroundMode(TQt::PaletteBackground);
205// setEmptyAreaColor(d->appearance.baseColor);//palette().active().color(TQColorGroup::Base));
206
207// d->baseColor = colorGroup().base();
208// d->textColor = colorGroup().text();
209
210// d->altColor = TDEGlobalSettings::alternateBackgroundColor();
211// d->grayColor = TQColor(200,200,200);
212 d->diagonalGrayPattern = TQBrush(d->appearance.borderColor, TQt::BDiagPattern);
213
214 setLineWidth(1);
215 horizontalScrollBar()->installEventFilter(this);
216 horizontalScrollBar()->raise();
217 verticalScrollBar()->raise();
218
219 //context menu
220 m_popupMenu = new TDEPopupMenu(this, "contextMenu");
221#if 0 //moved to mainwindow's actions
222 d->menu_id_addRecord = m_popupMenu->insertItem(i18n("Add Record"), this, TQ_SLOT(addRecord()), TQt::CTRL+TQt::Key_Insert);
223 d->menu_id_removeRecord = m_popupMenu->insertItem(
224 kapp->iconLoader()->loadIcon("button_cancel", TDEIcon::Small),
225 i18n("Remove Record"), this, TQ_SLOT(removeRecord()), TQt::CTRL+TQt::Key_Delete);
226#endif
227
228#ifdef TQ_WS_WIN
229 d->rowHeight = fontMetrics().lineSpacing() + 4;
230#else
231 d->rowHeight = fontMetrics().lineSpacing() + 1;
232#endif
233
234 if(d->rowHeight < 17)
235 d->rowHeight = 17;
236
237 d->pUpdateTimer = new TQTimer(this);
238
239// setMargins(14, fontMetrics().height() + 4, 0, 0);
240
241 // Create headers
242 m_horizontalHeader = new KexiTableViewHeader(this, "topHeader");
243 m_horizontalHeader->setSelectionBackgroundColor( palette().active().highlight() );
244 m_horizontalHeader->setOrientation(TQt::Horizontal);
245 m_horizontalHeader->setTracking(false);
246 m_horizontalHeader->setMovingEnabled(false);
247 connect(m_horizontalHeader, TQ_SIGNAL(sizeChange(int,int,int)), this, TQ_SLOT(slotTopHeaderSizeChange(int,int,int)));
248
249 m_verticalHeader = new KexiRecordMarker(this, "rm");
250 m_verticalHeader->setSelectionBackgroundColor( palette().active().highlight() );
251 m_verticalHeader->setCellHeight(d->rowHeight);
252// m_verticalHeader->setFixedWidth(d->rowHeight);
253 m_verticalHeader->setCurrentRow(-1);
254
255 setMargins(
256 TQMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
257 m_horizontalHeader->sizeHint().height(), 0, 0);
258
259 setupNavigator();
260
261// setMinimumHeight(horizontalScrollBar()->height() + d->rowHeight + topMargin());
262
263// navPanelLyr->addStretch(25);
264// enableClipper(true);
265
266 if (data)
267 setData( data );
268
269#if 0//(js) doesn't work!
270 d->scrollTimer = new TQTimer(this);
271 connect(d->scrollTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotAutoScroll()));
272#endif
273
274// setBackgroundAltering(true);
275// setFullRowSelectionEnabled(false);
276
277 setAcceptDrops(true);
278 viewport()->setAcceptDrops(true);
279
280 // Connect header, table and scrollbars
281 connect(horizontalScrollBar(), TQ_SIGNAL(valueChanged(int)), m_horizontalHeader, TQ_SLOT(setOffset(int)));
282 connect(verticalScrollBar(), TQ_SIGNAL(valueChanged(int)), m_verticalHeader, TQ_SLOT(setOffset(int)));
283 connect(m_horizontalHeader, TQ_SIGNAL(sizeChange(int, int, int)), this, TQ_SLOT(slotColumnWidthChanged(int, int, int)));
284 connect(m_horizontalHeader, TQ_SIGNAL(sectionHandleDoubleClicked(int)), this, TQ_SLOT(slotSectionHandleDoubleClicked(int)));
285 connect(m_horizontalHeader, TQ_SIGNAL(clicked(int)), this, TQ_SLOT(sortColumnInternal(int)));
286
287 connect(d->pUpdateTimer, TQ_SIGNAL(timeout()), this, TQ_SLOT(slotUpdate()));
288
289// horizontalScrollBar()->show();
290 updateScrollBars();
291// resize(sizeHint());
292// updateContents();
293// setMinimumHeight(horizontalScrollBar()->height() + d->rowHeight + topMargin());
294
295//TMP
296//setVerticalHeaderVisible(false);
297//setHorizontalHeaderVisible(false);
298
299//will be updated by setAppearance: updateFonts();
300 setAppearance(d->appearance); //refresh
301
302 d->cellToolTip = new KexiTableViewCellToolTip(this);
303 new WhatsThis(this);
304}
305
306KexiTableView::~KexiTableView()
307{
309
311 m_data = 0;
312 if (m_owner) {
313 if (data)
314 data->deleteLater();
315 }
316 delete d;
317}
318
324
325/*void KexiTableView::initActions(TDEActionCollection *ac)
326{
327 emit reloadActions(ac);
328}*/
329
331{
332 updateScrollBars();
333
334 m_navPanel = new KexiRecordNavigator(this, leftMargin(), "navPanel");
336 m_navPanel->setSizePolicy(TQSizePolicy::Minimum,TQSizePolicy::Preferred);
337}
338
347
348void KexiTableView::addHeaderColumn(const TQString& caption, const TQString& description,
349 const TQIconSet& icon, int width)
350{
351 const int nr = m_horizontalHeader->count();
352 if (icon.isNull())
353 m_horizontalHeader->addLabel(caption, width);
354 else
355 m_horizontalHeader->addLabel(icon, caption, width);
356
357 if (!description.isEmpty())
358 m_horizontalHeader->setToolTip(nr, description);
359}
360
362{
363 TQSize s(tableSize());
364 resizeContents(s.width(), s.height());
365}
366
367void KexiTableView::slotRowsDeleted( const TQValueList<int> &rows )
368{
369 viewport()->repaint();
371 setCursorPosition(TQMAX(0, (int)m_curRow - (int)rows.count()), -1, true);
372}
373
374
375/*void KexiTableView::addDropFilter(const TQString &filter)
376{
377 d->dropFilters.append(filter);
378 viewport()->setAcceptDrops(true);
379}*/
380
381void KexiTableView::setFont( const TQFont &font )
382{
383 TQScrollView::setFont(font);
384 updateFonts(true);
385}
386
388{
389#ifdef TQ_WS_WIN
390 d->rowHeight = fontMetrics().lineSpacing() + 4;
391#else
392 d->rowHeight = fontMetrics().lineSpacing() + 1;
393#endif
394 if (d->appearance.fullRowSelection) {
395 d->rowHeight -= 1;
396 }
397 if(d->rowHeight < 17)
398 d->rowHeight = 17;
399// if(d->rowHeight < 22)
400// d->rowHeight = 22;
401 setMargins(
402 TQMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
403 m_horizontalHeader->sizeHint().height(), 0, 0);
404// setMargins(14, d->rowHeight, 0, 0);
405 m_verticalHeader->setCellHeight(d->rowHeight);
406
407 KexiDisplayUtils::initDisplayForAutonumberSign(d->autonumberSignDisplayParameters, this);
408 KexiDisplayUtils::initDisplayForDefaultValue(d->defaultValueDisplayParameters, this);
409
410 if (repaint)
411 updateContents();
412}
413
415{
416 //get last visible row
417 int r = rowAt(clipper()->height()+contentsY());
418 if (r==-1) {
419 r = rows()+1+(isInsertingEnabled()?1:0);
420 }
421 //update all visible rows below
422 int leftcol = m_horizontalHeader->sectionAt( m_horizontalHeader->offset() );
423// int row = m_curRow;
424 updateContents( columnPos( leftcol ), rowPos(row),
425 clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
426}
427
428void KexiTableView::clearColumnsInternal(bool /*repaint*/)
429{
430 while(m_horizontalHeader->count()>0)
431 m_horizontalHeader->removeLabel(0);
432}
433
435{
436// kdDebug(44021) << " KexiTableView::slotUpdate() -- " << endl;
437// TQSize s(tableSize());
438// viewport()->setUpdatesEnabled(false);
440// viewport()->setUpdatesEnabled(true);
441
442 updateContents();
443 updateScrollBars();
444 if (m_navPanel)
445 m_navPanel->updateGeometry(leftMargin());
446// updateNavPanelGeometry();
447
449// updateContents(0, contentsY()+clipper()->height()-2*d->rowHeight, clipper()->width(), d->rowHeight*3);
450
451 //updateGeometries();
452// updateContents(0, 0, viewport()->width(), contentsHeight());
453// updateGeometries();
454}
455
457{
458 if (m_horizontalHeader->sortIndicatorSection()==-1)
459 return 0;
460 return (m_horizontalHeader->sortIndicatorOrder() == TQt::Ascending) ? 1 : -1;
461}
462
464{
465 if (order == 0)
466 col = -1;
467 if (col>=0)
468 m_horizontalHeader->setSortIndicator(col, (order==1) ? TQt::Ascending : TQt::Descending);
469}
470
472{
473 return m_horizontalHeader->sortIndicatorSection();
474}
475
477{
478 int cw = columnWidth(m_curCol);
479 int rh = rowHeight();
480
481// m_verticalHeader->setCurrentRow(m_curRow);
482 center(columnPos(m_curCol) + cw / 2, rowPos(m_curRow) + rh / 2);
483// updateCell(oldRow, m_curCol);
484// updateCell(m_curRow, m_curCol);
485// slotUpdate();
486
487 updateContents();
488// d->pUpdateTimer->start(1,true);
489}
490
491TQSizePolicy KexiTableView::sizePolicy() const
492{
493 // this widget is expandable
494 return TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding);
495}
496
497TQSize KexiTableView::sizeHint() const
498{
499 const TQSize &ts = tableSize();
500 int w = TQMAX( ts.width() + leftMargin()+ verticalScrollBar()->sizeHint().width() + 2*2,
501 (m_navPanel->isVisible() ? m_navPanel->width() : 0) );
502 int h = TQMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(),
503 minimumSizeHint().height() );
504 w = TQMIN( w, tqApp->desktop()->width()*3/4 ); //stretch
505 h = TQMIN( h, tqApp->desktop()->height()*3/4 ); //stretch
506
507// kexidbg << "KexiTableView::sizeHint()= " <<w <<", " <<h << endl;
508
509 return TQSize(w, h);
510 /*TQSize(
511 TQMAX( ts.width() + leftMargin() + 2*2, (m_navPanel ? m_navPanel->width() : 0) ),
512 //+ TQMIN(m_verticalHeader->width(),d->rowHeight) + margin()*2,
513 TQMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(),
514 minimumSizeHint().height() )
515 );*/
516// TQMAX(ts.height() + topMargin(), minimumSizeHint().height()) );
517}
518
519TQSize KexiTableView::minimumSizeHint() const
520{
521 return TQSize(
522 leftMargin() + ((columns()>0)?columnWidth(0):KEXI_DEFAULT_DATA_COLUMN_WIDTH) + 2*2,
523 d->rowHeight*5/2 + topMargin() + (m_navPanel && m_navPanel->isVisible() ? m_navPanel->height() : 0)
524 );
525}
526
527void KexiTableView::createBuffer(int width, int height)
528{
529 if(!d->pBufferPm)
530 d->pBufferPm = new TQPixmap(width, height);
531 else
532 if(d->pBufferPm->width() < width || d->pBufferPm->height() < height)
533 d->pBufferPm->resize(width, height);
534// d->pBufferPm->fill();
535}
536
537//internal
538inline void KexiTableView::paintRow(KexiTableItem *item,
539 TQPainter *pb, int r, int rowp, int cx, int cy,
540 int colfirst, int collast, int maxwc)
541{
542 if (!item)
543 return;
544 // Go through the columns in the row r
545 // if we know from where to where, go through [colfirst, collast],
546 // else go through all of them
547 if (colfirst==-1)
548 colfirst=0;
549 if (collast==-1)
550 collast=columns()-1;
551
552 int transly = rowp-cy;
553
554 if (d->appearance.rowHighlightingEnabled && r == m_curRow && !d->appearance.fullRowSelection) {
555 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowHighlightingColor);
556 }
557 else if (d->appearance.rowMouseOverHighlightingEnabled && r == d->highlightedRow) {
558 if(d->appearance.backgroundAltering && (r%2 != 0))
559 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowMouseOverAlternateHighlightingColor);
560 else
561 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowMouseOverHighlightingColor);
562 }
563 else {
564 if(d->appearance.backgroundAltering && (r%2 != 0))
565 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.alternateBackgroundColor);
566 else
567 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.baseColor);
568 }
569
570 for(int c = colfirst; c <= collast; c++)
571 {
572 // get position and width of column c
573 int colp = columnPos(c);
574 if (colp==-1)
575 continue; //invisible column?
576 int colw = columnWidth(c);
577 int translx = colp-cx;
578
579 // Translate painter and draw the cell
580 pb->saveWorldMatrix();
581 pb->translate(translx, transly);
582 paintCell( pb, item, c, r, TQRect(colp, rowp, colw, d->rowHeight));
583 pb->restoreWorldMatrix();
584 }
585
586 if (m_dragIndicatorLine>=0) {
587 int y_line = -1;
588 if (r==(rows()-1) && m_dragIndicatorLine==rows()) {
589 y_line = transly+d->rowHeight-3; //draw at last line
590 }
591 if (m_dragIndicatorLine==r) {
592 y_line = transly+1;
593 }
594 if (y_line>=0) {
595 RasterOp op = pb->rasterOp();
596 pb->setRasterOp(XorROP);
597 pb->setPen( TQPen(TQt::white, 3) );
598 pb->drawLine(0, y_line, maxwc, y_line);
599 pb->setRasterOp(op);
600 }
601 }
602}
603
604void KexiTableView::drawContents( TQPainter *p, int cx, int cy, int cw, int ch)
605{
606 if (d->disableDrawContents)
607 return;
608 int colfirst = columnAt(cx);
609 int rowfirst = rowAt(cy);
610 int collast = columnAt(cx + cw-1);
611 int rowlast = rowAt(cy + ch-1);
612 bool inserting = isInsertingEnabled();
613 bool plus1row = false; //true if we should show 'inserting' row at the end
614 bool paintOnlyInsertRow = false;
615
616/* kdDebug(44021) << TQString(" KexiTableView::drawContents(cx:%1 cy:%2 cw:%3 ch:%4)")
617 .arg(cx).arg(cy).arg(cw).arg(ch) << endl;*/
618
619 if (rowlast == -1) {
620 rowlast = rows() - 1;
621 plus1row = inserting;
622 if (rowfirst == -1) {
623 if (rowAt(cy - d->rowHeight) != -1) {
624 paintOnlyInsertRow = true;
625// kdDebug(44021) << "-- paintOnlyInsertRow --" << endl;
626 }
627 }
628 }
629// kdDebug(44021) << "rowfirst="<<rowfirst<<" rowlast="<<rowlast<<" rows()="<<rows()<<endl;
630// kdDebug(44021)<<" plus1row=" << plus1row<<endl;
631
632 if ( collast == -1 )
633 collast = columns() - 1;
634
635 if (colfirst>collast) {
636 int tmp = colfirst;
637 colfirst = collast;
638 collast = tmp;
639 }
640 if (rowfirst>rowlast) {
641 int tmp = rowfirst;
642 rowfirst = rowlast;
643 rowlast = tmp;
644 }
645
646// tqDebug("cx:%3d cy:%3d w:%3d h:%3d col:%2d..%2d row:%2d..%2d tsize:%4d,%4d",
647// cx, cy, cw, ch, colfirst, collast, rowfirst, rowlast, tableSize().width(), tableSize().height());
648// triggerUpdate();
649
650 if (rowfirst == -1 || colfirst == -1) {
651 if (!paintOnlyInsertRow && !plus1row) {
652 paintEmptyArea(p, cx, cy, cw, ch);
653 return;
654 }
655 }
656
657 createBuffer(cw, ch);
658 if(d->pBufferPm->isNull())
659 return;
660 TQPainter *pb = new TQPainter(d->pBufferPm, this);
661// pb->fillRect(0, 0, cw, ch, colorGroup().base());
662
663// int maxwc = TQMIN(cw, (columnPos(d->numCols - 1) + columnWidth(d->numCols - 1)));
664 int maxwc = columnPos(columns() - 1) + columnWidth(columns() - 1);
665// kdDebug(44021) << "KexiTableView::drawContents(): maxwc: " << maxwc << endl;
666
667 pb->fillRect(cx, cy, cw, ch, d->appearance.baseColor);
668
669 int rowp;
670 int r;
671 if (paintOnlyInsertRow) {
672 r = rows();
673 rowp = rowPos(r); // 'insert' row's position
674 }
675 else {
676 TQPtrListIterator<KexiTableItem> it = m_data->iterator();
677 it += rowfirst;//move to 1st row
678 rowp = rowPos(rowfirst); // row position
679 for (r = rowfirst;r <= rowlast; r++, ++it, rowp+=d->rowHeight) {
680 paintRow(it.current(), pb, r, rowp, cx, cy, colfirst, collast, maxwc);
681 }
682 }
683
684 if (plus1row) { //additional - 'insert' row
685 paintRow(m_insertItem, pb, r, rowp, cx, cy, colfirst, collast, maxwc);
686 }
687
688 delete pb;
689
690 p->drawPixmap(cx,cy,*d->pBufferPm, 0,0,cw,ch);
691
692 //(js)
693 paintEmptyArea(p, cx, cy, cw, ch);
694}
695
696bool KexiTableView::isDefaultValueDisplayed(KexiTableItem *item, int col, TQVariant* value)
697{
698 const bool cursorAtInsertRowOrEditingNewRow = (item == m_insertItem || (m_newRowEditing && m_currentItem == item));
699 KexiTableViewColumn *tvcol;
700 if (cursorAtInsertRowOrEditingNewRow
701 && (tvcol = m_data->column(col))
702 && hasDefaultValueAt(*tvcol)
703 && !tvcol->field()->isAutoIncrement())
704 {
705 if (value)
706 *value = tvcol->field()->defaultValue();
707 return true;
708 }
709 return false;
710}
711
712void KexiTableView::paintCell(TQPainter* p, KexiTableItem *item, int col, int row, const TQRect &cr, bool print)
713{
714 p->save();
715 Q_UNUSED(print);
716 int w = cr.width();
717 int h = cr.height();
718 int x2 = w - 1;
719 int y2 = h - 1;
720
721/* if (0==qstrcmp("KexiComboBoxPopup",parentWidget()->className())) {
722 kexidbg << parentWidget()->className() << " >>>>>> KexiTableView::paintCell(col=" << col <<"row="<<row<<") w="<<w<<endl;
723 }*/
724
725 // Draw our lines
726 TQPen pen(p->pen());
727
728 if (d->appearance.gridEnabled) {
729 p->setPen(d->appearance.borderColor);
730 p->drawLine( x2, 0, x2, y2 ); // right
731 p->drawLine( 0, y2, x2, y2 ); // bottom
732 }
733 p->setPen(pen);
734
735 if (m_editor && row == m_curRow && col == m_curCol //don't paint contents of edited cell
736 && m_editor->hasFocusableWidget() //..if it's visible
737 ) {
738 p->restore();
739 return;
740 }
741
742 KexiTableEdit *edit = tableEditorWidget( col, /*ignoreMissingEditor=*/true );
743// if (!edit)
744// return;
745
746 int x = edit ? edit->leftMargin() : 0;
747 int y_offset=0;
748
749 int align = TQt::SingleLine | TQt::AlignVCenter;
750 TQString txt; //text to draw
751
752 KexiTableViewColumn *tvcol = m_data->column(col);
753
754 TQVariant cellValue;
755 if (col < (int)item->count()) {
756 if (m_currentItem == item) {
757 if (m_editor && row == m_curRow && col == m_curCol
758 && !m_editor->hasFocusableWidget())
759 {
760 //we're over editing cell and the editor has no widget
761 // - we're displaying internal values, not buffered
762// bool ok;
763 cellValue = m_editor->value();
764 }
765 else {
766 //we're displaying values from edit buffer, if available
767 // this assignment will also get default value if there's no actual value set
768 cellValue = *bufferedValueAt(col);
769 }
770 }
771 else {
772 cellValue = item->at(col);
773 }
774 }
775
776 bool defaultValueDisplayed = isDefaultValueDisplayed(item, col);
777
778 if ((item == m_insertItem /*|| m_newRowEditing*/) && cellValue.isNull()) {
779 if (!tvcol->field()->isAutoIncrement() && !tvcol->field()->defaultValue().isNull()) {
780 //display default value in the "insert row", if available
781 //(but not if there is autoincrement flag set)
782 cellValue = tvcol->field()->defaultValue();
783 defaultValueDisplayed = true;
784 }
785 }
786
787 const bool columnReadOnly = tvcol->isReadOnly();
788 const bool dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
789 = d->appearance.rowHighlightingEnabled && !d->appearance.persistentSelections
790 && m_curRow /*d->highlightedRow*/ >= 0 && row != m_curRow; //d->highlightedRow;
791
792 // setup default pen
793 TQPen defaultPen;
794 const bool usesSelectedTextColor = edit && edit->usesSelectedTextColor();
795 if (defaultValueDisplayed) {
796 if (col == m_curCol && row == m_curRow && usesSelectedTextColor)
797 defaultPen = TQPen(d->defaultValueDisplayParameters.selectedTextColor);
798 else
799 defaultPen = TQPen(d->defaultValueDisplayParameters.textColor);
800 }
801 else if (d->appearance.fullRowSelection
802 && (row == d->highlightedRow || (row == m_curRow && d->highlightedRow==-1))
803 && usesSelectedTextColor )
804 {
805 defaultPen = TQPen(d->appearance.rowHighlightingTextColor); //special case: highlighted row
806 }
807 else if (d->appearance.fullRowSelection && row == m_curRow && usesSelectedTextColor)
808 {
809 defaultPen = TQPen(d->appearance.textColor); //special case for full row selection
810 }
811 else if (m_currentItem == item && col == m_curCol && !columnReadOnly
812 && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
813 && usesSelectedTextColor)
814 {
815 defaultPen = TQPen(colorGroup().highlightedText()); //selected text
816 }
817 else if (d->appearance.rowHighlightingEnabled && row == m_curRow
818 && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
819 && usesSelectedTextColor)
820 {
821 defaultPen = TQPen(d->appearance.rowHighlightingTextColor);
822 }
823 else if (d->appearance.rowMouseOverHighlightingEnabled && row == d->highlightedRow
824 && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
825 && usesSelectedTextColor)
826 {
827 defaultPen = TQPen(d->appearance.rowMouseOverHighlightingTextColor);
828 }
829 else
830 defaultPen = TQPen(d->appearance.textColor);
831
832 if (edit) {
833 if (defaultValueDisplayed)
834 p->setFont( d->defaultValueDisplayParameters.font );
835 p->setPen( defaultPen );
836
837 //get visible lookup value if available
838 getVisibleLookupValue(cellValue, edit, item, tvcol);
839
840 edit->setupContents( p, m_currentItem == item && col == m_curCol,
841 cellValue, txt, align, x, y_offset, w, h );
842 }
843 if (!d->appearance.gridEnabled)
844 y_offset++; //correction because we're not drawing cell borders
845
846 if (d->appearance.fullRowSelection && d->appearance.fullRowSelection) {
847// p->fillRect(x, y_offset, x+w-1, y_offset+h-1, red);
848 }
849 if (m_currentItem == item && (col == m_curCol || d->appearance.fullRowSelection)) {
850 if (edit && ((d->appearance.rowHighlightingEnabled && !d->appearance.fullRowSelection) || (row == m_curRow && d->highlightedRow==-1 && d->appearance.fullRowSelection)))
851 edit->paintSelectionBackground( p, isEnabled(), txt, align, x, y_offset, w, h,
852 isEnabled() ? colorGroup().highlight() : TQColor(200,200,200),//d->grayColor,
853 p->fontMetrics(), columnReadOnly, d->appearance.fullRowSelection );
854 }
855
856 if (!edit) {
857 p->fillRect(0, 0, x2, y2, d->diagonalGrayPattern);
858 }
859
860// If we are in the focus cell, draw indication
861 if(m_currentItem == item && col == m_curCol //js: && !d->recordIndicator)
862 && !d->appearance.fullRowSelection)
863 {
864// kexidbg << ">>> CURRENT CELL ("<<m_curCol<<"," << m_curRow<<") focus="<<has_focus<<endl;
865// if (has_focus) {
866 if (isEnabled()) {
867 p->setPen(d->appearance.textColor);
868 }
869 else {
870 TQPen gray_pen(p->pen());
871 gray_pen.setColor(d->appearance.borderColor);
872 p->setPen(gray_pen);
873 }
874 if (edit)
875 edit->paintFocusBorders( p, cellValue, 0, 0, x2, y2 );
876 else
877 p->drawRect(0, 0, x2, y2);
878 }
879
881 if ((!m_newRowEditing && item == m_insertItem)
882 || (m_newRowEditing && item == m_currentItem && cellValue.isNull())) {
883 //we're in "insert row"
884 if (tvcol->field()->isAutoIncrement()) {
885 //"autonumber" column
886// txt = i18n("(autonumber)");
887// autonumber = true;
888// if (autonumber) {
889 KexiDisplayUtils::paintAutonumberSign(d->autonumberSignDisplayParameters, p,
890 x, y_offset, w - x - x - ((align & TQt::AlignLeft)?2:0), h, align);
891// }
892 }
893 }
894
895 // draw text
896 if (!txt.isEmpty()) {
897 if (defaultValueDisplayed)
898 p->setFont( d->defaultValueDisplayParameters.font );
899 p->setPen( defaultPen );
900 p->drawText(x, y_offset, w - (x + x)- ((align & TQt::AlignLeft)?2:0)/*right space*/, h,
901 align, txt);
902 }
903 p->restore();
904}
905
906TQPoint KexiTableView::contentsToViewport2( const TQPoint &p )
907{
908 return TQPoint( p.x() - contentsX(), p.y() - contentsY() );
909}
910
911void KexiTableView::contentsToViewport2( int x, int y, int& vx, int& vy )
912{
913 const TQPoint v = contentsToViewport2( TQPoint( x, y ) );
914 vx = v.x();
915 vy = v.y();
916}
917
918TQPoint KexiTableView::viewportToContents2( const TQPoint& vp )
919{
920 return TQPoint( vp.x() + contentsX(),
921 vp.y() + contentsY() );
922}
923
924void KexiTableView::paintEmptyArea( TQPainter *p, int cx, int cy, int cw, int ch )
925{
926// tqDebug("%s: paintEmptyArea(x:%d y:%d w:%d h:%d)", (const char*)parentWidget()->caption(),cx,cy,cw,ch);
927
928 // Regions work with shorts, so avoid an overflow and adjust the
929 // table size to the visible size
930 TQSize ts( tableSize() );
931// ts.setWidth( TQMIN( ts.width(), visibleWidth() ) );
932// ts.setHeight( TQMIN( ts.height() - (m_navPanel ? m_navPanel->height() : 0), visibleHeight()) );
933/* kdDebug(44021) << TQString(" (cx:%1 cy:%2 cw:%3 ch:%4)")
934 .arg(cx).arg(cy).arg(cw).arg(ch) << endl;
935 kdDebug(44021) << TQString(" (w:%3 h:%4)")
936 .arg(ts.width()).arg(ts.height()) << endl;*/
937
938 // Region of the rect we should draw, calculated in viewport
939 // coordinates, as a region can't handle bigger coordinates
940 contentsToViewport2( cx, cy, cx, cy );
941 TQRegion reg( TQRect( cx, cy, cw, ch ) );
942
943//kexidbg << "---cy-- " << contentsY() << endl;
944
945 // Subtract the table from it
946// reg = reg.subtract( TQRect( TQPoint( 0, 0 ), ts-TQSize(0,m_navPanel->isVisible() ? m_navPanel->height() : 0) ) );
947 reg = reg.subtract( TQRect( TQPoint( 0, 0 ), ts
948 -TQSize(0,TQMAX((m_navPanel ? m_navPanel->height() : 0), horizontalScrollBar()->sizeHint().height())
949 - (horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height()/2 : 0)
950 + (horizontalScrollBar()->isVisible() ? 0 :
951 d->internal_bottomMargin
952// horizontalScrollBar()->sizeHint().height()/2
953 )
954//- /*d->bottomMargin */ horizontalScrollBar()->sizeHint().height()*3/2
955 + contentsY()
956// - (verticalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height()/2 : 0)
957 )
958 ) );
959// reg = reg.subtract( TQRect( TQPoint( 0, 0 ), ts ) );
960
961 // And draw the rectangles (transformed inc contents coordinates as needed)
962 TQMemArray<TQRect> r = reg.rects();
963 for ( int i = 0; i < (int)r.count(); i++ ) {
964 TQRect rect( viewportToContents2(r[i].topLeft()), r[i].size() );
965/* kdDebug(44021) << TQString("- pEA: p->fillRect(x:%1 y:%2 w:%3 h:%4)")
966 .arg(rect.x()).arg(rect.y())
967 .arg(rect.width()).arg(rect.height()) << endl;*/
968// p->fillRect( TQRect(viewportToContents2(r[i].topLeft()),r[i].size()), d->emptyAreaColor );
969 p->fillRect( rect, d->appearance.emptyAreaColor );
970// p->fillRect( TQRect(viewportToContents2(r[i].topLeft()),r[i].size()), viewport()->backgroundBrush() );
971 }
972}
973
974void KexiTableView::contentsMouseDoubleClickEvent(TQMouseEvent *e)
975{
976// kdDebug(44021) << "KexiTableView::contentsMouseDoubleClickEvent()" << endl;
978 contentsMousePressEvent(e);
980
981 if(m_currentItem)
982 {
983 if(d->editOnDoubleClick && columnEditable(m_curCol) && columnType(m_curCol) != KexiDB::Field::Boolean) {
984 KexiTableEdit *edit = tableEditorWidget( m_curCol, /*ignoreMissingEditor=*/true );
985 if (edit && edit->handleDoubleClick()) {
986 //nothing to do: editors like BLOB editor has custom handling of double clicking
987 }
988 else {
990 // createEditor(m_curRow, m_curCol, TQString());
991 }
992 }
993
994 emit itemDblClicked(m_currentItem, m_curRow, m_curCol);
995 }
996}
997
998void KexiTableView::contentsMousePressEvent( TQMouseEvent* e )
999{
1000// kdDebug(44021) << "KexiTableView::contentsMousePressEvent() ??" << endl;
1001 setFocus();
1002 if(m_data->count()==0 && !isInsertingEnabled()) {
1003 TQScrollView::contentsMousePressEvent( e );
1004 return;
1005 }
1006
1007 if (columnAt(e->pos().x())==-1) { //outside a colums
1008 TQScrollView::contentsMousePressEvent( e );
1009 return;
1010 }
1011// d->contentsMousePressEvent_ev = *e;
1012// d->contentsMousePressEvent_enabled = true;
1013// TQTimer::singleShot(2000, this, TQ_SLOT( contentsMousePressEvent_Internal() ));
1014// d->contentsMousePressEvent_timer.start(100,true);
1015
1016// if (!d->contentsMousePressEvent_enabled)
1017// return;
1018// d->contentsMousePressEvent_enabled=false;
1019
1020 if (!d->moveCursorOnMouseRelease) {
1021 if (!handleContentsMousePressOrRelease(e, false))
1022 return;
1023 }
1024
1025// kdDebug(44021)<<"void KexiTableView::contentsMousePressEvent( TQMouseEvent* e ) by now the current items should be set, if not -> error + crash"<<endl;
1026 if(e->button() == TQt::RightButton)
1027 {
1028 showContextMenu(e->globalPos());
1029 }
1030 else if(e->button() == TQt::LeftButton)
1031 {
1032 if(columnType(m_curCol) == KexiDB::Field::Boolean && columnEditable(m_curCol))
1033 {
1034 //only accept clicking on the [x] rect (copied from KexiBoolTableEdit::setupContents())
1035 int s = TQMAX(d->rowHeight - 5, 12);
1036 s = TQMIN( d->rowHeight-3, s );
1037 s = TQMIN( columnWidth(m_curCol)-3, s ); //avoid too large box
1038 const TQRect r( columnPos(m_curCol) + TQMAX( columnWidth(m_curCol)/2 - s/2, 0 ), rowPos(m_curRow) +d->rowHeight/2 - s/2 /*- 1*/, s, s);
1039 //kexidbg << r << endl;
1040 if (r.contains(e->pos())) {
1041// kexidbg << "e->x:" << e->x() << " e->y:" << e->y() << " " << rowPos(m_curRow) <<
1042// " " << columnPos(m_curCol) << endl;
1043 boolToggled();
1044 }
1045 }
1046#if 0 //js: TODO
1047 else if(columnType(m_curCol) == TQVariant::StringList && columnEditable(m_curCol))
1048 {
1049 createEditor(m_curRow, m_curCol);
1050 }
1051#endif
1052 }
1053//ScrollView::contentsMousePressEvent( e );
1054}
1055
1056void KexiTableView::contentsMouseReleaseEvent( TQMouseEvent* e )
1057{
1058// kdDebug(44021) << "KexiTableView::contentsMousePressEvent() ??" << endl;
1059 if(m_data->count()==0 && !isInsertingEnabled())
1060 return;
1061
1062 if (d->moveCursorOnMouseRelease)
1063 handleContentsMousePressOrRelease(e, true);
1064
1065 int col = columnAt(e->pos().x());
1066 int row = rowAt(e->pos().y());
1067
1068 if (!m_currentItem || col==-1 || row==-1 || col!=m_curCol || row!=m_curRow)//outside a current cell
1069 return;
1070
1071 TQScrollView::contentsMouseReleaseEvent( e );
1072
1073 emit itemMouseReleased(m_currentItem, m_curRow, m_curCol);
1074}
1075
1076bool KexiTableView::handleContentsMousePressOrRelease(TQMouseEvent* e, bool release)
1077{
1078 // remember old focus cell
1079 int oldRow = m_curRow;
1080 int oldCol = m_curCol;
1081 kdDebug(44021) << "oldRow=" << oldRow <<" oldCol=" << oldCol <<endl;
1082 bool onInsertItem = false;
1083
1084 int newrow, newcol;
1085 //compute clicked row nr
1086 if (isInsertingEnabled()) {
1087 if (rowAt(e->pos().y())==-1) {
1088 newrow = rowAt(e->pos().y() - d->rowHeight);
1089 if (newrow==-1 && m_data->count()>0) {
1090 if (release)
1091 TQScrollView::contentsMouseReleaseEvent( e );
1092 else
1093 TQScrollView::contentsMousePressEvent( e );
1094 return false;
1095 }
1096 newrow++;
1097 kdDebug(44021) << "Clicked just on 'insert' row." << endl;
1098 onInsertItem=true;
1099 }
1100 else {
1101 // get new focus cell
1102 newrow = rowAt(e->pos().y());
1103 }
1104 }
1105 else {
1106 if (rowAt(e->pos().y())==-1 || columnAt(e->pos().x())==-1) {
1107 if (release)
1108 TQScrollView::contentsMouseReleaseEvent( e );
1109 else
1110 TQScrollView::contentsMousePressEvent( e );
1111 return false; //clicked outside a grid
1112 }
1113 // get new focus cell
1114 newrow = rowAt(e->pos().y());
1115 }
1116 newcol = columnAt(e->pos().x());
1117
1118 if(e->button() != TQt::NoButton) {
1119 setCursorPosition(newrow,newcol);
1120 }
1121 return true;
1122}
1123
1124void KexiTableView::showContextMenu(const TQPoint& _pos)
1125{
1126 if (!d->contextMenuEnabled || m_popupMenu->count()<1)
1127 return;
1128 TQPoint pos(_pos);
1129 if (pos==TQPoint(-1,-1)) {
1130 pos = viewport()->mapToGlobal( TQPoint( columnPos(m_curCol), rowPos(m_curRow) + d->rowHeight ) );
1131 }
1132 //show own context menu if configured
1133// if (updateContextMenu()) {
1134 selectRow(m_curRow);
1135 m_popupMenu->exec(pos);
1136/* }
1137 else {
1138 //request other context menu
1139 emit contextMenuRequested(m_currentItem, m_curCol, pos);
1140 }*/
1141}
1142
1143void KexiTableView::contentsMouseMoveEvent( TQMouseEvent *e )
1144{
1145 int row;
1146 const int col = columnAt(e->x());
1147 if (col < 0) {
1148 row = -1;
1149 } else {
1150 row = rowAt( e->y(), true /*ignoreEnd*/ );
1151 if (row > (rows() - 1 + (isInsertingEnabled()?1:0)))
1152 row = -1; //no row to paint
1153 }
1154// kexidbg << " row="<<row<< " col="<<col<<endl;
1155 //update row highlight if needed
1156 if (d->appearance.rowMouseOverHighlightingEnabled) {
1157 if (row != d->highlightedRow) {
1158 const int oldRow = d->highlightedRow;
1159 d->highlightedRow = row;
1160 updateRow(oldRow);
1161 updateRow(d->highlightedRow);
1162 //currently selected (not necessary highlighted) row needs to be repainted
1164 m_verticalHeader->setHighlightedRow(d->highlightedRow);
1165 }
1166 }
1167
1168#if 0//(js) doesn't work!
1169
1170 // do the same as in mouse press
1171 int x,y;
1172 contentsToViewport(e->x(), e->y(), x, y);
1173
1174 if(y > visibleHeight())
1175 {
1176 d->needAutoScroll = true;
1177 d->scrollTimer->start(70, false);
1178 d->scrollDirection = ScrollDown;
1179 }
1180 else if(y < 0)
1181 {
1182 d->needAutoScroll = true;
1183 d->scrollTimer->start(70, false);
1184 d->scrollDirection = ScrollUp;
1185 }
1186 else if(x > visibleWidth())
1187 {
1188 d->needAutoScroll = true;
1189 d->scrollTimer->start(70, false);
1190 d->scrollDirection = ScrollRight;
1191 }
1192 else if(x < 0)
1193 {
1194 d->needAutoScroll = true;
1195 d->scrollTimer->start(70, false);
1196 d->scrollDirection = ScrollLeft;
1197 }
1198 else
1199 {
1200 d->needAutoScroll = false;
1201 d->scrollTimer->stop();
1202 contentsMousePressEvent(e);
1203 }
1204#endif
1205 TQScrollView::contentsMouseMoveEvent(e);
1206}
1207
1208#if 0//(js) doesn't work!
1209void KexiTableView::contentsMouseReleaseEvent(TQMouseEvent *)
1210{
1211 if(d->needAutoScroll)
1212 {
1213 d->scrollTimer->stop();
1214 }
1215}
1216#endif
1217
1218static bool overrideEditorShortcutNeeded(TQKeyEvent *e)
1219{
1220 //perhaps more to come...
1221 return e->key() == TQt::Key_Delete && e->state()==TQt::ControlButton;
1222}
1223
1224bool KexiTableView::shortCutPressed( TQKeyEvent *e, const TQCString &action_name )
1225{
1226 const int k = e->key();
1227 TDEAction *action = m_sharedActions[action_name];
1228 if (action) {
1229 if (!action->isEnabled())//this action is disabled - don't process it!
1230 return false;
1231 if (action->shortcut() == TDEShortcut( KKey(e) )) {
1232 //special cases when we need to override editor's shortcut
1233 if (overrideEditorShortcutNeeded(e)) {
1234 return true;
1235 }
1236 return false;//this shortcut is owned by shared action - don't process it!
1237 }
1238 }
1239
1240 //check default shortcut (when user app has no action shortcuts defined
1241 // but we want these shortcuts to still work)
1242 if (action_name=="data_save_row")
1243 return (k == TQt::Key_Return || k == TQt::Key_Enter) && e->state()==TQt::ShiftButton;
1244 if (action_name=="edit_delete_row")
1245 return k == TQt::Key_Delete && e->state()==TQt::ControlButton;
1246 if (action_name=="edit_delete")
1247 return k == TQt::Key_Delete && e->state()==TQt::NoButton;
1248 if (action_name=="edit_edititem")
1249 return k == TQt::Key_F2 && e->state()==TQt::NoButton;
1250 if (action_name=="edit_insert_empty_row")
1251 return k == TQt::Key_Insert && e->state()==(TQt::ShiftButton | TQt::ControlButton);
1252
1253 return false;
1254}
1255
1257{
1258 if (!hasData())
1259 return;
1260// kexidbg << "KexiTableView::keyPressEvent: key=" <<e->key() << " txt=" <<e->text()<<endl;
1261
1262 const int k = e->key();
1263 const bool ro = isReadOnly();
1264 TQWidget *w = focusWidget();
1265// if (!w || w!=viewport() && w!=this && (!m_editor || w!=m_editor->view() && w!=m_editor)) {
1266// if (!w || w!=viewport() && w!=this && (!m_editor || w!=m_editor->view())) {
1267 if (!w || w!=viewport() && w!=this && (!m_editor || !KexiUtils::hasParent(dynamic_cast<TQObject*>(m_editor), w))) {
1268 //don't process stranger's events
1269 e->ignore();
1270 return;
1271 }
1272 if (d->skipKeyPress) {
1273 d->skipKeyPress=false;
1274 e->ignore();
1275 return;
1276 }
1277
1278 if(m_currentItem == 0 && (m_data->count() > 0 || isInsertingEnabled()))
1279 {
1280 setCursorPosition(0,0);
1281 }
1282 else if(m_data->count() == 0 && !isInsertingEnabled())
1283 {
1284 e->accept();
1285 return;
1286 }
1287
1288 if(m_editor) {// if a cell is edited, do some special stuff
1289 if (k == TQt::Key_Escape) {
1290 cancelEditor();
1291 e->accept();
1292 return;
1293 } else if (k == TQt::Key_Return || k == TQt::Key_Enter) {
1294 if (columnType(m_curCol) == KexiDB::Field::Boolean) {
1295 boolToggled();
1296 }
1297 else {
1298 acceptEditor();
1299 }
1300 e->accept();
1301 return;
1302 }
1303 }
1304 else if (m_rowEditing) {// if a row is in edit mode, do some special stuff
1305 if (shortCutPressed( e, "data_save_row")) {
1306 kexidbg << "shortCutPressed!!!" <<endl;
1307 acceptRowEdit();
1308 return;
1309 }
1310 }
1311
1312 if(k == TQt::Key_Return || k == TQt::Key_Enter)
1313 {
1314 emit itemReturnPressed(m_currentItem, m_curRow, m_curCol);
1315 }
1316
1317 int curRow = m_curRow;
1318 int curCol = m_curCol;
1319
1320 const bool nobtn = e->state()==TQt::NoButton;
1321 bool printable = false;
1322
1323 //check shared shortcuts
1324 if (!ro) {
1325 if (shortCutPressed(e, "edit_delete_row")) {
1327 e->accept();
1328 return;
1329 } else if (shortCutPressed(e, "edit_delete")) {
1331 e->accept();
1332 return;
1333 }
1334 else if (shortCutPressed(e, "edit_insert_empty_row")) {
1336 e->accept();
1337 return;
1338 }
1339 }
1340
1341/* case TQt::Key_Delete:
1342 if (e->state()==TQt::ControlButton) {//remove current row
1343 deleteCurrentRow();
1344 }
1345 else if (nobtn) {//remove contents of the current cell
1346 deleteAndStartEditCurrentCell();
1347 }
1348 break;*/
1349
1350// bool _return;
1351 if (k == TQt::Key_Shift || k == TQt::Key_Alt || k == TQt::Key_Control || k == TQt::Key_Meta) {
1352 e->ignore();
1353 }
1354 else if (KexiDataAwareObjectInterface::handleKeyPress(e, curRow, curCol, d->appearance.fullRowSelection)) {
1355 if (e->isAccepted())
1356 return;
1357 }
1358 else if (k == TQt::Key_Backspace && nobtn) {
1359 if (!ro && columnType(curCol) != KexiDB::Field::Boolean && columnEditable(curCol))
1360 createEditor(curRow, curCol, TQString(), true);
1361 }
1362 else if (k == TQt::Key_Space) {
1363 if (nobtn && !ro && columnEditable(curCol)) {
1364 if (columnType(curCol) == KexiDB::Field::Boolean) {
1365 boolToggled();
1366 }
1367 else
1368 printable = true; //just space key
1369 }
1370 }
1371 else if (k == TQt::Key_Escape) {
1372 if (nobtn && m_rowEditing) {
1373 cancelRowEdit();
1374 return;
1375 }
1376 }
1377 else {
1378 //others:
1379 if (nobtn && (k==TQt::Key_Tab || k==TQt::Key_Right)) {
1381 //tab
1382 if (acceptEditor()) {
1383 if (curCol == (columns() - 1)) {
1384 if (curRow < (rows()-1+(isInsertingEnabled()?1:0))) {//skip to next row
1385 curRow++;
1386 curCol = 0;
1387 }
1388 }
1389 else
1390 curCol++;
1391 }
1392 }
1393 else if ((e->state()==TQt::ShiftButton && k==TQt::Key_Tab)
1394 || (nobtn && k==TQt::Key_Backtab)
1395 || (e->state()==TQt::ShiftButton && k==TQt::Key_Backtab)
1396 || (nobtn && k==TQt::Key_Left)
1397 ) {
1399 //backward tab
1400 if (acceptEditor()) {
1401 if (curCol == 0) {
1402 if (curRow>0) {//skip to previous row
1403 curRow--;
1404 curCol = columns() - 1;
1405 }
1406 }
1407 else
1408 curCol--;
1409 }
1410 }
1411 else if (nobtn && k==d->contextMenuKey) { //TQt::Key_Menu:
1413 }
1414 else {
1415 KexiTableEdit *edit = tableEditorWidget( m_curCol );
1416 if (edit && edit->handleKeyPress(e, m_editor==edit)) {
1417 //try to handle the event @ editor's level
1418 e->accept();
1419 return;
1420 }
1421 else if ( nobtn && (k==TQt::Key_Enter || k==TQt::Key_Return || shortCutPressed(e, "edit_edititem")) ) {
1422 //this condition is moved after handleKeyPress() to allow to everride enter key as well
1424 }
1425 else {
1426 kexidbg << "KexiTableView::KeyPressEvent(): default" << endl;
1427 if (e->text().isEmpty() || !e->text().isEmpty() && !e->text()[0].isPrint() ) {
1428 kdDebug(44021) << "NOT PRINTABLE: 0x0" << TQString("%1").arg(k,0,16) <<endl;
1429 // e->ignore();
1430 TQScrollView::keyPressEvent(e);
1431 return;
1432 }
1433 printable = true;
1434 }
1435 }
1436 }
1437 //finally: we've printable char:
1438 if (printable && !ro) {
1439 KexiTableViewColumn *tvcol = m_data->column(curCol);
1440 if (tvcol->acceptsFirstChar(TQString(e->text())[0])) {
1441 kdDebug(44021) << "KexiTableView::KeyPressEvent(): ev pressed: acceptsFirstChar()==true" << endl;
1442 // if (e->text()[0].isPrint())
1443 createEditor(curRow, curCol, e->text(), true);
1444 }
1445 else {
1446//TODO show message "key not allowed eg. on a statusbar"
1447 kdDebug(44021) << "KexiTableView::KeyPressEvent(): ev pressed: acceptsFirstChar()==false" << endl;
1448 }
1449 }
1450
1452
1453 // if focus cell changes, repaint
1454 setCursorPosition(curRow, curCol);
1455
1457
1458 e->accept();
1459}
1460
1461void KexiTableView::emitSelected()
1462{
1463 if(m_currentItem)
1464 emit itemSelected(m_currentItem);
1465}
1466
1468{
1469 return visibleHeight() / d->rowHeight;
1470}
1471
1472KexiDataItemInterface *KexiTableView::editor( int col, bool ignoreMissingEditor )
1473{
1474 if (!m_data || col<0 || col>=columns())
1475 return 0;
1476 KexiTableViewColumn *tvcol = m_data->column(col);
1477// int t = tvcol->field->type();
1478
1479 //find the editor for this column
1480 KexiTableEdit *editor = d->editors[ tvcol ];
1481 if (editor)
1482 return editor;
1483
1484 //not found: create
1485// editor = KexiCellEditorFactory::createEditor(*m_data->column(col)->field, this);
1487 if (!editor) {//create error!
1488 if (!ignoreMissingEditor) {
1489 //js TODO: show error???
1490 cancelRowEdit();
1491 }
1492 return 0;
1493 }
1494 editor->hide();
1495 if (m_data->cursor() && m_data->cursor()->query())
1496 editor->createInternalEditor(*m_data->cursor()->query());
1497
1498 connect(editor,TQ_SIGNAL(editRequested()),this,TQ_SLOT(slotEditRequested()));
1499 connect(editor,TQ_SIGNAL(cancelRequested()),this,TQ_SLOT(cancelEditor()));
1500 connect(editor,TQ_SIGNAL(acceptRequested()),this,TQ_SLOT(acceptEditor()));
1501
1502 editor->resize(columnWidth(col)-1, rowHeight()-1);
1503 editor->installEventFilter(this);
1504 if (editor->widget())
1505 editor->widget()->installEventFilter(this);
1506 //store
1507 d->editors.insert( tvcol, editor );
1508 return editor;
1509}
1510
1511void KexiTableView::editorShowFocus( int /*row*/, int col )
1512{
1513 KexiDataItemInterface *edit = editor( col );
1514 /*nt p = rowPos(row);
1515 (!edit || (p < contentsY()) || (p > (contentsY()+clipper()->height()))) {
1516 kexidbg<< "KexiTableView::editorShowFocus() : OUT" << endl;
1517 return;
1518 }*/
1519 if (edit) {
1520 kexidbg<< "KexiTableView::editorShowFocus() : IN" << endl;
1521 TQRect rect = cellGeometry( m_curRow, m_curCol );
1522// rect.moveBy( -contentsX(), -contentsY() );
1523 edit->showFocus( rect, isReadOnly() || m_data->column(col)->isReadOnly() );
1524 }
1525}
1526
1528{
1529 createEditor(m_curRow, m_curCol);
1530}
1531
1534 updateContents();
1535}
1536
1537void KexiTableView::createEditor(int row, int col, const TQString& addText, bool removeOld)
1538{
1539 kdDebug(44021) << "KexiTableView::createEditor('"<<addText<<"',"<<removeOld<<")"<<endl;
1540 if (isReadOnly()) {
1541 kdDebug(44021) << "KexiTableView::createEditor(): DATA IS READ ONLY!"<<endl;
1542 return;
1543 }
1544
1545 if (m_data->column(col)->isReadOnly()) {//d->pColumnModes.at(d->numCols-1) & ColumnReadOnly)
1546 kdDebug(44021) << "KexiTableView::createEditor(): COL IS READ ONLY!"<<endl;
1547 return;
1548 }
1549
1550 const bool startRowEdit = !m_rowEditing; //remember if we're starting row edit
1551
1552 if (!m_rowEditing) {
1553 //we're starting row editing session
1555
1556 m_rowEditing = true;
1557 //indicate on the vheader that we are editing:
1560 //we should know that we are in state "new row editing"
1561 m_newRowEditing = true;
1562 //'insert' row editing: show another row after that:
1563 m_data->append( m_insertItem );
1564 //new empty 'inserting' item
1565 m_insertItem = m_data->createItem();
1566 m_verticalHeader->addLabel();
1569 //refr. current and next row
1570 updateContents(columnPos(0), rowPos(row), viewport()->width(), d->rowHeight*2);
1571// updateContents(columnPos(0), rowPos(row+1), viewport()->width(), d->rowHeight);
1572//js: warning this breaks behaviour (cursor is skipping, etc.): tqApp->processEvents(500);
1573 ensureVisible(columnPos(m_curCol), rowPos(row+1)+d->rowHeight-1, columnWidth(m_curCol), d->rowHeight);
1574
1575 m_verticalHeader->setOffset(contentsY());
1576 }
1577 }
1578
1579 KexiTableEdit *editorWidget = tableEditorWidget( col );
1580 m_editor = editorWidget;
1581 if (!editorWidget)
1582 return;
1583
1584 m_editor->setValue(*bufferedValueAt(col, !removeOld/*useDefaultValueIfPossible*/), addText, removeOld);
1585 if (m_editor->hasFocusableWidget()) {
1586 moveChild(editorWidget, columnPos(m_curCol), rowPos(m_curRow));
1587
1588 editorWidget->resize(columnWidth(m_curCol)-1, rowHeight()-1);
1589 editorWidget->show();
1590
1591 m_editor->setFocus();
1592 }
1593
1594 if (startRowEdit) {
1595 m_navPanel->showEditingIndicator(true); //this will allow to enable 'next' btn
1596// m_navPanel->updateButtons(rows()); //refresh 'next' btn
1598 }
1599}
1600
1601void KexiTableView::focusInEvent(TQFocusEvent* e)
1602{
1603 Q_UNUSED(e);
1604 updateCell(m_curRow, m_curCol);
1605}
1606
1611
1612bool KexiTableView::focusNextPrevChild(bool /*next*/)
1613{
1614 return false; //special Tab/BackTab meaning
1615/* if (m_editor)
1616 return true;
1617 return TQScrollView::focusNextPrevChild(next);*/
1618}
1619
1620void KexiTableView::resizeEvent(TQResizeEvent *e)
1621{
1622 TQScrollView::resizeEvent(e);
1623 //updateGeometries();
1624
1625 if (m_navPanel)
1626 m_navPanel->updateGeometry(leftMargin());
1627// updateNavPanelGeometry();
1628
1629 if ((contentsHeight() - e->size().height()) <= d->rowHeight) {
1630 slotUpdate();
1631 triggerUpdate();
1632 }
1633// d->pTopHeader->repaint();
1634
1635
1636/* m_navPanel->setGeometry(
1637 frameWidth(),
1638 viewport()->height() +d->pTopHeader->height()
1639 -(horizontalScrollBar()->isVisible() ? 0 : horizontalScrollBar()->sizeHint().height())
1640 +frameWidth(),
1641 m_navPanel->sizeHint().width(), // - verticalScrollBar()->sizeHint().width() - horizontalScrollBar()->sizeHint().width(),
1642 horizontalScrollBar()->sizeHint().height()
1643 );*/
1644// updateContents();
1645// m_navPanel->setGeometry(1,horizontalScrollBar()->pos().y(),
1646 // m_navPanel->width(), horizontalScrollBar()->height());
1647// updateContents(0,0,2000,2000);//js
1648// erase(); repaint();
1649}
1650
1651void KexiTableView::viewportResizeEvent( TQResizeEvent *e )
1652{
1653 TQScrollView::viewportResizeEvent( e );
1654 updateGeometries();
1655// erase(); repaint();
1656}
1657
1658void KexiTableView::showEvent(TQShowEvent *e)
1659{
1660 TQScrollView::showEvent(e);
1661 if (!d->maximizeColumnsWidthOnShow.isEmpty()) {
1662 maximizeColumnsWidth(d->maximizeColumnsWidthOnShow);
1663 d->maximizeColumnsWidthOnShow.clear();
1664 }
1665
1667 //full init
1670 }
1671 else {
1672 //just update size
1673 TQSize s(tableSize());
1674// TQRect r(cellGeometry(rows() - 1 + (isInsertingEnabled()?1:0), columns() - 1 ));
1675// resizeContents(r.right() + 1, r.bottom() + 1);
1676 resizeContents(s.width(),s.height());
1677 }
1678 updateGeometries();
1679
1680 //now we can ensure cell's visibility ( if there was such a call before show() )
1681 if (d->ensureCellVisibleOnShow!=TQPoint(-1,-1)) {
1682 ensureCellVisible( d->ensureCellVisibleOnShow.x(), d->ensureCellVisibleOnShow.y() );
1683 d->ensureCellVisibleOnShow = TQPoint(-1,-1); //reset the flag
1684 }
1685 if (m_navPanel)
1686 m_navPanel->updateGeometry(leftMargin());
1687// updateNavPanelGeometry();
1688}
1689
1690void KexiTableView::contentsDragMoveEvent(TQDragMoveEvent *e)
1691{
1692 if (!hasData())
1693 return;
1694 if (m_dropsAtRowEnabled) {
1695 TQPoint p = e->pos();
1696 int row = rowAt(p.y());
1697 KexiTableItem *item = 0;
1698// if (row==(rows()-1) && (p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
1699 if ((p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
1700 row++;
1701 }
1702 item = m_data->at(row);
1703 emit dragOverRow(item, row, e);
1704 if (e->isAccepted()) {
1705 if (m_dragIndicatorLine>=0 && m_dragIndicatorLine != row) {
1706 //erase old indicator
1708 }
1709 if (m_dragIndicatorLine != row) {
1710 m_dragIndicatorLine = row;
1712 }
1713 }
1714 else {
1715 if (m_dragIndicatorLine>=0) {
1716 //erase old indicator
1718 }
1720 }
1721 }
1722 else
1723 e->acceptAction(false);
1724/* TQStringList::ConstIterator it, end( d->dropFilters.constEnd() );
1725 for( it = d->dropFilters.constBegin(); it != end; it++)
1726 {
1727 if(e->provides((*it).latin1()))
1728 {
1729 e->acceptAction(true);
1730 return;
1731 }
1732 }*/
1733// e->acceptAction(false);
1734}
1735
1736void KexiTableView::contentsDropEvent(TQDropEvent *e)
1737{
1738 if (!hasData())
1739 return;
1740 if (m_dropsAtRowEnabled) {
1741 //we're no longer dragging over the table
1742 if (m_dragIndicatorLine>=0) {
1743 int row2update = m_dragIndicatorLine;
1745 updateRow(row2update);
1746 }
1747 TQPoint p = e->pos();
1748 int row = rowAt(p.y());
1749 if ((p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
1750 row++;
1751 }
1752 KexiTableItem *item = m_data->at(row);
1753 KexiTableItem *newItem = 0;
1754 emit droppedAtRow(item, row, e, newItem);
1755 if (newItem) {
1756 const int realRow = (row==m_curRow ? -1 : row);
1757 insertItem(newItem, realRow);
1758 setCursorPosition(row, 0);
1759// m_currentItem = newItem;
1760 }
1761 }
1762}
1763
1764void KexiTableView::viewportDragLeaveEvent( TQDragLeaveEvent *e )
1765{
1766 Q_UNUSED(e);
1767 if (!hasData())
1768 return;
1769 if (m_dropsAtRowEnabled) {
1770 //we're no longer dragging over the table
1771 if (m_dragIndicatorLine>=0) {
1772 int row2update = m_dragIndicatorLine;
1774 updateRow(row2update);
1775 }
1776 }
1777}
1778
1779void KexiTableView::updateCell(int row, int col)
1780{
1781// kdDebug(44021) << "updateCell("<<row<<", "<<col<<")"<<endl;
1782 updateContents(cellGeometry(row, col));
1783/* TQRect r = cellGeometry(row, col);
1784 r.setHeight(r.height()+6);
1785 r.setTop(r.top()-3);
1786 updateContents();*/
1787}
1788
1790{
1791 updateCell(m_curRow, m_curCol);
1792}
1793
1795{
1796// kdDebug(44021) << "updateRow("<<row<<")"<<endl;
1797 if (row < 0 || row >= (rows() + 2/* sometimes we want to refresh the row after last*/ ))
1798 return;
1799 //int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
1800
1801 //kexidbg << contentsX() << " " << contentsY() << endl;
1802 //kexidbg << TQRect( columnPos( leftcol ), rowPos(row), clipper()->width(), rowHeight() ) << endl;
1803 // updateContents( TQRect( columnPos( leftcol ), rowPos(row), clipper()->width(), rowHeight() ) ); //columnPos(rightcol)+columnWidth(rightcol), rowHeight() ) );
1804 updateContents( TQRect( contentsX(), rowPos(row), clipper()->width(), rowHeight() ) ); //columnPos(rightcol)+columnWidth(rightcol), rowHeight() ) );
1805}
1806
1808{
1809 TQSize s(tableSize());
1810 int w = contentsWidth();
1811 viewport()->setUpdatesEnabled(false);
1812 resizeContents( s.width(), s.height() );
1813 viewport()->setUpdatesEnabled(true);
1814 if (contentsWidth() < w) {
1815 updateContents(contentsX(), 0, viewport()->width(), contentsHeight());
1816// repaintContents( s.width(), 0, w - s.width() + 1, contentsHeight(), true );
1817 }
1818 else {
1819 // updateContents( columnPos(col), 0, contentsWidth(), contentsHeight() );
1820 updateContents(contentsX(), 0, viewport()->width(), contentsHeight());
1821 // viewport()->repaint();
1822 }
1823
1824// updateContents(0, 0, d->pBufferPm->width(), d->pBufferPm->height());
1825 TQWidget *editorWidget = dynamic_cast<TQWidget*>(m_editor);
1826 if (editorWidget)
1827 {
1828 editorWidget->resize(columnWidth(m_curCol)-1, rowHeight()-1);
1829 moveChild(editorWidget, columnPos(m_curCol), rowPos(m_curRow));
1830 }
1831 updateGeometries();
1832 updateScrollBars();
1833 if (m_navPanel)
1834 m_navPanel->updateGeometry(leftMargin());
1835// updateNavPanelGeometry();
1836}
1837
1838void KexiTableView::slotSectionHandleDoubleClicked( int section )
1839{
1841 slotColumnWidthChanged(0,0,0); //to update contents and redraw
1842}
1843
1844
1845void KexiTableView::updateGeometries()
1846{
1847 TQSize ts = tableSize();
1848 if (m_horizontalHeader->offset() && ts.width() < (m_horizontalHeader->offset() + m_horizontalHeader->width()))
1849 horizontalScrollBar()->setValue(ts.width() - m_horizontalHeader->width());
1850
1851// m_verticalHeader->setGeometry(1, topMargin() + 1, leftMargin(), visibleHeight());
1852 m_horizontalHeader->setGeometry(leftMargin() + 1, 1, visibleWidth(), topMargin());
1853 m_verticalHeader->setGeometry(1, topMargin() + 1, leftMargin(), visibleHeight());
1854}
1855
1856int KexiTableView::columnWidth(int col) const
1857{
1858 if (!hasData())
1859 return 0;
1860 int vcID = m_data->visibleColumnID( col );
1861 return (vcID==-1) ? 0 : m_horizontalHeader->sectionSize( vcID );
1862}
1863
1864int KexiTableView::rowHeight() const
1865{
1866 return d->rowHeight;
1867}
1868
1869int KexiTableView::columnPos(int col) const
1870{
1871 if (!hasData())
1872 return 0;
1873 //if this column is hidden, find first column before that is visible
1874 int c = TQMIN(col, (int)m_data->columnsCount()-1), vcID = 0;
1875 while (c>=0 && (vcID=m_data->visibleColumnID( c ))==-1)
1876 c--;
1877 if (c<0)
1878 return 0;
1879 if (c==col)
1880 return m_horizontalHeader->sectionPos(vcID);
1881 return m_horizontalHeader->sectionPos(vcID)+m_horizontalHeader->sectionSize(vcID);
1882}
1883
1884int KexiTableView::rowPos(int row) const
1885{
1886 return d->rowHeight*row;
1887}
1888
1889int KexiTableView::columnAt(int pos) const
1890{
1891 if (!hasData())
1892 return -1;
1893 int r = m_horizontalHeader->sectionAt(pos);
1894 if (r<0)
1895 return r;
1896 return m_data->globalColumnID( r );
1897
1898// if (r==-1)
1899// kexidbg << "columnAt("<<pos<<")==-1 !!!" << endl;
1900// return r;
1901}
1902
1903int KexiTableView::rowAt(int pos, bool ignoreEnd) const
1904{
1905 if (!hasData())
1906 return -1;
1907 pos /=d->rowHeight;
1908 if (pos < 0)
1909 return 0;
1910 if ((pos >= (int)m_data->count()) && !ignoreEnd)
1911 return -1;
1912 return pos;
1913}
1914
1915TQRect KexiTableView::cellGeometry(int row, int col) const
1916{
1917 return TQRect(columnPos(col), rowPos(row),
1918 columnWidth(col), rowHeight());
1919}
1920
1921TQSize KexiTableView::tableSize() const
1922{
1923 if ((rows()+ (isInsertingEnabled()?1:0) ) > 0 && columns() > 0) {
1924/* kexidbg << "tableSize()= " << columnPos( columns() - 1 ) + columnWidth( columns() - 1 )
1925 << ", " << rowPos( rows()-1+(isInsertingEnabled()?1:0)) + d->rowHeight
1926// + TQMAX(m_navPanel ? m_navPanel->height() : 0, horizontalScrollBar()->sizeHint().height())
1927 + (m_navPanel->isVisible() ? TQMAX( m_navPanel->height(), horizontalScrollBar()->sizeHint().height() ) :0 )
1928 + margin() << endl;
1929*/
1930// kexidbg<< m_navPanel->isVisible() <<" "<<m_navPanel->height()<<" "
1931// <<horizontalScrollBar()->sizeHint().height()<<" "<<rowPos( rows()-1+(isInsertingEnabled()?1:0))<<endl;
1932
1933 //int xx = horizontalScrollBar()->sizeHint().height()/2;
1934
1935 TQSize s(
1936 columnPos( columns() - 1 ) + columnWidth( columns() - 1 ),
1937// + verticalScrollBar()->sizeHint().width(),
1938 rowPos( rows()-1+(isInsertingEnabled()?1:0) ) + d->rowHeight
1939 + (horizontalScrollBar()->isVisible() ? 0 : horizontalScrollBar()->sizeHint().height())
1940 + d->internal_bottomMargin
1941// horizontalScrollBar()->sizeHint().height()/2
1942// - /*d->bottomMargin */ horizontalScrollBar()->sizeHint().height()*3/2
1943
1944// + ( (m_navPanel && m_navPanel->isVisible() && verticalScrollBar()->isVisible()
1945 // && !horizontalScrollBar()->isVisible())
1946 // ? horizontalScrollBar()->sizeHint().height() : 0)
1947
1948// + TQMAX( (m_navPanel && m_navPanel->isVisible()) ? m_navPanel->height() : 0,
1949// horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height() : 0)
1950
1951// + (m_navPanel->isVisible()
1952// ? TQMAX( m_navPanel->height(), horizontalScrollBar()->sizeHint().height() ) :0 )
1953
1954// - (horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height() :0 )
1955 + margin()
1956//-2*d->rowHeight
1957 );
1958
1959// kexidbg << rows()-1 <<" "<< (isInsertingEnabled()?1:0) <<" "<< (m_rowEditing?1:0) << " " << s << endl;
1960 return s;
1961// +horizontalScrollBar()->sizeHint().height() + margin() );
1962 }
1963 return TQSize(0,0);
1964}
1965
1966void KexiTableView::ensureCellVisible(int row, int col/*=-1*/)
1967{
1968 if (!isVisible()) {
1969 //the table is invisible: we can't ensure visibility now
1970 d->ensureCellVisibleOnShow = TQPoint(row,col);
1971 return;
1972 }
1973
1974 //quite clever: ensure the cell is visible:
1975 TQRect r( columnPos(col==-1 ? m_curCol : col), rowPos(row) +(d->appearance.fullRowSelection?1:0),
1976 columnWidth(col==-1 ? m_curCol : col), rowHeight());
1977
1978/* if (m_navPanel && horizontalScrollBar()->isHidden() && row == rows()-1) {
1979 //when cursor is moved down and navigator covers the cursor's area,
1980 //area is scrolled up
1981 if ((viewport()->height() - m_navPanel->height()) < r.bottom()) {
1982 scrollBy(0,r.bottom() - (viewport()->height() - m_navPanel->height()));
1983 }
1984 }*/
1985
1986 if (m_navPanel && m_navPanel->isVisible() && horizontalScrollBar()->isHidden()) {
1987 //a hack: for visible navigator: increase height of the visible rect 'r'
1988 r.setBottom(r.bottom()+m_navPanel->height());
1989 }
1990
1991 TQPoint pcenter = r.center();
1992 ensureVisible(pcenter.x(), pcenter.y(), r.width()/2, r.height()/2);
1993// updateContents();
1994// updateNavPanelGeometry();
1995// slotUpdate();
1996}
1997
1998void KexiTableView::updateAfterCancelRowEdit()
1999{
2000 KexiDataAwareObjectInterface::updateAfterCancelRowEdit();
2002}
2003
2004void KexiTableView::updateAfterAcceptRowEdit()
2005{
2006 KexiDataAwareObjectInterface::updateAfterAcceptRowEdit();
2008}
2009
2010bool KexiTableView::getVisibleLookupValue(TQVariant& cellValue, KexiTableEdit *edit,
2011 KexiTableItem *item, KexiTableViewColumn *tvcol) const
2012{
2013 if (edit->columnInfo() && edit->columnInfo()->indexForVisibleLookupValue()!=-1
2014 && edit->columnInfo()->indexForVisibleLookupValue() < (int)item->count())
2015 {
2016 const TQVariant *visibleFieldValue = 0;
2017 if (m_currentItem == item && m_data->rowEditBuffer()) {
2018 visibleFieldValue = m_data->rowEditBuffer()->at(
2019 *tvcol->visibleLookupColumnInfo, false );
2020 }
2021
2022 if (visibleFieldValue)
2023 //(use bufferedValueAt() - try to get buffered visible value for lookup field)
2024 cellValue = *visibleFieldValue; //txt = visibleFieldValue->toString();
2025 else
2026 cellValue /*txt*/ = item->at( edit->columnInfo()->indexForVisibleLookupValue() ); //.toString();
2027 return true;
2028 }
2029 return false;
2030}
2031
2032//reimpl.
2034{
2035 if (!m_editor)
2036 return;
2037 KexiDataAwareObjectInterface::removeEditor();
2038 viewport()->setFocus();
2039}
2040
2042{
2043 updateRow( m_data->findRef(&item) );
2044}
2045
2046//(js) unused
2047void KexiTableView::slotAutoScroll()
2048{
2049 kdDebug(44021) << "KexiTableView::slotAutoScroll()" <<endl;
2050 if (!d->needAutoScroll)
2051 return;
2052
2053 switch(d->scrollDirection)
2054 {
2055 case ScrollDown:
2056 setCursorPosition(m_curRow + 1, m_curCol);
2057 break;
2058
2059 case ScrollUp:
2060 setCursorPosition(m_curRow - 1, m_curCol);
2061 break;
2062 case ScrollLeft:
2063 setCursorPosition(m_curRow, m_curCol - 1);
2064 break;
2065
2066 case ScrollRight:
2067 setCursorPosition(m_curRow, m_curCol + 1);
2068 break;
2069 }
2070}
2071
2072#ifndef KEXI_NO_PRINT
2073void
2074KexiTableView::print(KPrinter &/*printer*/)
2075{
2076// printer.setFullPage(true);
2077#if 0
2078 int leftMargin = printer.margins().width() + 2 + d->rowHeight;
2079 int topMargin = printer.margins().height() + 2;
2080// int bottomMargin = topMargin + ( printer.realPageSize()->height() * printer.resolution() + 36 ) / 72;
2081 int bottomMargin = 0;
2082 kdDebug(44021) << "KexiTableView::print: bottom = " << bottomMargin << endl;
2083
2084 TQPainter p(&printer);
2085
2086 KexiTableItem *i;
2087 int width = leftMargin;
2088 for(int col=0; col < columns(); col++)
2089 {
2090 p.fillRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, TQBrush(TQt::gray));
2091 p.drawRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight);
2092 p.drawText(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, TQt::AlignLeft | TQt::AlignVCenter,
2093 m_horizontalHeader->label(col));
2094 width = width + columnWidth(col);
2095 }
2096
2097 int yOffset = topMargin;
2098 int row = 0;
2099 int right = 0;
2100 for(i = m_data->first(); i; i = m_data->next())
2101 {
2102 if(!i->isInsertItem())
2103 { kdDebug(44021) << "KexiTableView::print: row = " << row << " y = " << yOffset << endl;
2104 int xOffset = leftMargin;
2105 for(int col=0; col < columns(); col++)
2106 {
2107 kdDebug(44021) << "KexiTableView::print: col = " << col << " x = " << xOffset << endl;
2108 p.saveWorldMatrix();
2109 p.translate(xOffset, yOffset);
2110 paintCell(&p, i, col, TQRect(0, 0, columnWidth(col) + 1, d->rowHeight), true);
2111 p.restoreWorldMatrix();
2112// p.drawRect(xOffset, yOffset, columnWidth(col), d->rowHeight);
2113 xOffset = xOffset + columnWidth(col);
2114 right = xOffset;
2115 }
2116
2117 row++;
2118 yOffset = topMargin + row * d->rowHeight;
2119 }
2120
2121 if(yOffset > 900)
2122 {
2123 p.drawLine(leftMargin, topMargin, leftMargin, yOffset);
2124 p.drawLine(leftMargin, topMargin, right - 1, topMargin);
2125 printer.newPage();
2126 yOffset = topMargin;
2127 row = 0;
2128 }
2129 }
2130 p.drawLine(leftMargin, topMargin, leftMargin, yOffset);
2131 p.drawLine(leftMargin, topMargin, right - 1, topMargin);
2132
2133// p.drawLine(60,60,120,150);
2134 p.end();
2135#endif
2136}
2137#endif
2138
2139TQString KexiTableView::columnCaption(int colNum) const
2140{
2141 return m_horizontalHeader->label(colNum);
2142}
2143
2145{
2146 if (!m_data || !m_data->column(colNum))
2147 return 0;
2148 return m_data->column(colNum)->field();
2149}
2150
2152{
2153 if (!hasData())
2154 return;
2155 if (colNum==-1) {
2156 const int cols = columns();
2157 for (int i=0; i<cols; i++)
2159 return;
2160 }
2161
2162 int indexOfVisibleColumn = (m_data->column(colNum) && m_data->column(colNum)->columnInfo)
2163 ? m_data->column(colNum)->columnInfo->indexForVisibleLookupValue() : -1;
2164 if (-1==indexOfVisibleColumn)
2165 indexOfVisibleColumn = colNum;
2166
2167 if (indexOfVisibleColumn < 0)
2168 return;
2169
2170 TQPtrListIterator<KexiTableItem> it = m_data->iterator();
2171 if (it.current() && it.current()->count()<=(uint)indexOfVisibleColumn)
2172 return;
2173
2174 KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item( columnType(indexOfVisibleColumn) );
2175 if (!item)
2176 return;
2177 TQFontMetrics fm(fontMetrics());
2178 int maxw = horizontalHeaderVisible()
2179 ? fm.width( m_horizontalHeader->label( colNum/* not indexOfVisibleColumn*/ ) ) : 0;
2180 if (maxw == 0 && m_data->isEmpty())
2181 return; //nothing to adjust
2182
2184
2185 KexiTableEdit *ed = tableEditorWidget( colNum/* not indexOfVisibleColumn*/ );
2186 if (ed) {
2187 for (it = m_data->iterator(); it.current(); ++it) {
2188 const int wfw = ed->widthForValue( it.current()->at( indexOfVisibleColumn ), fm );
2189 maxw = TQMAX( maxw, wfw );
2190 }
2191 const bool focused = currentColumn() == colNum;
2192 maxw += (fm.width(" ") + ed->leftMargin() + ed->rightMargin(focused));
2193 }
2194 if (maxw < KEXITV_MINIMUM_COLUMN_WIDTH )
2195 maxw = KEXITV_MINIMUM_COLUMN_WIDTH; //not too small
2196 kexidbg << "KexiTableView: setColumnWidth(colNum=" << colNum
2197 << ", indexOfVisibleColumn=" << indexOfVisibleColumn << ", width=" << maxw <<" )" << endl;
2198 setColumnWidth( colNum/* not indexOfVisibleColumn*/, maxw );
2199}
2200
2201void KexiTableView::setColumnWidth(int colNum, int width)
2202{
2203 if (columns()<=colNum || colNum < 0)
2204 return;
2205 const int oldWidth = m_horizontalHeader->sectionSize( colNum );
2206 m_horizontalHeader->resizeSection( colNum, width );
2207 slotTopHeaderSizeChange( colNum, oldWidth, m_horizontalHeader->sectionSize( colNum ) );
2208}
2209
2210void KexiTableView::maximizeColumnsWidth( const TQValueList<int> &columnList )
2211{
2212 if (!isVisible()) {
2213 d->maximizeColumnsWidthOnShow += columnList;
2214 return;
2215 }
2216 if (width() <= m_horizontalHeader->headerWidth())
2217 return;
2218 //sort the list and make it unique
2219 TQValueList<int> cl, sortedList = columnList;
2220 qHeapSort(sortedList);
2221 int i=-999;
2222
2223 TQValueList<int>::ConstIterator it, end( sortedList.constEnd() );
2224 for ( it = sortedList.constBegin(); it != end; ++it) {
2225 if (i != (*it)) {
2226 cl += (*it);
2227 i = (*it);
2228 }
2229 }
2230 //resize
2231 int sizeToAdd = (width() - m_horizontalHeader->headerWidth()) / cl.count() - verticalHeader()->width();
2232 if (sizeToAdd<=0)
2233 return;
2234 end = cl.constEnd();
2235 for ( it = cl.constBegin(); it != end; ++it) {
2236 int w = m_horizontalHeader->sectionSize(*it);
2237 if (w>0) {
2238 m_horizontalHeader->resizeSection(*it, w+sizeToAdd);
2239 }
2240 }
2241 updateContents();
2242 editorShowFocus( m_curRow, m_curCol );
2243}
2244
2246{
2247 m_horizontalHeader->adjustHeaderSize();
2248}
2249
2250void KexiTableView::setColumnStretchEnabled( bool set, int colNum )
2251{
2252 m_horizontalHeader->setStretchEnabled( set, colNum );
2253}
2254
2255void KexiTableView::setEditableOnDoubleClick(bool set)
2256{
2257 d->editOnDoubleClick = set;
2258}
2259bool KexiTableView::editableOnDoubleClick() const
2260{
2261 return d->editOnDoubleClick;
2262}
2263
2265{
2266 return m_verticalHeader->isVisible();
2267}
2268
2270{
2271 int left_width;
2272 if (set) {
2273 m_verticalHeader->show();
2274 left_width = TQMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight);
2275 }
2276 else {
2277 m_verticalHeader->hide();
2278 left_width = 0;
2279 }
2280 setMargins( left_width, horizontalHeaderVisible() ? m_horizontalHeader->sizeHint().height() : 0, 0, 0);
2281}
2282
2284{
2285 return d->horizontalHeaderVisible;
2286}
2287
2289{
2290 int top_height;
2291 d->horizontalHeaderVisible = set; //needed because isVisible() is not always accurate
2292 if (set) {
2293 m_horizontalHeader->show();
2294 top_height = m_horizontalHeader->sizeHint().height();
2295 }
2296 else {
2297 m_horizontalHeader->hide();
2298 top_height = 0;
2299 }
2300 setMargins( verticalHeaderVisible() ? m_verticalHeader->width() : 0, top_height, 0, 0);
2301}
2302
2304{
2305// kdDebug(44021) << "KexiTableView::triggerUpdate()" << endl;
2306// if (!d->pUpdateTimer->isActive())
2307 d->pUpdateTimer->start(20, true);
2308// d->pUpdateTimer->start(200, true);
2309}
2310
2311void KexiTableView::setHBarGeometry( TQScrollBar & hbar, int x, int y, int w, int h )
2312{
2313/*todo*/
2314 kdDebug(44021)<<"KexiTableView::setHBarGeometry"<<endl;
2315 if (d->appearance.navigatorEnabled) {
2316 m_navPanel->setHBarGeometry( hbar, x, y, w, h );
2317 }
2318 else {
2319 hbar.setGeometry( x , y, w, h );
2320 }
2321}
2322
2324{
2326 //copy m_navPanelEnabled flag
2327 Appearance a = d->appearance;
2328 a.navigatorEnabled = m_navPanelEnabled;
2329 setAppearance( a );
2330}
2331
2332int KexiTableView::validRowNumber(const TQString& text)
2333{
2334 bool ok=true;
2335 int r = text.toInt(&ok);
2336 if (!ok || r<1)
2337 r = 1;
2338 else if (r > (rows()+(isInsertingEnabled()?1:0)))
2339 r = rows()+(isInsertingEnabled()?1:0);
2340 return r-1;
2341}
2342
2344{
2345 if (r > uint(rows()+(isInsertingEnabled()?1:0)))
2346 r = rows()+(isInsertingEnabled()?1:0);
2347 setFocus();
2348 selectRow( r );
2349}
2350
2351void KexiTableView::moveToLastRecordRequested()
2352{
2353 setFocus();
2354 selectRow(rows()>0 ? (rows()-1) : 0);
2355}
2356
2357void KexiTableView::moveToPreviousRecordRequested()
2358{
2359 setFocus();
2360 selectPrevRow();
2361}
2362
2363void KexiTableView::moveToNextRecordRequested()
2364{
2365 setFocus();
2366 selectNextRow();
2367}
2368
2369void KexiTableView::moveToFirstRecordRequested()
2370{
2371 setFocus();
2372 selectFirstRow();
2373}
2374
2376{
2377 if (m_currentItem && m_curCol!=-1) {
2378 KexiTableEdit *edit = tableEditorWidget( m_curCol );
2379 TQVariant defaultValue;
2380 const bool defaultValueDisplayed
2381 = isDefaultValueDisplayed(m_currentItem, m_curCol, &defaultValue);
2382 if (edit) {
2383 TQVariant visibleValue;
2384 getVisibleLookupValue(visibleValue, edit, m_currentItem, m_data->column(m_curCol));
2385 edit->handleCopyAction(
2386 defaultValueDisplayed ? defaultValue : m_currentItem->at( m_curCol ),
2387 visibleValue );
2388 }
2389 }
2390}
2391
2393{
2394 //try to handle @ editor's level
2395 KexiTableEdit *edit = tableEditorWidget( m_curCol );
2396 if (edit)
2397 edit->handleAction("edit_cut");
2398}
2399
2401{
2402 //try to handle @ editor's level
2403 KexiTableEdit *edit = tableEditorWidget( m_curCol );
2404 if (edit)
2405 edit->handleAction("edit_paste");
2406}
2407
2408bool KexiTableView::eventFilter( TQObject *o, TQEvent *e )
2409{
2410 //don't allow to stole key my events by others:
2411// kexidbg << "spontaneous " << e->spontaneous() << " type=" << e->type() << endl;
2412
2413 if (e->type()==TQEvent::KeyPress) {
2414 if (e->spontaneous() /*|| e->type()==TQEvent::AccelOverride*/) {
2415 TQKeyEvent *ke = static_cast<TQKeyEvent*>(e);
2416 const int k = ke->key();
2417 int s = ke->state();
2418 //cell editor's events:
2419 //try to handle the event @ editor's level
2420 KexiTableEdit *edit = tableEditorWidget( m_curCol );
2421 if (edit && edit->handleKeyPress(ke, m_editor==edit)) {
2422 ke->accept();
2423 return true;
2424 }
2425 else if (m_editor && (o==dynamic_cast<TQObject*>(m_editor) || o==m_editor->widget())) {
2426 if ( (k==TQt::Key_Tab && (s==TQt::NoButton || s==TQt::ShiftButton))
2427 || (overrideEditorShortcutNeeded(ke))
2428 || (k==TQt::Key_Enter || k==TQt::Key_Return || k==TQt::Key_Up || k==TQt::Key_Down)
2429 || (k==TQt::Key_Left && m_editor->cursorAtStart())
2430 || (k==TQt::Key_Right && m_editor->cursorAtEnd())
2431 )
2432 {
2433 //try to steal the key press from editor or it's internal widget...
2434 keyPressEvent(ke);
2435 if (ke->isAccepted())
2436 return true;
2437 }
2438 }
2439 /*
2440 else if (e->type()==TQEvent::KeyPress && (o==this || (m_editor && o==m_editor->widget()))){//|| o==viewport())
2441 keyPressEvent(ke);
2442 if (ke->isAccepted())
2443 return true;
2444 }*/
2445/*todo else if ((k==TQt::Key_Tab || k==(TQt::SHIFT|TQt::Key_Tab)) && o==d->navRowNumber) {
2446 //tab key focuses tv
2447 ke->accept();
2448 setFocus();
2449 return true;
2450 }*/
2451 }
2452 }
2453 else if (o==horizontalScrollBar()) {
2454 if ((e->type()==TQEvent::Show && !horizontalScrollBar()->isVisible())
2455 || (e->type()==TQEvent::Hide && horizontalScrollBar()->isVisible())) {
2457 }
2458 }
2459 else if (e->type()==TQEvent::Leave) {
2460 if (o==viewport() && d->appearance.rowMouseOverHighlightingEnabled
2461 && d->appearance.persistentSelections)
2462 {
2463 if (d->highlightedRow!=-1) {
2464 int oldRow = d->highlightedRow;
2465 d->highlightedRow = -1;
2466 updateRow(oldRow);
2467 const bool dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
2468 = d->appearance.rowHighlightingEnabled && !d->appearance.persistentSelections;
2469 if (oldRow!=m_curRow && m_curRow>=0) {
2470 if (!dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted)
2471 //no highlight for now: show selection again
2473 m_verticalHeader->setHighlightedRow(-1);
2474 }
2475 }
2476 }
2477 d->recentCellWithToolTip = TQPoint(-1,-1);
2478 }
2479/* else if (e->type()==TQEvent::FocusOut && o->inherits("TQWidget")) {
2480 //hp==true if currently focused widget is a child of this table view
2481 const bool hp = KexiUtils::hasParent( o, focusWidget());
2482 if (!hp && KexiUtils::hasParent( this, o)) {
2483 //accept row editing if focus is moved to foreign widget
2484 //(not a child, like eg. editor) from one of our table view's children
2485 //or from table view itself
2486 if (!acceptRowEdit()) {
2487 static_cast<TQWidget*>(o)->setFocus();
2488 return true;
2489 }
2490 }
2491 }*/
2492 return TQScrollView::eventFilter(o,e);
2493}
2494
2496 int /*section*/, int /*oldSize*/, int /*newSize*/ )
2497{
2498 editorShowFocus( m_curRow, m_curCol );
2499}
2500
2501void KexiTableView::setBottomMarginInternal(int pixels)
2502{
2503 d->internal_bottomMargin = pixels;
2504}
2505
2506void KexiTableView::paletteChange( const TQPalette &oldPalette )
2507{
2508 Q_UNUSED(oldPalette);
2509 //update:
2510 if (m_verticalHeader)
2511 m_verticalHeader->setSelectionBackgroundColor( palette().active().highlight() );
2513 m_horizontalHeader->setSelectionBackgroundColor( palette().active().highlight() );
2514}
2515
2517{
2518 return d->appearance;
2519}
2520
2522{
2523// if (d->appearance.fullRowSelection != a.fullRowSelection) {
2524 if (a.fullRowSelection) {
2525 d->rowHeight -= 1;
2526 }
2527 else {
2528 d->rowHeight += 1;
2529 }
2530 if (m_verticalHeader)
2531 m_verticalHeader->setCellHeight(d->rowHeight);
2532 if (m_horizontalHeader) {
2533 setMargins(
2534 TQMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
2535 m_horizontalHeader->sizeHint().height(), 0, 0);
2536 }
2537// }
2540
2541 if(!a.navigatorEnabled)
2542 m_navPanel->hide();
2543 else
2544 m_navPanel->show();
2545// }
2546
2547 d->highlightedRow = -1;
2549 viewport()->setMouseTracking(a.rowMouseOverHighlightingEnabled);
2550
2551 d->appearance = a;
2552
2553 setFont(font()); //this also updates contents
2554}
2555
2557{
2558 return d->highlightedRow;
2559}
2560
2562{
2563 if (row!=-1) {
2564 row = TQMIN(rows() - 1 + (isInsertingEnabled()?1:0), row);
2565 row = TQMAX(0, row);
2566 ensureCellVisible(row, -1);
2567 }
2568 const int previouslyHighlightedRow = d->highlightedRow;
2569 if (previouslyHighlightedRow == row) {
2570 if (previouslyHighlightedRow!=-1)
2571 updateRow(previouslyHighlightedRow);
2572 return;
2573 }
2574 d->highlightedRow = row;
2575 if (d->highlightedRow!=-1)
2576 updateRow(d->highlightedRow);
2577
2578 if (previouslyHighlightedRow!=-1)
2579 updateRow(previouslyHighlightedRow);
2580
2581 if (m_curRow>=0 && (previouslyHighlightedRow==-1 || previouslyHighlightedRow==m_curRow)
2582 && d->highlightedRow!=m_curRow && !d->appearance.persistentSelections)
2583 {
2584 //currently selected row needs to be repainted
2586 }
2587}
2588
2589KexiTableItem *KexiTableView::highlightedItem() const
2590{
2591 return d->highlightedRow == -1 ? 0 : m_data->at(d->highlightedRow);
2592}
2593
2594void KexiTableView::slotSettingsChanged(int category)
2595{
2596 if (category==TDEApplication::SETTINGS_SHORTCUTS) {
2597 d->contextMenuKey = TDEGlobalSettings::contextMenuKey();
2598 }
2599}
2600
2602{
2603 return rowAt( contentsY() );
2604}
2605
2606#include "kexitableview.moc"
2607
A base class for implementing cell editor factories.
static KexiTableEdit * createEditor(KexiTableViewColumn &column, TQWidget *parent=0)
static KexiCellEditorFactoryItem * item(uint type, const TQString &subType=TQString())
QuerySchema * query() const
Definition cursor.h:104
Meta-data for a field.
Definition field.h:73
TQString captionOrName() const
Definition field.h:374
bool isAutoIncrement() const
Definition field.h:231
TQString description() const
Definition field.h:377
TQVariant defaultValue() const
Definition field.h:326
int indexForVisibleLookupValue() const
Definition queryschema.h:75
const TQVariant * at(QueryColumnInfo &ci, bool useDefaultValueIfPossible=true) const
The KexiDataAwareObjectInterface is an interface for record-based data object.
KexiTableViewData * data() const
virtual void setCursorPosition(int row, int col=-1, bool forceSet=false)
void insertItem(KexiTableItem *newItem, int row=-1)
KexiTableItem * m_insertItem
item data for inserting
bool m_rowEditing
when (current or new) row is edited - changed field values are temporary stored here
virtual bool handleKeyPress(TQKeyEvent *e, int &curRow, int &curCol, bool fullRowSelection, bool *moveToFirstField=0, bool *moveToLastField=0)
bool hasData() const
for sanity checks (return true if m_data is present; else: outputs warning)
KexiTableViewData * m_data
data structure displayed for this object
KexiDataItemInterface * editor() const
virtual void focusOutEvent(TQFocusEvent *e)
Call this from the subclass. *‍/.
KexiRecordNavigator * m_navPanel
main navigation widget
KexiTableItem * m_currentItem
current data item
bool m_owner
true if m_data member is owned by this object
An interface for declaring widgets to be data-aware.
virtual bool cursorAtEnd()=0
virtual bool cursorAtStart()=0
virtual TQVariant value()=0
virtual void showFocus(const TQRect &r, bool readOnly)
void setValue(const TQVariant &value, const TQVariant &add=TQVariant(), bool removeOld=false, const TQVariant *visibleValue=0)
virtual void handleAction(const TQString &actionName)
virtual TQWidget * widget()=0
static void initDisplayForDefaultValue(DisplayParameters &par, TQWidget *widget)
Initializes display parameters for default value.
static void paintAutonumberSign(const DisplayParameters &par, TQPainter *painter, int x, int y, int width, int height, int align, bool overrideColor=false)
Paints autonumber sign using par parameters.
static void initDisplayForAutonumberSign(DisplayParameters &par, TQWidget *widget)
Initializes display parameters for autonumber sign.
Record marker, usually displayed at the left side of a table view or a continuous form.
void setEditRow(int row)
KexiRecordNavigatorHandler interface handles requests generated by KexiRecordNavigator.
KexiRecordNavigator class provides a record navigator.
void showEditingIndicator(bool show)
void setHBarGeometry(TQScrollBar &hbar, int x, int y, int w, int h)
void setRecordHandler(KexiRecordNavigatorHandler *handler)
The KexiSharedActionClient is an interface using application-wide (shared) actions.
TQAsciiDict< TDEAction > m_sharedActions
Actions pluged for this widget using plugSharedAction(), available by name.
Abstract class for a cell editor. Handles cell painting and displaying the editor widget.
virtual bool handleKeyPress(TQKeyEvent *ke, bool editorActive)
virtual bool showToolTipIfNeeded(const TQVariant &value, const TQRect &rect, const TQFontMetrics &fm, bool focused)
bool usesSelectedTextColor() const
int leftMargin() const
virtual void setupContents(TQPainter *p, bool focused, const TQVariant &val, TQString &txt, int &align, int &x, int &y_offset, int &w, int &h)
virtual void resize(int w, int h)
virtual void paintSelectionBackground(TQPainter *p, bool focused, const TQString &txt, int align, int x, int y_offset, int w, int h, const TQColor &fillColor, const TQFontMetrics &fm, bool readOnly, bool fullRowSelection)
virtual KexiDB::QueryColumnInfo * columnInfo() const
KexiDB::Field * displayedField() const
virtual void handleCopyAction(const TQVariant &value, const TQVariant &visibleValue)=0
int rightMargin(bool focused) const
virtual int widthForValue(TQVariant &val, const TQFontMetrics &fm)
virtual void paintFocusBorders(TQPainter *p, TQVariant &cal, int x, int y, int w, int h)
virtual bool handleDoubleClick()
KexiDB::Field * field() const
KexiDB::QueryColumnInfo * visibleLookupColumnInfo
KexiDB::QueryColumnInfo * columnInfo
A table view header with additional actions.
void setToolTip(int section, const TQString &toolTip)
KexiTableView class provides a widget for displaying data in a tabular view.
virtual void createEditor(int row, int col, const TQString &addText=TQString(), bool removeOld=false)
Creates editors and shows it, what usually means the beginning of a cell editing.
void setAppearance(const Appearance &a)
virtual int rowsPerPage() const
const Appearance & appearance() const
void showContextMenu(const TQPoint &pos=TQPoint(-1,-1))
KexiDB::Field * field(int colNum) const
virtual void copySelection()
Copy current selection to a clipboard (e.g. cell)
void setVerticalHeaderVisible(bool set)
Sets vertical header's visibility.
virtual void setLocalSortingOrder(int col, int order)
void triggerUpdate()
single shot after 1ms for contents updatinh
void setColumnWidth(int col, int width)
Sets width of column width to width.
bool getVisibleLookupValue(TQVariant &cellValue, KexiTableEdit *edit, KexiTableItem *item, KexiTableViewColumn *tvcol) const
void setHorizontalHeaderVisible(bool set)
Sets horizontal header's visibility.
void paintRow(KexiTableItem *item, TQPainter *pb, int r, int rowp, int cx, int cy, int colfirst, int collast, int maxwc)
void rowEditStarted(int row)
emmited when row editing is started (for updating or inserting)
int validRowNumber(const TQString &text)
internal, to determine valid row number when navigator text changed
virtual void slotRowRepaintRequested(KexiTableItem &item)
Handles KexiTableViewData::rowRepaintRequested() signal.
virtual void deleteAndStartEditCurrentCell()
virtual void ensureCellVisible(int row, int col)
void slotEditRequested()
receives a signal from cell editors
virtual void focusOutEvent(TQFocusEvent *e)
Call this from the subclass. *‍/.
virtual bool acceptRowEdit()
bool shortCutPressed(TQKeyEvent *e, const TQCString &action_name)
virtual void updateRow(int row)
void adjustHorizontalHeaderSize()
bool verticalHeaderVisible() const
virtual void moveToRecordRequested(uint r)
for navigator
virtual void setSpreadSheetMode()
void paintCell(TQPainter *p, KexiTableItem *item, int col, int row, const TQRect &cr, bool print=false)
virtual void addHeaderColumn(const TQString &caption, const TQString &description, const TQIconSet &icon, int size)
virtual int currentLocalSortingOrder() const
virtual int currentLocalSortColumn() const
void setupNavigator()
Setups navigator widget.
virtual void cutSelection()
Cut current selection to a clipboard (e.g. cell)
virtual void startEditCurrentCell(const TQString &setText=TQString())
virtual void updateWidgetContentsSize()
void maximizeColumnsWidth(const TQValueList< int > &columnList)
virtual void removeEditor()
void setFont(const TQFont &f)
virtual void editorShowFocus(int row, int col)
virtual void initDataContents()
virtual void clearVariables()
virtual void paste()
Paste current clipboard contents (e.g. to a cell)
virtual KexiTableItem * insertEmptyRow(int row=-1)
virtual void updateAllVisibleRowsBelow(int row)
virtual int lastVisibleRow() const
virtual void keyPressEvent(TQKeyEvent *e)
void slotColumnWidthChanged(int col, int os, int ns)
updates display after many rows deletion
void adjustColumnWidthToContents(int colNum=-1)
virtual void updateCell(int row, int col)
void setColumnStretchEnabled(bool set, int colNum)
void updateFonts(bool repaint=false)
Internal: updated sched fonts for painting.
virtual bool cancelRowEdit()
virtual TQScrollBar * verticalScrollBar() const
void drawContents(TQPainter *p, int cx, int cy, int cw, int ch)
painting and layout
virtual void reloadData()
bool horizontalHeaderVisible() const
virtual void updateGUIAfterSorting()
void slotTopHeaderSizeChange(int section, int oldSize, int newSize)
internal, used when top header's size changed
int highlightedRow() const
virtual void updateCurrentCell()
void setHighlightedRow(int row)
virtual void deleteCurrentRow()
TQString columnCaption(int colNum) const
bool hasParent(TQObject *par, TQObject *o)
KEXIUTILS_EXPORT TQColor blendedColors(const TQColor &c1, const TQColor &c2, int factor1=1, int factor2=1)