summaryrefslogtreecommitdiffstats
path: root/kexi/widget/tableview/kexitableview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kexi/widget/tableview/kexitableview.cpp')
-rw-r--r--kexi/widget/tableview/kexitableview.cpp2607
1 files changed, 2607 insertions, 0 deletions
diff --git a/kexi/widget/tableview/kexitableview.cpp b/kexi/widget/tableview/kexitableview.cpp
new file mode 100644
index 00000000..108b1696
--- /dev/null
+++ b/kexi/widget/tableview/kexitableview.cpp
@@ -0,0 +1,2607 @@
+/* This file is part of the KDE project
+ Copyright (C) 2002 Till Busch <till@bux.at>
+ Copyright (C) 2003 Lucijan Busch <lucijan@gmx.at>
+ Copyright (C) 2003 Daniel Molkentin <molkentin@kde.org>
+ Copyright (C) 2003 Joseph Wenninger <jowenn@kde.org>
+ Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this program; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+
+ Original Author: Till Busch <till@bux.at>
+ Original Project: buX (www.bux.at)
+*/
+
+#include <qpainter.h>
+#include <qkeycode.h>
+#include <qlineedit.h>
+#include <qcombobox.h>
+#include <qwmatrix.h>
+#include <qtimer.h>
+#include <qpopupmenu.h>
+#include <qcursor.h>
+#include <qstyle.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qwhatsthis.h>
+
+#include <kglobal.h>
+#include <klocale.h>
+#include <kdebug.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <kmessagebox.h>
+
+#ifndef KEXI_NO_PRINT
+# include <kprinter.h>
+#endif
+
+#include "kexitableview.h"
+#include <kexiutils/utils.h>
+#include <kexiutils/validator.h>
+
+#include "kexicelleditorfactory.h"
+#include "kexitableviewheader.h"
+#include "kexitableview_p.h"
+#include <widget/utils/kexirecordmarker.h>
+#include <widget/utils/kexidisplayutils.h>
+#include <kexidb/cursor.h>
+
+KexiTableView::Appearance::Appearance(QWidget *widget)
+ : alternateBackgroundColor( KGlobalSettings::alternateBackgroundColor() )
+{
+ //set defaults
+ if (qApp) {
+ QPalette p = widget ? widget->palette() : qApp->palette();
+ baseColor = p.active().base();
+ textColor = p.active().text();
+ borderColor = QColor(200,200,200);
+ emptyAreaColor = p.active().color(QColorGroup::Base);
+ rowHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), baseColor, 33, 66);
+ rowMouseOverHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), baseColor, 10, 90);
+ rowMouseOverAlternateHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), alternateBackgroundColor, 10, 90);
+ rowHighlightingTextColor = textColor;
+ rowMouseOverHighlightingTextColor = textColor;
+ }
+ backgroundAltering = true;
+ rowMouseOverHighlightingEnabled = true;
+ rowHighlightingEnabled = true;
+ persistentSelections = true;
+ navigatorEnabled = true;
+ fullRowSelection = false;
+ gridEnabled = true;
+}
+
+//-----------------------------------------
+
+//! @internal A special What's This class displaying information about a given column
+class KexiTableView::WhatsThis : public QWhatsThis
+{
+ public:
+ WhatsThis(KexiTableView* tv) : QWhatsThis(tv), m_tv(tv)
+ {
+ Q_ASSERT(tv);
+ }
+ virtual ~WhatsThis()
+ {
+ }
+ virtual QString text( const QPoint & pos)
+ {
+ const int leftMargin = m_tv->verticalHeaderVisible() ? m_tv->verticalHeader()->width() : 0;
+ //const int topMargin = m_tv->horizontalHeaderVisible() ? m_tv->d->pTopHeader->height() : 0;
+ //const int bottomMargin = m_tv->d->appearance.navigatorEnabled ? m_tv->m_navPanel->height() : 0;
+ if (KexiUtils::hasParent(m_tv->verticalHeader(), m_tv->childAt(pos))) {
+ return i18n("Contains a pointer to the currently selected row");
+ }
+ else if (KexiUtils::hasParent(m_tv->m_navPanel, m_tv->childAt(pos))) {
+ return i18n("Row navigator");
+// return QWhatsThis::textFor(m_tv->m_navPanel, QPoint( pos.x(), pos.y() - m_tv->height() + bottomMargin ));
+ }
+ KexiDB::Field *f = m_tv->field( m_tv->columnAt(pos.x()-leftMargin) );
+ if (!f)
+ return QString::null;
+ return f->description().isEmpty() ? f->captionOrName() : f->description();
+ }
+ protected:
+ KexiTableView *m_tv;
+};
+
+//-----------------------------------------
+
+KexiTableViewCellToolTip::KexiTableViewCellToolTip( KexiTableView * tableView )
+ : QToolTip(tableView->viewport())
+ , m_tableView(tableView)
+{
+}
+
+KexiTableViewCellToolTip::~KexiTableViewCellToolTip()
+{
+ remove(parentWidget());
+}
+
+void KexiTableViewCellToolTip::maybeTip( const QPoint & p )
+{
+ const QPoint cp( m_tableView->viewportToContents( p ) );
+ const int row = m_tableView->rowAt( cp.y(), true/*ignoreEnd*/ );
+ const int col = m_tableView->columnAt( cp.x() );
+
+ //show tooltip if needed
+ if (col>=0 && row>=0) {
+ KexiTableEdit *editor = m_tableView->tableEditorWidget( col );
+ const bool insertRowSelected = m_tableView->isInsertingEnabled() && row==m_tableView->rows();
+ KexiTableItem *item = insertRowSelected ? m_tableView->m_insertItem : m_tableView->itemAt( row );
+ if (editor && item && (col < (int)item->count())) {
+ int w = m_tableView->columnWidth( col );
+ int h = m_tableView->rowHeight();
+ int x = 0;
+ int y_offset = 0;
+ int align = Qt::SingleLine | Qt::AlignVCenter;
+ QString txtValue;
+ QVariant cellValue;
+ KexiTableViewColumn *tvcol = m_tableView->column(col);
+ if (!m_tableView->getVisibleLookupValue(cellValue, editor, item, tvcol))
+ cellValue = insertRowSelected ? editor->displayedField()->defaultValue() : item->at(col); //display default value if available
+ const bool focused = m_tableView->selectedItem() == item && col == m_tableView->currentColumn();
+ editor->setupContents( 0, focused, cellValue, txtValue, align, x, y_offset, w, h );
+ QRect realRect(m_tableView->columnPos(col)-m_tableView->contentsX(),
+ m_tableView->rowPos(row)-m_tableView->contentsY(), w, h); //m_tableView->cellGeometry( row, col ));
+ if (editor->showToolTipIfNeeded(
+ txtValue.isEmpty() ? item->at(col) : QVariant(txtValue),
+ realRect, m_tableView->fontMetrics(), focused))
+ {
+ QString squeezedTxtValue;
+ if (txtValue.length() > 50)
+ squeezedTxtValue = txtValue.left(100) + "...";
+ else
+ squeezedTxtValue = txtValue;
+ tip( realRect, squeezedTxtValue );
+ }
+ }
+ }
+}
+
+//-----------------------------------------
+
+KexiTableView::KexiTableView(KexiTableViewData* data, QWidget* parent, const char* name)
+: QScrollView(parent, name, /*Qt::WRepaintNoErase | */Qt::WStaticContents /*| Qt::WResizeNoErase*/)
+, KexiRecordNavigatorHandler()
+, KexiSharedActionClient()
+, KexiDataAwareObjectInterface()
+{
+//not needed KexiTableView::initCellEditorFactories();
+
+ d = new KexiTableViewPrivate(this);
+
+ connect( kapp, SIGNAL( settingsChanged(int) ), SLOT( slotSettingsChanged(int) ) );
+ slotSettingsChanged(KApplication::SETTINGS_SHORTCUTS);
+
+ m_data = new KexiTableViewData(); //to prevent crash because m_data==0
+ m_owner = true; //-this will be deleted if needed
+
+ setResizePolicy(Manual);
+ viewport()->setBackgroundMode(Qt::NoBackground);
+// viewport()->setFocusPolicy(StrongFocus);
+ viewport()->setFocusPolicy(WheelFocus);
+ setFocusPolicy(WheelFocus); //<--- !!!!! important (was NoFocus),
+ // otherwise QApplication::setActiveWindow() won't activate
+ // this widget when needed!
+// setFocusProxy(viewport());
+ viewport()->installEventFilter(this);
+
+ //setup colors defaults
+ setBackgroundMode(Qt::PaletteBackground);
+// setEmptyAreaColor(d->appearance.baseColor);//palette().active().color(QColorGroup::Base));
+
+// d->baseColor = colorGroup().base();
+// d->textColor = colorGroup().text();
+
+// d->altColor = KGlobalSettings::alternateBackgroundColor();
+// d->grayColor = QColor(200,200,200);
+ d->diagonalGrayPattern = QBrush(d->appearance.borderColor, Qt::BDiagPattern);
+
+ setLineWidth(1);
+ horizontalScrollBar()->installEventFilter(this);
+ horizontalScrollBar()->raise();
+ verticalScrollBar()->raise();
+
+ //context menu
+ m_popupMenu = new KPopupMenu(this, "contextMenu");
+#if 0 //moved to mainwindow's actions
+ d->menu_id_addRecord = m_popupMenu->insertItem(i18n("Add Record"), this, SLOT(addRecord()), Qt::CTRL+Qt::Key_Insert);
+ d->menu_id_removeRecord = m_popupMenu->insertItem(
+ kapp->iconLoader()->loadIcon("button_cancel", KIcon::Small),
+ i18n("Remove Record"), this, SLOT(removeRecord()), Qt::CTRL+Qt::Key_Delete);
+#endif
+
+#ifdef Q_WS_WIN
+ d->rowHeight = fontMetrics().lineSpacing() + 4;
+#else
+ d->rowHeight = fontMetrics().lineSpacing() + 1;
+#endif
+
+ if(d->rowHeight < 17)
+ d->rowHeight = 17;
+
+ d->pUpdateTimer = new QTimer(this);
+
+// setMargins(14, fontMetrics().height() + 4, 0, 0);
+
+ // Create headers
+ m_horizontalHeader = new KexiTableViewHeader(this, "topHeader");
+ m_horizontalHeader->setSelectionBackgroundColor( palette().active().highlight() );
+ m_horizontalHeader->setOrientation(Qt::Horizontal);
+ m_horizontalHeader->setTracking(false);
+ m_horizontalHeader->setMovingEnabled(false);
+ connect(m_horizontalHeader, SIGNAL(sizeChange(int,int,int)), this, SLOT(slotTopHeaderSizeChange(int,int,int)));
+
+ m_verticalHeader = new KexiRecordMarker(this, "rm");
+ m_verticalHeader->setSelectionBackgroundColor( palette().active().highlight() );
+ m_verticalHeader->setCellHeight(d->rowHeight);
+// m_verticalHeader->setFixedWidth(d->rowHeight);
+ m_verticalHeader->setCurrentRow(-1);
+
+ setMargins(
+ QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
+ m_horizontalHeader->sizeHint().height(), 0, 0);
+
+ setupNavigator();
+
+// setMinimumHeight(horizontalScrollBar()->height() + d->rowHeight + topMargin());
+
+// navPanelLyr->addStretch(25);
+// enableClipper(true);
+
+ if (data)
+ setData( data );
+
+#if 0//(js) doesn't work!
+ d->scrollTimer = new QTimer(this);
+ connect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll()));
+#endif
+
+// setBackgroundAltering(true);
+// setFullRowSelectionEnabled(false);
+
+ setAcceptDrops(true);
+ viewport()->setAcceptDrops(true);
+
+ // Connect header, table and scrollbars
+ connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), m_horizontalHeader, SLOT(setOffset(int)));
+ connect(verticalScrollBar(), SIGNAL(valueChanged(int)), m_verticalHeader, SLOT(setOffset(int)));
+ connect(m_horizontalHeader, SIGNAL(sizeChange(int, int, int)), this, SLOT(slotColumnWidthChanged(int, int, int)));
+ connect(m_horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)), this, SLOT(slotSectionHandleDoubleClicked(int)));
+ connect(m_horizontalHeader, SIGNAL(clicked(int)), this, SLOT(sortColumnInternal(int)));
+
+ connect(d->pUpdateTimer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
+
+// horizontalScrollBar()->show();
+ updateScrollBars();
+// resize(sizeHint());
+// updateContents();
+// setMinimumHeight(horizontalScrollBar()->height() + d->rowHeight + topMargin());
+
+//TMP
+//setVerticalHeaderVisible(false);
+//setHorizontalHeaderVisible(false);
+
+//will be updated by setAppearance: updateFonts();
+ setAppearance(d->appearance); //refresh
+
+ d->cellToolTip = new KexiTableViewCellToolTip(this);
+ new WhatsThis(this);
+}
+
+KexiTableView::~KexiTableView()
+{
+ cancelRowEdit();
+
+ KexiTableViewData *data = m_data;
+ m_data = 0;
+ if (m_owner) {
+ if (data)
+ data->deleteLater();
+ }
+ delete d;
+}
+
+void KexiTableView::clearVariables()
+{
+ KexiDataAwareObjectInterface::clearVariables();
+ d->clearVariables();
+}
+
+/*void KexiTableView::initActions(KActionCollection *ac)
+{
+ emit reloadActions(ac);
+}*/
+
+void KexiTableView::setupNavigator()
+{
+ updateScrollBars();
+
+ m_navPanel = new KexiRecordNavigator(this, leftMargin(), "navPanel");
+ m_navPanel->setRecordHandler(this);
+ m_navPanel->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Preferred);
+}
+
+void KexiTableView::initDataContents()
+{
+ updateWidgetContentsSize();
+
+ KexiDataAwareObjectInterface::initDataContents();
+
+ m_navPanel->showEditingIndicator(false);
+}
+
+void KexiTableView::addHeaderColumn(const QString& caption, const QString& description,
+ const QIconSet& icon, int width)
+{
+ const int nr = m_horizontalHeader->count();
+ if (icon.isNull())
+ m_horizontalHeader->addLabel(caption, width);
+ else
+ m_horizontalHeader->addLabel(icon, caption, width);
+
+ if (!description.isEmpty())
+ m_horizontalHeader->setToolTip(nr, description);
+}
+
+void KexiTableView::updateWidgetContentsSize()
+{
+ QSize s(tableSize());
+ resizeContents(s.width(), s.height());
+}
+
+void KexiTableView::slotRowsDeleted( const QValueList<int> &rows )
+{
+ viewport()->repaint();
+ updateWidgetContentsSize();
+ setCursorPosition(QMAX(0, (int)m_curRow - (int)rows.count()), -1, true);
+}
+
+
+/*void KexiTableView::addDropFilter(const QString &filter)
+{
+ d->dropFilters.append(filter);
+ viewport()->setAcceptDrops(true);
+}*/
+
+void KexiTableView::setFont( const QFont &font )
+{
+ QScrollView::setFont(font);
+ updateFonts(true);
+}
+
+void KexiTableView::updateFonts(bool repaint)
+{
+#ifdef Q_WS_WIN
+ d->rowHeight = fontMetrics().lineSpacing() + 4;
+#else
+ d->rowHeight = fontMetrics().lineSpacing() + 1;
+#endif
+ if (d->appearance.fullRowSelection) {
+ d->rowHeight -= 1;
+ }
+ if(d->rowHeight < 17)
+ d->rowHeight = 17;
+// if(d->rowHeight < 22)
+// d->rowHeight = 22;
+ setMargins(
+ QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
+ m_horizontalHeader->sizeHint().height(), 0, 0);
+// setMargins(14, d->rowHeight, 0, 0);
+ m_verticalHeader->setCellHeight(d->rowHeight);
+
+ KexiDisplayUtils::initDisplayForAutonumberSign(d->autonumberSignDisplayParameters, this);
+ KexiDisplayUtils::initDisplayForDefaultValue(d->defaultValueDisplayParameters, this);
+
+ if (repaint)
+ updateContents();
+}
+
+void KexiTableView::updateAllVisibleRowsBelow(int row)
+{
+ //get last visible row
+ int r = rowAt(clipper()->height()+contentsY());
+ if (r==-1) {
+ r = rows()+1+(isInsertingEnabled()?1:0);
+ }
+ //update all visible rows below
+ int leftcol = m_horizontalHeader->sectionAt( m_horizontalHeader->offset() );
+// int row = m_curRow;
+ updateContents( columnPos( leftcol ), rowPos(row),
+ clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
+}
+
+void KexiTableView::clearColumnsInternal(bool /*repaint*/)
+{
+ while(m_horizontalHeader->count()>0)
+ m_horizontalHeader->removeLabel(0);
+}
+
+void KexiTableView::slotUpdate()
+{
+// kdDebug(44021) << " KexiTableView::slotUpdate() -- " << endl;
+// QSize s(tableSize());
+// viewport()->setUpdatesEnabled(false);
+/// resizeContents(s.width(), s.height());
+// viewport()->setUpdatesEnabled(true);
+
+ updateContents();
+ updateScrollBars();
+ if (m_navPanel)
+ m_navPanel->updateGeometry(leftMargin());
+// updateNavPanelGeometry();
+
+ updateWidgetContentsSize();
+// updateContents(0, contentsY()+clipper()->height()-2*d->rowHeight, clipper()->width(), d->rowHeight*3);
+
+ //updateGeometries();
+// updateContents(0, 0, viewport()->width(), contentsHeight());
+// updateGeometries();
+}
+
+int KexiTableView::currentLocalSortingOrder() const
+{
+ if (m_horizontalHeader->sortIndicatorSection()==-1)
+ return 0;
+ return (m_horizontalHeader->sortIndicatorOrder() == Qt::Ascending) ? 1 : -1;
+}
+
+void KexiTableView::setLocalSortingOrder(int col, int order)
+{
+ if (order == 0)
+ col = -1;
+ if (col>=0)
+ m_horizontalHeader->setSortIndicator(col, (order==1) ? Qt::Ascending : Qt::Descending);
+}
+
+int KexiTableView::currentLocalSortColumn() const
+{
+ return m_horizontalHeader->sortIndicatorSection();
+}
+
+void KexiTableView::updateGUIAfterSorting()
+{
+ int cw = columnWidth(m_curCol);
+ int rh = rowHeight();
+
+// m_verticalHeader->setCurrentRow(m_curRow);
+ center(columnPos(m_curCol) + cw / 2, rowPos(m_curRow) + rh / 2);
+// updateCell(oldRow, m_curCol);
+// updateCell(m_curRow, m_curCol);
+// slotUpdate();
+
+ updateContents();
+// d->pUpdateTimer->start(1,true);
+}
+
+QSizePolicy KexiTableView::sizePolicy() const
+{
+ // this widget is expandable
+ return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+}
+
+QSize KexiTableView::sizeHint() const
+{
+ const QSize &ts = tableSize();
+ int w = QMAX( ts.width() + leftMargin()+ verticalScrollBar()->sizeHint().width() + 2*2,
+ (m_navPanel->isVisible() ? m_navPanel->width() : 0) );
+ int h = QMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(),
+ minimumSizeHint().height() );
+ w = QMIN( w, qApp->desktop()->width()*3/4 ); //stretch
+ h = QMIN( h, qApp->desktop()->height()*3/4 ); //stretch
+
+// kexidbg << "KexiTableView::sizeHint()= " <<w <<", " <<h << endl;
+
+ return QSize(w, h);
+ /*QSize(
+ QMAX( ts.width() + leftMargin() + 2*2, (m_navPanel ? m_navPanel->width() : 0) ),
+ //+ QMIN(m_verticalHeader->width(),d->rowHeight) + margin()*2,
+ QMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(),
+ minimumSizeHint().height() )
+ );*/
+// QMAX(ts.height() + topMargin(), minimumSizeHint().height()) );
+}
+
+QSize KexiTableView::minimumSizeHint() const
+{
+ return QSize(
+ leftMargin() + ((columns()>0)?columnWidth(0):KEXI_DEFAULT_DATA_COLUMN_WIDTH) + 2*2,
+ d->rowHeight*5/2 + topMargin() + (m_navPanel && m_navPanel->isVisible() ? m_navPanel->height() : 0)
+ );
+}
+
+void KexiTableView::createBuffer(int width, int height)
+{
+ if(!d->pBufferPm)
+ d->pBufferPm = new QPixmap(width, height);
+ else
+ if(d->pBufferPm->width() < width || d->pBufferPm->height() < height)
+ d->pBufferPm->resize(width, height);
+// d->pBufferPm->fill();
+}
+
+//internal
+inline void KexiTableView::paintRow(KexiTableItem *item,
+ QPainter *pb, int r, int rowp, int cx, int cy,
+ int colfirst, int collast, int maxwc)
+{
+ if (!item)
+ return;
+ // Go through the columns in the row r
+ // if we know from where to where, go through [colfirst, collast],
+ // else go through all of them
+ if (colfirst==-1)
+ colfirst=0;
+ if (collast==-1)
+ collast=columns()-1;
+
+ int transly = rowp-cy;
+
+ if (d->appearance.rowHighlightingEnabled && r == m_curRow && !d->appearance.fullRowSelection) {
+ pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowHighlightingColor);
+ }
+ else if (d->appearance.rowMouseOverHighlightingEnabled && r == d->highlightedRow) {
+ if(d->appearance.backgroundAltering && (r%2 != 0))
+ pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowMouseOverAlternateHighlightingColor);
+ else
+ pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowMouseOverHighlightingColor);
+ }
+ else {
+ if(d->appearance.backgroundAltering && (r%2 != 0))
+ pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.alternateBackgroundColor);
+ else
+ pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.baseColor);
+ }
+
+ for(int c = colfirst; c <= collast; c++)
+ {
+ // get position and width of column c
+ int colp = columnPos(c);
+ if (colp==-1)
+ continue; //invisible column?
+ int colw = columnWidth(c);
+ int translx = colp-cx;
+
+ // Translate painter and draw the cell
+ pb->saveWorldMatrix();
+ pb->translate(translx, transly);
+ paintCell( pb, item, c, r, QRect(colp, rowp, colw, d->rowHeight));
+ pb->restoreWorldMatrix();
+ }
+
+ if (m_dragIndicatorLine>=0) {
+ int y_line = -1;
+ if (r==(rows()-1) && m_dragIndicatorLine==rows()) {
+ y_line = transly+d->rowHeight-3; //draw at last line
+ }
+ if (m_dragIndicatorLine==r) {
+ y_line = transly+1;
+ }
+ if (y_line>=0) {
+ RasterOp op = pb->rasterOp();
+ pb->setRasterOp(XorROP);
+ pb->setPen( QPen(Qt::white, 3) );
+ pb->drawLine(0, y_line, maxwc, y_line);
+ pb->setRasterOp(op);
+ }
+ }
+}
+
+void KexiTableView::drawContents( QPainter *p, int cx, int cy, int cw, int ch)
+{
+ if (d->disableDrawContents)
+ return;
+ int colfirst = columnAt(cx);
+ int rowfirst = rowAt(cy);
+ int collast = columnAt(cx + cw-1);
+ int rowlast = rowAt(cy + ch-1);
+ bool inserting = isInsertingEnabled();
+ bool plus1row = false; //true if we should show 'inserting' row at the end
+ bool paintOnlyInsertRow = false;
+
+/* kdDebug(44021) << QString(" KexiTableView::drawContents(cx:%1 cy:%2 cw:%3 ch:%4)")
+ .arg(cx).arg(cy).arg(cw).arg(ch) << endl;*/
+
+ if (rowlast == -1) {
+ rowlast = rows() - 1;
+ plus1row = inserting;
+ if (rowfirst == -1) {
+ if (rowAt(cy - d->rowHeight) != -1) {
+ paintOnlyInsertRow = true;
+// kdDebug(44021) << "-- paintOnlyInsertRow --" << endl;
+ }
+ }
+ }
+// kdDebug(44021) << "rowfirst="<<rowfirst<<" rowlast="<<rowlast<<" rows()="<<rows()<<endl;
+// kdDebug(44021)<<" plus1row=" << plus1row<<endl;
+
+ if ( collast == -1 )
+ collast = columns() - 1;
+
+ if (colfirst>collast) {
+ int tmp = colfirst;
+ colfirst = collast;
+ collast = tmp;
+ }
+ if (rowfirst>rowlast) {
+ int tmp = rowfirst;
+ rowfirst = rowlast;
+ rowlast = tmp;
+ }
+
+// qDebug("cx:%3d cy:%3d w:%3d h:%3d col:%2d..%2d row:%2d..%2d tsize:%4d,%4d",
+// cx, cy, cw, ch, colfirst, collast, rowfirst, rowlast, tableSize().width(), tableSize().height());
+// triggerUpdate();
+
+ if (rowfirst == -1 || colfirst == -1) {
+ if (!paintOnlyInsertRow && !plus1row) {
+ paintEmptyArea(p, cx, cy, cw, ch);
+ return;
+ }
+ }
+
+ createBuffer(cw, ch);
+ if(d->pBufferPm->isNull())
+ return;
+ QPainter *pb = new QPainter(d->pBufferPm, this);
+// pb->fillRect(0, 0, cw, ch, colorGroup().base());
+
+// int maxwc = QMIN(cw, (columnPos(d->numCols - 1) + columnWidth(d->numCols - 1)));
+ int maxwc = columnPos(columns() - 1) + columnWidth(columns() - 1);
+// kdDebug(44021) << "KexiTableView::drawContents(): maxwc: " << maxwc << endl;
+
+ pb->fillRect(cx, cy, cw, ch, d->appearance.baseColor);
+
+ int rowp;
+ int r;
+ if (paintOnlyInsertRow) {
+ r = rows();
+ rowp = rowPos(r); // 'insert' row's position
+ }
+ else {
+ QPtrListIterator<KexiTableItem> it = m_data->iterator();
+ it += rowfirst;//move to 1st row
+ rowp = rowPos(rowfirst); // row position
+ for (r = rowfirst;r <= rowlast; r++, ++it, rowp+=d->rowHeight) {
+ paintRow(it.current(), pb, r, rowp, cx, cy, colfirst, collast, maxwc);
+ }
+ }
+
+ if (plus1row) { //additional - 'insert' row
+ paintRow(m_insertItem, pb, r, rowp, cx, cy, colfirst, collast, maxwc);
+ }
+
+ delete pb;
+
+ p->drawPixmap(cx,cy,*d->pBufferPm, 0,0,cw,ch);
+
+ //(js)
+ paintEmptyArea(p, cx, cy, cw, ch);
+}
+
+bool KexiTableView::isDefaultValueDisplayed(KexiTableItem *item, int col, QVariant* value)
+{
+ const bool cursorAtInsertRowOrEditingNewRow = (item == m_insertItem || (m_newRowEditing && m_currentItem == item));
+ KexiTableViewColumn *tvcol;
+ if (cursorAtInsertRowOrEditingNewRow
+ && (tvcol = m_data->column(col))
+ && hasDefaultValueAt(*tvcol)
+ && !tvcol->field()->isAutoIncrement())
+ {
+ if (value)
+ *value = tvcol->field()->defaultValue();
+ return true;
+ }
+ return false;
+}
+
+void KexiTableView::paintCell(QPainter* p, KexiTableItem *item, int col, int row, const QRect &cr, bool print)
+{
+ p->save();
+ Q_UNUSED(print);
+ int w = cr.width();
+ int h = cr.height();
+ int x2 = w - 1;
+ int y2 = h - 1;
+
+/* if (0==qstrcmp("KexiComboBoxPopup",parentWidget()->className())) {
+ kexidbg << parentWidget()->className() << " >>>>>> KexiTableView::paintCell(col=" << col <<"row="<<row<<") w="<<w<<endl;
+ }*/
+
+ // Draw our lines
+ QPen pen(p->pen());
+
+ if (d->appearance.gridEnabled) {
+ p->setPen(d->appearance.borderColor);
+ p->drawLine( x2, 0, x2, y2 ); // right
+ p->drawLine( 0, y2, x2, y2 ); // bottom
+ }
+ p->setPen(pen);
+
+ if (m_editor && row == m_curRow && col == m_curCol //don't paint contents of edited cell
+ && m_editor->hasFocusableWidget() //..if it's visible
+ ) {
+ p->restore();
+ return;
+ }
+
+ KexiTableEdit *edit = tableEditorWidget( col, /*ignoreMissingEditor=*/true );
+// if (!edit)
+// return;
+
+ int x = edit ? edit->leftMargin() : 0;
+ int y_offset=0;
+
+ int align = Qt::SingleLine | Qt::AlignVCenter;
+ QString txt; //text to draw
+
+ KexiTableViewColumn *tvcol = m_data->column(col);
+
+ QVariant cellValue;
+ if (col < (int)item->count()) {
+ if (m_currentItem == item) {
+ if (m_editor && row == m_curRow && col == m_curCol
+ && !m_editor->hasFocusableWidget())
+ {
+ //we're over editing cell and the editor has no widget
+ // - we're displaying internal values, not buffered
+// bool ok;
+ cellValue = m_editor->value();
+ }
+ else {
+ //we're displaying values from edit buffer, if available
+ // this assignment will also get default value if there's no actual value set
+ cellValue = *bufferedValueAt(col);
+ }
+ }
+ else {
+ cellValue = item->at(col);
+ }
+ }
+
+ bool defaultValueDisplayed = isDefaultValueDisplayed(item, col);
+
+ if ((item == m_insertItem /*|| m_newRowEditing*/) && cellValue.isNull()) {
+ if (!tvcol->field()->isAutoIncrement() && !tvcol->field()->defaultValue().isNull()) {
+ //display default value in the "insert row", if available
+ //(but not if there is autoincrement flag set)
+ cellValue = tvcol->field()->defaultValue();
+ defaultValueDisplayed = true;
+ }
+ }
+
+ const bool columnReadOnly = tvcol->isReadOnly();
+ const bool dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
+ = d->appearance.rowHighlightingEnabled && !d->appearance.persistentSelections
+ && m_curRow /*d->highlightedRow*/ >= 0 && row != m_curRow; //d->highlightedRow;
+
+ // setup default pen
+ QPen defaultPen;
+ const bool usesSelectedTextColor = edit && edit->usesSelectedTextColor();
+ if (defaultValueDisplayed) {
+ if (col == m_curCol && row == m_curRow && usesSelectedTextColor)
+ defaultPen = d->defaultValueDisplayParameters.selectedTextColor;
+ else
+ defaultPen = d->defaultValueDisplayParameters.textColor;
+ }
+ else if (d->appearance.fullRowSelection
+ && (row == d->highlightedRow || (row == m_curRow && d->highlightedRow==-1))
+ && usesSelectedTextColor )
+ {
+ defaultPen = d->appearance.rowHighlightingTextColor; //special case: highlighted row
+ }
+ else if (d->appearance.fullRowSelection && row == m_curRow && usesSelectedTextColor)
+ {
+ defaultPen = d->appearance.textColor; //special case for full row selection
+ }
+ else if (m_currentItem == item && col == m_curCol && !columnReadOnly
+ && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
+ && usesSelectedTextColor)
+ {
+ defaultPen = colorGroup().highlightedText(); //selected text
+ }
+ else if (d->appearance.rowHighlightingEnabled && row == m_curRow
+ && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
+ && usesSelectedTextColor)
+ {
+ defaultPen = d->appearance.rowHighlightingTextColor;
+ }
+ else if (d->appearance.rowMouseOverHighlightingEnabled && row == d->highlightedRow
+ && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
+ && usesSelectedTextColor)
+ {
+ defaultPen = d->appearance.rowMouseOverHighlightingTextColor;
+ }
+ else
+ defaultPen = d->appearance.textColor;
+
+ if (edit) {
+ if (defaultValueDisplayed)
+ p->setFont( d->defaultValueDisplayParameters.font );
+ p->setPen( defaultPen );
+
+ //get visible lookup value if available
+ getVisibleLookupValue(cellValue, edit, item, tvcol);
+
+ edit->setupContents( p, m_currentItem == item && col == m_curCol,
+ cellValue, txt, align, x, y_offset, w, h );
+ }
+ if (!d->appearance.gridEnabled)
+ y_offset++; //correction because we're not drawing cell borders
+
+ if (d->appearance.fullRowSelection && d->appearance.fullRowSelection) {
+// p->fillRect(x, y_offset, x+w-1, y_offset+h-1, red);
+ }
+ if (m_currentItem == item && (col == m_curCol || d->appearance.fullRowSelection)) {
+ if (edit && ((d->appearance.rowHighlightingEnabled && !d->appearance.fullRowSelection) || (row == m_curRow && d->highlightedRow==-1 && d->appearance.fullRowSelection))) //!dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted)
+ edit->paintSelectionBackground( p, isEnabled(), txt, align, x, y_offset, w, h,
+ isEnabled() ? colorGroup().highlight() : QColor(200,200,200),//d->grayColor,
+ p->fontMetrics(), columnReadOnly, d->appearance.fullRowSelection );
+ }
+
+ if (!edit) {
+ p->fillRect(0, 0, x2, y2, d->diagonalGrayPattern);
+ }
+
+// If we are in the focus cell, draw indication
+ if(m_currentItem == item && col == m_curCol //js: && !d->recordIndicator)
+ && !d->appearance.fullRowSelection)
+ {
+// kexidbg << ">>> CURRENT CELL ("<<m_curCol<<"," << m_curRow<<") focus="<<has_focus<<endl;
+// if (has_focus) {
+ if (isEnabled()) {
+ p->setPen(d->appearance.textColor);
+ }
+ else {
+ QPen gray_pen(p->pen());
+ gray_pen.setColor(d->appearance.borderColor);
+ p->setPen(gray_pen);
+ }
+ if (edit)
+ edit->paintFocusBorders( p, cellValue, 0, 0, x2, y2 );
+ else
+ p->drawRect(0, 0, x2, y2);
+ }
+
+/// bool autonumber = false;
+ if ((!m_newRowEditing && item == m_insertItem)
+ || (m_newRowEditing && item == m_currentItem && cellValue.isNull())) {
+ //we're in "insert row"
+ if (tvcol->field()->isAutoIncrement()) {
+ //"autonumber" column
+// txt = i18n("(autonumber)");
+// autonumber = true;
+// if (autonumber) {
+ KexiDisplayUtils::paintAutonumberSign(d->autonumberSignDisplayParameters, p,
+ x, y_offset, w - x - x - ((align & Qt::AlignLeft)?2:0), h, align);
+// }
+ }
+ }
+
+ // draw text
+ if (!txt.isEmpty()) {
+ if (defaultValueDisplayed)
+ p->setFont( d->defaultValueDisplayParameters.font );
+ p->setPen( defaultPen );
+ p->drawText(x, y_offset, w - (x + x)- ((align & Qt::AlignLeft)?2:0)/*right space*/, h,
+ align, txt);
+ }
+ p->restore();
+}
+
+QPoint KexiTableView::contentsToViewport2( const QPoint &p )
+{
+ return QPoint( p.x() - contentsX(), p.y() - contentsY() );
+}
+
+void KexiTableView::contentsToViewport2( int x, int y, int& vx, int& vy )
+{
+ const QPoint v = contentsToViewport2( QPoint( x, y ) );
+ vx = v.x();
+ vy = v.y();
+}
+
+QPoint KexiTableView::viewportToContents2( const QPoint& vp )
+{
+ return QPoint( vp.x() + contentsX(),
+ vp.y() + contentsY() );
+}
+
+void KexiTableView::paintEmptyArea( QPainter *p, int cx, int cy, int cw, int ch )
+{
+// qDebug("%s: paintEmptyArea(x:%d y:%d w:%d h:%d)", (const char*)parentWidget()->caption(),cx,cy,cw,ch);
+
+ // Regions work with shorts, so avoid an overflow and adjust the
+ // table size to the visible size
+ QSize ts( tableSize() );
+// ts.setWidth( QMIN( ts.width(), visibleWidth() ) );
+// ts.setHeight( QMIN( ts.height() - (m_navPanel ? m_navPanel->height() : 0), visibleHeight()) );
+/* kdDebug(44021) << QString(" (cx:%1 cy:%2 cw:%3 ch:%4)")
+ .arg(cx).arg(cy).arg(cw).arg(ch) << endl;
+ kdDebug(44021) << QString(" (w:%3 h:%4)")
+ .arg(ts.width()).arg(ts.height()) << endl;*/
+
+ // Region of the rect we should draw, calculated in viewport
+ // coordinates, as a region can't handle bigger coordinates
+ contentsToViewport2( cx, cy, cx, cy );
+ QRegion reg( QRect( cx, cy, cw, ch ) );
+
+//kexidbg << "---cy-- " << contentsY() << endl;
+
+ // Subtract the table from it
+// reg = reg.subtract( QRect( QPoint( 0, 0 ), ts-QSize(0,m_navPanel->isVisible() ? m_navPanel->height() : 0) ) );
+ reg = reg.subtract( QRect( QPoint( 0, 0 ), ts
+ -QSize(0,QMAX((m_navPanel ? m_navPanel->height() : 0), horizontalScrollBar()->sizeHint().height())
+ - (horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height()/2 : 0)
+ + (horizontalScrollBar()->isVisible() ? 0 :
+ d->internal_bottomMargin
+// horizontalScrollBar()->sizeHint().height()/2
+ )
+//- /*d->bottomMargin */ horizontalScrollBar()->sizeHint().height()*3/2
+ + contentsY()
+// - (verticalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height()/2 : 0)
+ )
+ ) );
+// reg = reg.subtract( QRect( QPoint( 0, 0 ), ts ) );
+
+ // And draw the rectangles (transformed inc contents coordinates as needed)
+ QMemArray<QRect> r = reg.rects();
+ for ( int i = 0; i < (int)r.count(); i++ ) {
+ QRect rect( viewportToContents2(r[i].topLeft()), r[i].size() );
+/* kdDebug(44021) << QString("- pEA: p->fillRect(x:%1 y:%2 w:%3 h:%4)")
+ .arg(rect.x()).arg(rect.y())
+ .arg(rect.width()).arg(rect.height()) << endl;*/
+// p->fillRect( QRect(viewportToContents2(r[i].topLeft()),r[i].size()), d->emptyAreaColor );
+ p->fillRect( rect, d->appearance.emptyAreaColor );
+// p->fillRect( QRect(viewportToContents2(r[i].topLeft()),r[i].size()), viewport()->backgroundBrush() );
+ }
+}
+
+void KexiTableView::contentsMouseDoubleClickEvent(QMouseEvent *e)
+{
+// kdDebug(44021) << "KexiTableView::contentsMouseDoubleClickEvent()" << endl;
+ m_contentsMousePressEvent_dblClick = true;
+ contentsMousePressEvent(e);
+ m_contentsMousePressEvent_dblClick = false;
+
+ if(m_currentItem)
+ {
+ if(d->editOnDoubleClick && columnEditable(m_curCol) && columnType(m_curCol) != KexiDB::Field::Boolean) {
+ KexiTableEdit *edit = tableEditorWidget( m_curCol, /*ignoreMissingEditor=*/true );
+ if (edit && edit->handleDoubleClick()) {
+ //nothing to do: editors like BLOB editor has custom handling of double clicking
+ }
+ else {
+ startEditCurrentCell();
+ // createEditor(m_curRow, m_curCol, QString::null);
+ }
+ }
+
+ emit itemDblClicked(m_currentItem, m_curRow, m_curCol);
+ }
+}
+
+void KexiTableView::contentsMousePressEvent( QMouseEvent* e )
+{
+// kdDebug(44021) << "KexiTableView::contentsMousePressEvent() ??" << endl;
+ setFocus();
+ if(m_data->count()==0 && !isInsertingEnabled()) {
+ QScrollView::contentsMousePressEvent( e );
+ return;
+ }
+
+ if (columnAt(e->pos().x())==-1) { //outside a colums
+ QScrollView::contentsMousePressEvent( e );
+ return;
+ }
+// d->contentsMousePressEvent_ev = *e;
+// d->contentsMousePressEvent_enabled = true;
+// QTimer::singleShot(2000, this, SLOT( contentsMousePressEvent_Internal() ));
+// d->contentsMousePressEvent_timer.start(100,true);
+
+// if (!d->contentsMousePressEvent_enabled)
+// return;
+// d->contentsMousePressEvent_enabled=false;
+
+ if (!d->moveCursorOnMouseRelease) {
+ if (!handleContentsMousePressOrRelease(e, false))
+ return;
+ }
+
+// kdDebug(44021)<<"void KexiTableView::contentsMousePressEvent( QMouseEvent* e ) by now the current items should be set, if not -> error + crash"<<endl;
+ if(e->button() == Qt::RightButton)
+ {
+ showContextMenu(e->globalPos());
+ }
+ else if(e->button() == Qt::LeftButton)
+ {
+ if(columnType(m_curCol) == KexiDB::Field::Boolean && columnEditable(m_curCol))
+ {
+ //only accept clicking on the [x] rect (copied from KexiBoolTableEdit::setupContents())
+ int s = QMAX(d->rowHeight - 5, 12);
+ s = QMIN( d->rowHeight-3, s );
+ s = QMIN( columnWidth(m_curCol)-3, s ); //avoid too large box
+ const QRect r( columnPos(m_curCol) + QMAX( columnWidth(m_curCol)/2 - s/2, 0 ), rowPos(m_curRow) +d->rowHeight/2 - s/2 /*- 1*/, s, s);
+ //kexidbg << r << endl;
+ if (r.contains(e->pos())) {
+// kexidbg << "e->x:" << e->x() << " e->y:" << e->y() << " " << rowPos(m_curRow) <<
+// " " << columnPos(m_curCol) << endl;
+ boolToggled();
+ }
+ }
+#if 0 //js: TODO
+ else if(columnType(m_curCol) == QVariant::StringList && columnEditable(m_curCol))
+ {
+ createEditor(m_curRow, m_curCol);
+ }
+#endif
+ }
+//ScrollView::contentsMousePressEvent( e );
+}
+
+void KexiTableView::contentsMouseReleaseEvent( QMouseEvent* e )
+{
+// kdDebug(44021) << "KexiTableView::contentsMousePressEvent() ??" << endl;
+ if(m_data->count()==0 && !isInsertingEnabled())
+ return;
+
+ if (d->moveCursorOnMouseRelease)
+ handleContentsMousePressOrRelease(e, true);
+
+ int col = columnAt(e->pos().x());
+ int row = rowAt(e->pos().y());
+
+ if (!m_currentItem || col==-1 || row==-1 || col!=m_curCol || row!=m_curRow)//outside a current cell
+ return;
+
+ QScrollView::contentsMouseReleaseEvent( e );
+
+ emit itemMouseReleased(m_currentItem, m_curRow, m_curCol);
+}
+
+bool KexiTableView::handleContentsMousePressOrRelease(QMouseEvent* e, bool release)
+{
+ // remember old focus cell
+ int oldRow = m_curRow;
+ int oldCol = m_curCol;
+ kdDebug(44021) << "oldRow=" << oldRow <<" oldCol=" << oldCol <<endl;
+ bool onInsertItem = false;
+
+ int newrow, newcol;
+ //compute clicked row nr
+ if (isInsertingEnabled()) {
+ if (rowAt(e->pos().y())==-1) {
+ newrow = rowAt(e->pos().y() - d->rowHeight);
+ if (newrow==-1 && m_data->count()>0) {
+ if (release)
+ QScrollView::contentsMouseReleaseEvent( e );
+ else
+ QScrollView::contentsMousePressEvent( e );
+ return false;
+ }
+ newrow++;
+ kdDebug(44021) << "Clicked just on 'insert' row." << endl;
+ onInsertItem=true;
+ }
+ else {
+ // get new focus cell
+ newrow = rowAt(e->pos().y());
+ }
+ }
+ else {
+ if (rowAt(e->pos().y())==-1 || columnAt(e->pos().x())==-1) {
+ if (release)
+ QScrollView::contentsMouseReleaseEvent( e );
+ else
+ QScrollView::contentsMousePressEvent( e );
+ return false; //clicked outside a grid
+ }
+ // get new focus cell
+ newrow = rowAt(e->pos().y());
+ }
+ newcol = columnAt(e->pos().x());
+
+ if(e->button() != Qt::NoButton) {
+ setCursorPosition(newrow,newcol);
+ }
+ return true;
+}
+
+void KexiTableView::showContextMenu(const QPoint& _pos)
+{
+ if (!d->contextMenuEnabled || m_popupMenu->count()<1)
+ return;
+ QPoint pos(_pos);
+ if (pos==QPoint(-1,-1)) {
+ pos = viewport()->mapToGlobal( QPoint( columnPos(m_curCol), rowPos(m_curRow) + d->rowHeight ) );
+ }
+ //show own context menu if configured
+// if (updateContextMenu()) {
+ selectRow(m_curRow);
+ m_popupMenu->exec(pos);
+/* }
+ else {
+ //request other context menu
+ emit contextMenuRequested(m_currentItem, m_curCol, pos);
+ }*/
+}
+
+void KexiTableView::contentsMouseMoveEvent( QMouseEvent *e )
+{
+ int row;
+ const int col = columnAt(e->x());
+ if (col < 0) {
+ row = -1;
+ } else {
+ row = rowAt( e->y(), true /*ignoreEnd*/ );
+ if (row > (rows() - 1 + (isInsertingEnabled()?1:0)))
+ row = -1; //no row to paint
+ }
+// kexidbg << " row="<<row<< " col="<<col<<endl;
+ //update row highlight if needed
+ if (d->appearance.rowMouseOverHighlightingEnabled) {
+ if (row != d->highlightedRow) {
+ const int oldRow = d->highlightedRow;
+ d->highlightedRow = row;
+ updateRow(oldRow);
+ updateRow(d->highlightedRow);
+ //currently selected (not necessary highlighted) row needs to be repainted
+ updateRow(m_curRow);
+ m_verticalHeader->setHighlightedRow(d->highlightedRow);
+ }
+ }
+
+#if 0//(js) doesn't work!
+
+ // do the same as in mouse press
+ int x,y;
+ contentsToViewport(e->x(), e->y(), x, y);
+
+ if(y > visibleHeight())
+ {
+ d->needAutoScroll = true;
+ d->scrollTimer->start(70, false);
+ d->scrollDirection = ScrollDown;
+ }
+ else if(y < 0)
+ {
+ d->needAutoScroll = true;
+ d->scrollTimer->start(70, false);
+ d->scrollDirection = ScrollUp;
+ }
+ else if(x > visibleWidth())
+ {
+ d->needAutoScroll = true;
+ d->scrollTimer->start(70, false);
+ d->scrollDirection = ScrollRight;
+ }
+ else if(x < 0)
+ {
+ d->needAutoScroll = true;
+ d->scrollTimer->start(70, false);
+ d->scrollDirection = ScrollLeft;
+ }
+ else
+ {
+ d->needAutoScroll = false;
+ d->scrollTimer->stop();
+ contentsMousePressEvent(e);
+ }
+#endif
+ QScrollView::contentsMouseMoveEvent(e);
+}
+
+#if 0//(js) doesn't work!
+void KexiTableView::contentsMouseReleaseEvent(QMouseEvent *)
+{
+ if(d->needAutoScroll)
+ {
+ d->scrollTimer->stop();
+ }
+}
+#endif
+
+static bool overrideEditorShortcutNeeded(QKeyEvent *e)
+{
+ //perhaps more to come...
+ return e->key() == Qt::Key_Delete && e->state()==Qt::ControlButton;
+}
+
+bool KexiTableView::shortCutPressed( QKeyEvent *e, const QCString &action_name )
+{
+ const int k = e->key();
+ KAction *action = m_sharedActions[action_name];
+ if (action) {
+ if (!action->isEnabled())//this action is disabled - don't process it!
+ return false;
+ if (action->shortcut() == KShortcut( KKey(e) )) {
+ //special cases when we need to override editor's shortcut
+ if (overrideEditorShortcutNeeded(e)) {
+ return true;
+ }
+ return false;//this shortcut is owned by shared action - don't process it!
+ }
+ }
+
+ //check default shortcut (when user app has no action shortcuts defined
+ // but we want these shortcuts to still work)
+ if (action_name=="data_save_row")
+ return (k == Qt::Key_Return || k == Qt::Key_Enter) && e->state()==Qt::ShiftButton;
+ if (action_name=="edit_delete_row")
+ return k == Qt::Key_Delete && e->state()==Qt::ControlButton;
+ if (action_name=="edit_delete")
+ return k == Qt::Key_Delete && e->state()==Qt::NoButton;
+ if (action_name=="edit_edititem")
+ return k == Qt::Key_F2 && e->state()==Qt::NoButton;
+ if (action_name=="edit_insert_empty_row")
+ return k == Qt::Key_Insert && e->state()==(Qt::ShiftButton | Qt::ControlButton);
+
+ return false;
+}
+
+void KexiTableView::keyPressEvent(QKeyEvent* e)
+{
+ if (!hasData())
+ return;
+// kexidbg << "KexiTableView::keyPressEvent: key=" <<e->key() << " txt=" <<e->text()<<endl;
+
+ const int k = e->key();
+ const bool ro = isReadOnly();
+ QWidget *w = focusWidget();
+// if (!w || w!=viewport() && w!=this && (!m_editor || w!=m_editor->view() && w!=m_editor)) {
+// if (!w || w!=viewport() && w!=this && (!m_editor || w!=m_editor->view())) {
+ if (!w || w!=viewport() && w!=this && (!m_editor || !KexiUtils::hasParent(dynamic_cast<QObject*>(m_editor), w))) {
+ //don't process stranger's events
+ e->ignore();
+ return;
+ }
+ if (d->skipKeyPress) {
+ d->skipKeyPress=false;
+ e->ignore();
+ return;
+ }
+
+ if(m_currentItem == 0 && (m_data->count() > 0 || isInsertingEnabled()))
+ {
+ setCursorPosition(0,0);
+ }
+ else if(m_data->count() == 0 && !isInsertingEnabled())
+ {
+ e->accept();
+ return;
+ }
+
+ if(m_editor) {// if a cell is edited, do some special stuff
+ if (k == Qt::Key_Escape) {
+ cancelEditor();
+ e->accept();
+ return;
+ } else if (k == Qt::Key_Return || k == Qt::Key_Enter) {
+ if (columnType(m_curCol) == KexiDB::Field::Boolean) {
+ boolToggled();
+ }
+ else {
+ acceptEditor();
+ }
+ e->accept();
+ return;
+ }
+ }
+ else if (m_rowEditing) {// if a row is in edit mode, do some special stuff
+ if (shortCutPressed( e, "data_save_row")) {
+ kexidbg << "shortCutPressed!!!" <<endl;
+ acceptRowEdit();
+ return;
+ }
+ }
+
+ if(k == Qt::Key_Return || k == Qt::Key_Enter)
+ {
+ emit itemReturnPressed(m_currentItem, m_curRow, m_curCol);
+ }
+
+ int curRow = m_curRow;
+ int curCol = m_curCol;
+
+ const bool nobtn = e->state()==NoButton;
+ bool printable = false;
+
+ //check shared shortcuts
+ if (!ro) {
+ if (shortCutPressed(e, "edit_delete_row")) {
+ deleteCurrentRow();
+ e->accept();
+ return;
+ } else if (shortCutPressed(e, "edit_delete")) {
+ deleteAndStartEditCurrentCell();
+ e->accept();
+ return;
+ }
+ else if (shortCutPressed(e, "edit_insert_empty_row")) {
+ insertEmptyRow();
+ e->accept();
+ return;
+ }
+ }
+
+/* case Qt::Key_Delete:
+ if (e->state()==Qt::ControlButton) {//remove current row
+ deleteCurrentRow();
+ }
+ else if (nobtn) {//remove contents of the current cell
+ deleteAndStartEditCurrentCell();
+ }
+ break;*/
+
+// bool _return;
+ if (k == Qt::Key_Shift || k == Qt::Key_Alt || k == Qt::Key_Control || k == Qt::Key_Meta) {
+ e->ignore();
+ }
+ else if (KexiDataAwareObjectInterface::handleKeyPress(e, curRow, curCol, d->appearance.fullRowSelection)) {
+ if (e->isAccepted())
+ return;
+ }
+ else if (k == Qt::Key_Backspace && nobtn) {
+ if (!ro && columnType(curCol) != KexiDB::Field::Boolean && columnEditable(curCol))
+ createEditor(curRow, curCol, QString::null, true);
+ }
+ else if (k == Qt::Key_Space) {
+ if (nobtn && !ro && columnEditable(curCol)) {
+ if (columnType(curCol) == KexiDB::Field::Boolean) {
+ boolToggled();
+ }
+ else
+ printable = true; //just space key
+ }
+ }
+ else if (k == Qt::Key_Escape) {
+ if (nobtn && m_rowEditing) {
+ cancelRowEdit();
+ return;
+ }
+ }
+ else {
+ //others:
+ if (nobtn && (k==Qt::Key_Tab || k==Qt::Key_Right)) {
+//! \todo add option for stopping at 1st column for Qt::Key_left
+ //tab
+ if (acceptEditor()) {
+ if (curCol == (columns() - 1)) {
+ if (curRow < (rows()-1+(isInsertingEnabled()?1:0))) {//skip to next row
+ curRow++;
+ curCol = 0;
+ }
+ }
+ else
+ curCol++;
+ }
+ }
+ else if ((e->state()==Qt::ShiftButton && k==Qt::Key_Tab)
+ || (nobtn && k==Qt::Key_Backtab)
+ || (e->state()==Qt::ShiftButton && k==Qt::Key_Backtab)
+ || (nobtn && k==Qt::Key_Left)
+ ) {
+//! \todo add option for stopping at last column
+ //backward tab
+ if (acceptEditor()) {
+ if (curCol == 0) {
+ if (curRow>0) {//skip to previous row
+ curRow--;
+ curCol = columns() - 1;
+ }
+ }
+ else
+ curCol--;
+ }
+ }
+ else if (nobtn && k==d->contextMenuKey) { //Qt::Key_Menu:
+ showContextMenu();
+ }
+ else {
+ KexiTableEdit *edit = tableEditorWidget( m_curCol );
+ if (edit && edit->handleKeyPress(e, m_editor==edit)) {
+ //try to handle the event @ editor's level
+ e->accept();
+ return;
+ }
+ else if ( nobtn && (k==Qt::Key_Enter || k==Qt::Key_Return || shortCutPressed(e, "edit_edititem")) ) {
+ //this condition is moved after handleKeyPress() to allow to everride enter key as well
+ startEditOrToggleValue();
+ }
+ else {
+ kexidbg << "KexiTableView::KeyPressEvent(): default" << endl;
+ if (e->text().isEmpty() || !e->text().isEmpty() && !e->text()[0].isPrint() ) {
+ kdDebug(44021) << "NOT PRINTABLE: 0x0" << QString("%1").arg(k,0,16) <<endl;
+ // e->ignore();
+ QScrollView::keyPressEvent(e);
+ return;
+ }
+ printable = true;
+ }
+ }
+ }
+ //finally: we've printable char:
+ if (printable && !ro) {
+ KexiTableViewColumn *tvcol = m_data->column(curCol);
+ if (tvcol->acceptsFirstChar(e->text()[0])) {
+ kdDebug(44021) << "KexiTableView::KeyPressEvent(): ev pressed: acceptsFirstChar()==true" << endl;
+ // if (e->text()[0].isPrint())
+ createEditor(curRow, curCol, e->text(), true);
+ }
+ else {
+//TODO show message "key not allowed eg. on a statusbar"
+ kdDebug(44021) << "KexiTableView::KeyPressEvent(): ev pressed: acceptsFirstChar()==false" << endl;
+ }
+ }
+
+ m_vScrollBarValueChanged_enabled=false;
+
+ // if focus cell changes, repaint
+ setCursorPosition(curRow, curCol);
+
+ m_vScrollBarValueChanged_enabled=true;
+
+ e->accept();
+}
+
+void KexiTableView::emitSelected()
+{
+ if(m_currentItem)
+ emit itemSelected(m_currentItem);
+}
+
+int KexiTableView::rowsPerPage() const
+{
+ return visibleHeight() / d->rowHeight;
+}
+
+KexiDataItemInterface *KexiTableView::editor( int col, bool ignoreMissingEditor )
+{
+ if (!m_data || col<0 || col>=columns())
+ return 0;
+ KexiTableViewColumn *tvcol = m_data->column(col);
+// int t = tvcol->field->type();
+
+ //find the editor for this column
+ KexiTableEdit *editor = d->editors[ tvcol ];
+ if (editor)
+ return editor;
+
+ //not found: create
+// editor = KexiCellEditorFactory::createEditor(*m_data->column(col)->field, this);
+ editor = KexiCellEditorFactory::createEditor(*tvcol, this);
+ if (!editor) {//create error!
+ if (!ignoreMissingEditor) {
+ //js TODO: show error???
+ cancelRowEdit();
+ }
+ return 0;
+ }
+ editor->hide();
+ if (m_data->cursor() && m_data->cursor()->query())
+ editor->createInternalEditor(*m_data->cursor()->query());
+
+ connect(editor,SIGNAL(editRequested()),this,SLOT(slotEditRequested()));
+ connect(editor,SIGNAL(cancelRequested()),this,SLOT(cancelEditor()));
+ connect(editor,SIGNAL(acceptRequested()),this,SLOT(acceptEditor()));
+
+ editor->resize(columnWidth(col)-1, rowHeight()-1);
+ editor->installEventFilter(this);
+ if (editor->widget())
+ editor->widget()->installEventFilter(this);
+ //store
+ d->editors.insert( tvcol, editor );
+ return editor;
+}
+
+void KexiTableView::editorShowFocus( int /*row*/, int col )
+{
+ KexiDataItemInterface *edit = editor( col );
+ /*nt p = rowPos(row);
+ (!edit || (p < contentsY()) || (p > (contentsY()+clipper()->height()))) {
+ kexidbg<< "KexiTableView::editorShowFocus() : OUT" << endl;
+ return;
+ }*/
+ if (edit) {
+ kexidbg<< "KexiTableView::editorShowFocus() : IN" << endl;
+ QRect rect = cellGeometry( m_curRow, m_curCol );
+// rect.moveBy( -contentsX(), -contentsY() );
+ edit->showFocus( rect, isReadOnly() || m_data->column(col)->isReadOnly() );
+ }
+}
+
+void KexiTableView::slotEditRequested()
+{
+ createEditor(m_curRow, m_curCol);
+}
+
+void KexiTableView::reloadData() {
+ KexiDataAwareObjectInterface::reloadData();
+ updateContents();
+}
+
+void KexiTableView::createEditor(int row, int col, const QString& addText, bool removeOld)
+{
+ kdDebug(44021) << "KexiTableView::createEditor('"<<addText<<"',"<<removeOld<<")"<<endl;
+ if (isReadOnly()) {
+ kdDebug(44021) << "KexiTableView::createEditor(): DATA IS READ ONLY!"<<endl;
+ return;
+ }
+
+ if (m_data->column(col)->isReadOnly()) {//d->pColumnModes.at(d->numCols-1) & ColumnReadOnly)
+ kdDebug(44021) << "KexiTableView::createEditor(): COL IS READ ONLY!"<<endl;
+ return;
+ }
+
+ const bool startRowEdit = !m_rowEditing; //remember if we're starting row edit
+
+ if (!m_rowEditing) {
+ //we're starting row editing session
+ m_data->clearRowEditBuffer();
+
+ m_rowEditing = true;
+ //indicate on the vheader that we are editing:
+ m_verticalHeader->setEditRow(m_curRow);
+ if (isInsertingEnabled() && m_currentItem==m_insertItem) {
+ //we should know that we are in state "new row editing"
+ m_newRowEditing = true;
+ //'insert' row editing: show another row after that:
+ m_data->append( m_insertItem );
+ //new empty 'inserting' item
+ m_insertItem = m_data->createItem();
+ m_verticalHeader->addLabel();
+ m_verticalHeaderAlreadyAdded = true;
+ updateWidgetContentsSize();
+ //refr. current and next row
+ updateContents(columnPos(0), rowPos(row), viewport()->width(), d->rowHeight*2);
+// updateContents(columnPos(0), rowPos(row+1), viewport()->width(), d->rowHeight);
+//js: warning this breaks behaviour (cursor is skipping, etc.): qApp->processEvents(500);
+ ensureVisible(columnPos(m_curCol), rowPos(row+1)+d->rowHeight-1, columnWidth(m_curCol), d->rowHeight);
+
+ m_verticalHeader->setOffset(contentsY());
+ }
+ }
+
+ KexiTableEdit *editorWidget = tableEditorWidget( col );
+ m_editor = editorWidget;
+ if (!editorWidget)
+ return;
+
+ m_editor->setValue(*bufferedValueAt(col, !removeOld/*useDefaultValueIfPossible*/), addText, removeOld);
+ if (m_editor->hasFocusableWidget()) {
+ moveChild(editorWidget, columnPos(m_curCol), rowPos(m_curRow));
+
+ editorWidget->resize(columnWidth(m_curCol)-1, rowHeight()-1);
+ editorWidget->show();
+
+ m_editor->setFocus();
+ }
+
+ if (startRowEdit) {
+ m_navPanel->showEditingIndicator(true); //this will allow to enable 'next' btn
+// m_navPanel->updateButtons(rows()); //refresh 'next' btn
+ emit rowEditStarted(m_curRow);
+ }
+}
+
+void KexiTableView::focusInEvent(QFocusEvent* e)
+{
+ Q_UNUSED(e);
+ updateCell(m_curRow, m_curCol);
+}
+
+void KexiTableView::focusOutEvent(QFocusEvent* e)
+{
+ KexiDataAwareObjectInterface::focusOutEvent(e);
+}
+
+bool KexiTableView::focusNextPrevChild(bool /*next*/)
+{
+ return false; //special Tab/BackTab meaning
+/* if (m_editor)
+ return true;
+ return QScrollView::focusNextPrevChild(next);*/
+}
+
+void KexiTableView::resizeEvent(QResizeEvent *e)
+{
+ QScrollView::resizeEvent(e);
+ //updateGeometries();
+
+ if (m_navPanel)
+ m_navPanel->updateGeometry(leftMargin());
+// updateNavPanelGeometry();
+
+ if ((contentsHeight() - e->size().height()) <= d->rowHeight) {
+ slotUpdate();
+ triggerUpdate();
+ }
+// d->pTopHeader->repaint();
+
+
+/* m_navPanel->setGeometry(
+ frameWidth(),
+ viewport()->height() +d->pTopHeader->height()
+ -(horizontalScrollBar()->isVisible() ? 0 : horizontalScrollBar()->sizeHint().height())
+ +frameWidth(),
+ m_navPanel->sizeHint().width(), // - verticalScrollBar()->sizeHint().width() - horizontalScrollBar()->sizeHint().width(),
+ horizontalScrollBar()->sizeHint().height()
+ );*/
+// updateContents();
+// m_navPanel->setGeometry(1,horizontalScrollBar()->pos().y(),
+ // m_navPanel->width(), horizontalScrollBar()->height());
+// updateContents(0,0,2000,2000);//js
+// erase(); repaint();
+}
+
+void KexiTableView::viewportResizeEvent( QResizeEvent *e )
+{
+ QScrollView::viewportResizeEvent( e );
+ updateGeometries();
+// erase(); repaint();
+}
+
+void KexiTableView::showEvent(QShowEvent *e)
+{
+ QScrollView::showEvent(e);
+ if (!d->maximizeColumnsWidthOnShow.isEmpty()) {
+ maximizeColumnsWidth(d->maximizeColumnsWidthOnShow);
+ d->maximizeColumnsWidthOnShow.clear();
+ }
+
+ if (m_initDataContentsOnShow) {
+ //full init
+ m_initDataContentsOnShow = false;
+ initDataContents();
+ }
+ else {
+ //just update size
+ QSize s(tableSize());
+// QRect r(cellGeometry(rows() - 1 + (isInsertingEnabled()?1:0), columns() - 1 ));
+// resizeContents(r.right() + 1, r.bottom() + 1);
+ resizeContents(s.width(),s.height());
+ }
+ updateGeometries();
+
+ //now we can ensure cell's visibility ( if there was such a call before show() )
+ if (d->ensureCellVisibleOnShow!=QPoint(-1,-1)) {
+ ensureCellVisible( d->ensureCellVisibleOnShow.x(), d->ensureCellVisibleOnShow.y() );
+ d->ensureCellVisibleOnShow = QPoint(-1,-1); //reset the flag
+ }
+ if (m_navPanel)
+ m_navPanel->updateGeometry(leftMargin());
+// updateNavPanelGeometry();
+}
+
+void KexiTableView::contentsDragMoveEvent(QDragMoveEvent *e)
+{
+ if (!hasData())
+ return;
+ if (m_dropsAtRowEnabled) {
+ QPoint p = e->pos();
+ int row = rowAt(p.y());
+ KexiTableItem *item = 0;
+// if (row==(rows()-1) && (p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
+ if ((p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
+ row++;
+ }
+ item = m_data->at(row);
+ emit dragOverRow(item, row, e);
+ if (e->isAccepted()) {
+ if (m_dragIndicatorLine>=0 && m_dragIndicatorLine != row) {
+ //erase old indicator
+ updateRow(m_dragIndicatorLine);
+ }
+ if (m_dragIndicatorLine != row) {
+ m_dragIndicatorLine = row;
+ updateRow(m_dragIndicatorLine);
+ }
+ }
+ else {
+ if (m_dragIndicatorLine>=0) {
+ //erase old indicator
+ updateRow(m_dragIndicatorLine);
+ }
+ m_dragIndicatorLine = -1;
+ }
+ }
+ else
+ e->acceptAction(false);
+/* QStringList::ConstIterator it, end( d->dropFilters.constEnd() );
+ for( it = d->dropFilters.constBegin(); it != end; it++)
+ {
+ if(e->provides((*it).latin1()))
+ {
+ e->acceptAction(true);
+ return;
+ }
+ }*/
+// e->acceptAction(false);
+}
+
+void KexiTableView::contentsDropEvent(QDropEvent *e)
+{
+ if (!hasData())
+ return;
+ if (m_dropsAtRowEnabled) {
+ //we're no longer dragging over the table
+ if (m_dragIndicatorLine>=0) {
+ int row2update = m_dragIndicatorLine;
+ m_dragIndicatorLine = -1;
+ updateRow(row2update);
+ }
+ QPoint p = e->pos();
+ int row = rowAt(p.y());
+ if ((p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
+ row++;
+ }
+ KexiTableItem *item = m_data->at(row);
+ KexiTableItem *newItem = 0;
+ emit droppedAtRow(item, row, e, newItem);
+ if (newItem) {
+ const int realRow = (row==m_curRow ? -1 : row);
+ insertItem(newItem, realRow);
+ setCursorPosition(row, 0);
+// m_currentItem = newItem;
+ }
+ }
+}
+
+void KexiTableView::viewportDragLeaveEvent( QDragLeaveEvent *e )
+{
+ Q_UNUSED(e);
+ if (!hasData())
+ return;
+ if (m_dropsAtRowEnabled) {
+ //we're no longer dragging over the table
+ if (m_dragIndicatorLine>=0) {
+ int row2update = m_dragIndicatorLine;
+ m_dragIndicatorLine = -1;
+ updateRow(row2update);
+ }
+ }
+}
+
+void KexiTableView::updateCell(int row, int col)
+{
+// kdDebug(44021) << "updateCell("<<row<<", "<<col<<")"<<endl;
+ updateContents(cellGeometry(row, col));
+/* QRect r = cellGeometry(row, col);
+ r.setHeight(r.height()+6);
+ r.setTop(r.top()-3);
+ updateContents();*/
+}
+
+void KexiTableView::updateCurrentCell()
+{
+ updateCell(m_curRow, m_curCol);
+}
+
+void KexiTableView::updateRow(int row)
+{
+// kdDebug(44021) << "updateRow("<<row<<")"<<endl;
+ if (row < 0 || row >= (rows() + 2/* sometimes we want to refresh the row after last*/ ))
+ return;
+ //int leftcol = d->pTopHeader->sectionAt( d->pTopHeader->offset() );
+
+ //kexidbg << contentsX() << " " << contentsY() << endl;
+ //kexidbg << QRect( columnPos( leftcol ), rowPos(row), clipper()->width(), rowHeight() ) << endl;
+ // updateContents( QRect( columnPos( leftcol ), rowPos(row), clipper()->width(), rowHeight() ) ); //columnPos(rightcol)+columnWidth(rightcol), rowHeight() ) );
+ updateContents( QRect( contentsX(), rowPos(row), clipper()->width(), rowHeight() ) ); //columnPos(rightcol)+columnWidth(rightcol), rowHeight() ) );
+}
+
+void KexiTableView::slotColumnWidthChanged( int, int, int )
+{
+ QSize s(tableSize());
+ int w = contentsWidth();
+ viewport()->setUpdatesEnabled(false);
+ resizeContents( s.width(), s.height() );
+ viewport()->setUpdatesEnabled(true);
+ if (contentsWidth() < w) {
+ updateContents(contentsX(), 0, viewport()->width(), contentsHeight());
+// repaintContents( s.width(), 0, w - s.width() + 1, contentsHeight(), true );
+ }
+ else {
+ // updateContents( columnPos(col), 0, contentsWidth(), contentsHeight() );
+ updateContents(contentsX(), 0, viewport()->width(), contentsHeight());
+ // viewport()->repaint();
+ }
+
+// updateContents(0, 0, d->pBufferPm->width(), d->pBufferPm->height());
+ QWidget *editorWidget = dynamic_cast<QWidget*>(m_editor);
+ if (editorWidget)
+ {
+ editorWidget->resize(columnWidth(m_curCol)-1, rowHeight()-1);
+ moveChild(editorWidget, columnPos(m_curCol), rowPos(m_curRow));
+ }
+ updateGeometries();
+ updateScrollBars();
+ if (m_navPanel)
+ m_navPanel->updateGeometry(leftMargin());
+// updateNavPanelGeometry();
+}
+
+void KexiTableView::slotSectionHandleDoubleClicked( int section )
+{
+ adjustColumnWidthToContents(section);
+ slotColumnWidthChanged(0,0,0); //to update contents and redraw
+}
+
+
+void KexiTableView::updateGeometries()
+{
+ QSize ts = tableSize();
+ if (m_horizontalHeader->offset() && ts.width() < (m_horizontalHeader->offset() + m_horizontalHeader->width()))
+ horizontalScrollBar()->setValue(ts.width() - m_horizontalHeader->width());
+
+// m_verticalHeader->setGeometry(1, topMargin() + 1, leftMargin(), visibleHeight());
+ m_horizontalHeader->setGeometry(leftMargin() + 1, 1, visibleWidth(), topMargin());
+ m_verticalHeader->setGeometry(1, topMargin() + 1, leftMargin(), visibleHeight());
+}
+
+int KexiTableView::columnWidth(int col) const
+{
+ if (!hasData())
+ return 0;
+ int vcID = m_data->visibleColumnID( col );
+ return (vcID==-1) ? 0 : m_horizontalHeader->sectionSize( vcID );
+}
+
+int KexiTableView::rowHeight() const
+{
+ return d->rowHeight;
+}
+
+int KexiTableView::columnPos(int col) const
+{
+ if (!hasData())
+ return 0;
+ //if this column is hidden, find first column before that is visible
+ int c = QMIN(col, (int)m_data->columnsCount()-1), vcID = 0;
+ while (c>=0 && (vcID=m_data->visibleColumnID( c ))==-1)
+ c--;
+ if (c<0)
+ return 0;
+ if (c==col)
+ return m_horizontalHeader->sectionPos(vcID);
+ return m_horizontalHeader->sectionPos(vcID)+m_horizontalHeader->sectionSize(vcID);
+}
+
+int KexiTableView::rowPos(int row) const
+{
+ return d->rowHeight*row;
+}
+
+int KexiTableView::columnAt(int pos) const
+{
+ if (!hasData())
+ return -1;
+ int r = m_horizontalHeader->sectionAt(pos);
+ if (r<0)
+ return r;
+ return m_data->globalColumnID( r );
+
+// if (r==-1)
+// kexidbg << "columnAt("<<pos<<")==-1 !!!" << endl;
+// return r;
+}
+
+int KexiTableView::rowAt(int pos, bool ignoreEnd) const
+{
+ if (!hasData())
+ return -1;
+ pos /=d->rowHeight;
+ if (pos < 0)
+ return 0;
+ if ((pos >= (int)m_data->count()) && !ignoreEnd)
+ return -1;
+ return pos;
+}
+
+QRect KexiTableView::cellGeometry(int row, int col) const
+{
+ return QRect(columnPos(col), rowPos(row),
+ columnWidth(col), rowHeight());
+}
+
+QSize KexiTableView::tableSize() const
+{
+ if ((rows()+ (isInsertingEnabled()?1:0) ) > 0 && columns() > 0) {
+/* kexidbg << "tableSize()= " << columnPos( columns() - 1 ) + columnWidth( columns() - 1 )
+ << ", " << rowPos( rows()-1+(isInsertingEnabled()?1:0)) + d->rowHeight
+// + QMAX(m_navPanel ? m_navPanel->height() : 0, horizontalScrollBar()->sizeHint().height())
+ + (m_navPanel->isVisible() ? QMAX( m_navPanel->height(), horizontalScrollBar()->sizeHint().height() ) :0 )
+ + margin() << endl;
+*/
+// kexidbg<< m_navPanel->isVisible() <<" "<<m_navPanel->height()<<" "
+// <<horizontalScrollBar()->sizeHint().height()<<" "<<rowPos( rows()-1+(isInsertingEnabled()?1:0))<<endl;
+
+ //int xx = horizontalScrollBar()->sizeHint().height()/2;
+
+ QSize s(
+ columnPos( columns() - 1 ) + columnWidth( columns() - 1 ),
+// + verticalScrollBar()->sizeHint().width(),
+ rowPos( rows()-1+(isInsertingEnabled()?1:0) ) + d->rowHeight
+ + (horizontalScrollBar()->isVisible() ? 0 : horizontalScrollBar()->sizeHint().height())
+ + d->internal_bottomMargin
+// horizontalScrollBar()->sizeHint().height()/2
+// - /*d->bottomMargin */ horizontalScrollBar()->sizeHint().height()*3/2
+
+// + ( (m_navPanel && m_navPanel->isVisible() && verticalScrollBar()->isVisible()
+ // && !horizontalScrollBar()->isVisible())
+ // ? horizontalScrollBar()->sizeHint().height() : 0)
+
+// + QMAX( (m_navPanel && m_navPanel->isVisible()) ? m_navPanel->height() : 0,
+// horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height() : 0)
+
+// + (m_navPanel->isVisible()
+// ? QMAX( m_navPanel->height(), horizontalScrollBar()->sizeHint().height() ) :0 )
+
+// - (horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height() :0 )
+ + margin()
+//-2*d->rowHeight
+ );
+
+// kexidbg << rows()-1 <<" "<< (isInsertingEnabled()?1:0) <<" "<< (m_rowEditing?1:0) << " " << s << endl;
+ return s;
+// +horizontalScrollBar()->sizeHint().height() + margin() );
+ }
+ return QSize(0,0);
+}
+
+void KexiTableView::ensureCellVisible(int row, int col/*=-1*/)
+{
+ if (!isVisible()) {
+ //the table is invisible: we can't ensure visibility now
+ d->ensureCellVisibleOnShow = QPoint(row,col);
+ return;
+ }
+
+ //quite clever: ensure the cell is visible:
+ QRect r( columnPos(col==-1 ? m_curCol : col), rowPos(row) +(d->appearance.fullRowSelection?1:0),
+ columnWidth(col==-1 ? m_curCol : col), rowHeight());
+
+/* if (m_navPanel && horizontalScrollBar()->isHidden() && row == rows()-1) {
+ //when cursor is moved down and navigator covers the cursor's area,
+ //area is scrolled up
+ if ((viewport()->height() - m_navPanel->height()) < r.bottom()) {
+ scrollBy(0,r.bottom() - (viewport()->height() - m_navPanel->height()));
+ }
+ }*/
+
+ if (m_navPanel && m_navPanel->isVisible() && horizontalScrollBar()->isHidden()) {
+ //a hack: for visible navigator: increase height of the visible rect 'r'
+ r.setBottom(r.bottom()+m_navPanel->height());
+ }
+
+ QPoint pcenter = r.center();
+ ensureVisible(pcenter.x(), pcenter.y(), r.width()/2, r.height()/2);
+// updateContents();
+// updateNavPanelGeometry();
+// slotUpdate();
+}
+
+void KexiTableView::updateAfterCancelRowEdit()
+{
+ KexiDataAwareObjectInterface::updateAfterCancelRowEdit();
+ m_navPanel->showEditingIndicator(false);
+}
+
+void KexiTableView::updateAfterAcceptRowEdit()
+{
+ KexiDataAwareObjectInterface::updateAfterAcceptRowEdit();
+ m_navPanel->showEditingIndicator(false);
+}
+
+bool KexiTableView::getVisibleLookupValue(QVariant& cellValue, KexiTableEdit *edit,
+ KexiTableItem *item, KexiTableViewColumn *tvcol) const
+{
+ if (edit->columnInfo() && edit->columnInfo()->indexForVisibleLookupValue()!=-1
+ && edit->columnInfo()->indexForVisibleLookupValue() < (int)item->count())
+ {
+ const QVariant *visibleFieldValue = 0;
+ if (m_currentItem == item && m_data->rowEditBuffer()) {
+ visibleFieldValue = m_data->rowEditBuffer()->at(
+ *tvcol->visibleLookupColumnInfo, false/*!useDefaultValueIfPossible*/ );
+ }
+
+ if (visibleFieldValue)
+ //(use bufferedValueAt() - try to get buffered visible value for lookup field)
+ cellValue = *visibleFieldValue; //txt = visibleFieldValue->toString();
+ else
+ cellValue /*txt*/ = item->at( edit->columnInfo()->indexForVisibleLookupValue() ); //.toString();
+ return true;
+ }
+ return false;
+}
+
+//reimpl.
+void KexiTableView::removeEditor()
+{
+ if (!m_editor)
+ return;
+ KexiDataAwareObjectInterface::removeEditor();
+ viewport()->setFocus();
+}
+
+void KexiTableView::slotRowRepaintRequested(KexiTableItem& item)
+{
+ updateRow( m_data->findRef(&item) );
+}
+
+//(js) unused
+void KexiTableView::slotAutoScroll()
+{
+ kdDebug(44021) << "KexiTableView::slotAutoScroll()" <<endl;
+ if (!d->needAutoScroll)
+ return;
+
+ switch(d->scrollDirection)
+ {
+ case ScrollDown:
+ setCursorPosition(m_curRow + 1, m_curCol);
+ break;
+
+ case ScrollUp:
+ setCursorPosition(m_curRow - 1, m_curCol);
+ break;
+ case ScrollLeft:
+ setCursorPosition(m_curRow, m_curCol - 1);
+ break;
+
+ case ScrollRight:
+ setCursorPosition(m_curRow, m_curCol + 1);
+ break;
+ }
+}
+
+#ifndef KEXI_NO_PRINT
+void
+KexiTableView::print(KPrinter &/*printer*/)
+{
+// printer.setFullPage(true);
+#if 0
+ int leftMargin = printer.margins().width() + 2 + d->rowHeight;
+ int topMargin = printer.margins().height() + 2;
+// int bottomMargin = topMargin + ( printer.realPageSize()->height() * printer.resolution() + 36 ) / 72;
+ int bottomMargin = 0;
+ kdDebug(44021) << "KexiTableView::print: bottom = " << bottomMargin << endl;
+
+ QPainter p(&printer);
+
+ KexiTableItem *i;
+ int width = leftMargin;
+ for(int col=0; col < columns(); col++)
+ {
+ p.fillRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, QBrush(Qt::gray));
+ p.drawRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight);
+ p.drawText(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, Qt::AlignLeft | Qt::AlignVCenter,
+ m_horizontalHeader->label(col));
+ width = width + columnWidth(col);
+ }
+
+ int yOffset = topMargin;
+ int row = 0;
+ int right = 0;
+ for(i = m_data->first(); i; i = m_data->next())
+ {
+ if(!i->isInsertItem())
+ { kdDebug(44021) << "KexiTableView::print: row = " << row << " y = " << yOffset << endl;
+ int xOffset = leftMargin;
+ for(int col=0; col < columns(); col++)
+ {
+ kdDebug(44021) << "KexiTableView::print: col = " << col << " x = " << xOffset << endl;
+ p.saveWorldMatrix();
+ p.translate(xOffset, yOffset);
+ paintCell(&p, i, col, QRect(0, 0, columnWidth(col) + 1, d->rowHeight), true);
+ p.restoreWorldMatrix();
+// p.drawRect(xOffset, yOffset, columnWidth(col), d->rowHeight);
+ xOffset = xOffset + columnWidth(col);
+ right = xOffset;
+ }
+
+ row++;
+ yOffset = topMargin + row * d->rowHeight;
+ }
+
+ if(yOffset > 900)
+ {
+ p.drawLine(leftMargin, topMargin, leftMargin, yOffset);
+ p.drawLine(leftMargin, topMargin, right - 1, topMargin);
+ printer.newPage();
+ yOffset = topMargin;
+ row = 0;
+ }
+ }
+ p.drawLine(leftMargin, topMargin, leftMargin, yOffset);
+ p.drawLine(leftMargin, topMargin, right - 1, topMargin);
+
+// p.drawLine(60,60,120,150);
+ p.end();
+#endif
+}
+#endif
+
+QString KexiTableView::columnCaption(int colNum) const
+{
+ return m_horizontalHeader->label(colNum);
+}
+
+KexiDB::Field* KexiTableView::field(int colNum) const
+{
+ if (!m_data || !m_data->column(colNum))
+ return 0;
+ return m_data->column(colNum)->field();
+}
+
+void KexiTableView::adjustColumnWidthToContents(int colNum)
+{
+ if (!hasData())
+ return;
+ if (colNum==-1) {
+ const int cols = columns();
+ for (int i=0; i<cols; i++)
+ adjustColumnWidthToContents(i);
+ return;
+ }
+
+ int indexOfVisibleColumn = (m_data->column(colNum) && m_data->column(colNum)->columnInfo)
+ ? m_data->column(colNum)->columnInfo->indexForVisibleLookupValue() : -1;
+ if (-1==indexOfVisibleColumn)
+ indexOfVisibleColumn = colNum;
+
+ if (indexOfVisibleColumn < 0)
+ return;
+
+ QPtrListIterator<KexiTableItem> it = m_data->iterator();
+ if (it.current() && it.current()->count()<=(uint)indexOfVisibleColumn)
+ return;
+
+ KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item( columnType(indexOfVisibleColumn) );
+ if (!item)
+ return;
+ QFontMetrics fm(fontMetrics());
+ int maxw = horizontalHeaderVisible()
+ ? fm.width( m_horizontalHeader->label( colNum/* not indexOfVisibleColumn*/ ) ) : 0;
+ if (maxw == 0 && m_data->isEmpty())
+ return; //nothing to adjust
+
+//! \todo js: this is NOT EFFECTIVE for big data sets!!!!
+
+ KexiTableEdit *ed = tableEditorWidget( colNum/* not indexOfVisibleColumn*/ );
+ if (ed) {
+ for (it = m_data->iterator(); it.current(); ++it) {
+ const int wfw = ed->widthForValue( it.current()->at( indexOfVisibleColumn ), fm );
+ maxw = QMAX( maxw, wfw );
+ }
+ const bool focused = currentColumn() == colNum;
+ maxw += (fm.width(" ") + ed->leftMargin() + ed->rightMargin(focused));
+ }
+ if (maxw < KEXITV_MINIMUM_COLUMN_WIDTH )
+ maxw = KEXITV_MINIMUM_COLUMN_WIDTH; //not too small
+ kexidbg << "KexiTableView: setColumnWidth(colNum=" << colNum
+ << ", indexOfVisibleColumn=" << indexOfVisibleColumn << ", width=" << maxw <<" )" << endl;
+ setColumnWidth( colNum/* not indexOfVisibleColumn*/, maxw );
+}
+
+void KexiTableView::setColumnWidth(int colNum, int width)
+{
+ if (columns()<=colNum || colNum < 0)
+ return;
+ const int oldWidth = m_horizontalHeader->sectionSize( colNum );
+ m_horizontalHeader->resizeSection( colNum, width );
+ slotTopHeaderSizeChange( colNum, oldWidth, m_horizontalHeader->sectionSize( colNum ) );
+}
+
+void KexiTableView::maximizeColumnsWidth( const QValueList<int> &columnList )
+{
+ if (!isVisible()) {
+ d->maximizeColumnsWidthOnShow += columnList;
+ return;
+ }
+ if (width() <= m_horizontalHeader->headerWidth())
+ return;
+ //sort the list and make it unique
+ QValueList<int> cl, sortedList = columnList;
+ qHeapSort(sortedList);
+ int i=-999;
+
+ QValueList<int>::ConstIterator it, end( sortedList.constEnd() );
+ for ( it = sortedList.constBegin(); it != end; ++it) {
+ if (i != (*it)) {
+ cl += (*it);
+ i = (*it);
+ }
+ }
+ //resize
+ int sizeToAdd = (width() - m_horizontalHeader->headerWidth()) / cl.count() - verticalHeader()->width();
+ if (sizeToAdd<=0)
+ return;
+ end = cl.constEnd();
+ for ( it = cl.constBegin(); it != end; ++it) {
+ int w = m_horizontalHeader->sectionSize(*it);
+ if (w>0) {
+ m_horizontalHeader->resizeSection(*it, w+sizeToAdd);
+ }
+ }
+ updateContents();
+ editorShowFocus( m_curRow, m_curCol );
+}
+
+void KexiTableView::adjustHorizontalHeaderSize()
+{
+ m_horizontalHeader->adjustHeaderSize();
+}
+
+void KexiTableView::setColumnStretchEnabled( bool set, int colNum )
+{
+ m_horizontalHeader->setStretchEnabled( set, colNum );
+}
+
+void KexiTableView::setEditableOnDoubleClick(bool set)
+{
+ d->editOnDoubleClick = set;
+}
+bool KexiTableView::editableOnDoubleClick() const
+{
+ return d->editOnDoubleClick;
+}
+
+bool KexiTableView::verticalHeaderVisible() const
+{
+ return m_verticalHeader->isVisible();
+}
+
+void KexiTableView::setVerticalHeaderVisible(bool set)
+{
+ int left_width;
+ if (set) {
+ m_verticalHeader->show();
+ left_width = QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight);
+ }
+ else {
+ m_verticalHeader->hide();
+ left_width = 0;
+ }
+ setMargins( left_width, horizontalHeaderVisible() ? m_horizontalHeader->sizeHint().height() : 0, 0, 0);
+}
+
+bool KexiTableView::horizontalHeaderVisible() const
+{
+ return d->horizontalHeaderVisible;
+}
+
+void KexiTableView::setHorizontalHeaderVisible(bool set)
+{
+ int top_height;
+ d->horizontalHeaderVisible = set; //needed because isVisible() is not always accurate
+ if (set) {
+ m_horizontalHeader->show();
+ top_height = m_horizontalHeader->sizeHint().height();
+ }
+ else {
+ m_horizontalHeader->hide();
+ top_height = 0;
+ }
+ setMargins( verticalHeaderVisible() ? m_verticalHeader->width() : 0, top_height, 0, 0);
+}
+
+void KexiTableView::triggerUpdate()
+{
+// kdDebug(44021) << "KexiTableView::triggerUpdate()" << endl;
+// if (!d->pUpdateTimer->isActive())
+ d->pUpdateTimer->start(20, true);
+// d->pUpdateTimer->start(200, true);
+}
+
+void KexiTableView::setHBarGeometry( QScrollBar & hbar, int x, int y, int w, int h )
+{
+/*todo*/
+ kdDebug(44021)<<"KexiTableView::setHBarGeometry"<<endl;
+ if (d->appearance.navigatorEnabled) {
+ m_navPanel->setHBarGeometry( hbar, x, y, w, h );
+ }
+ else {
+ hbar.setGeometry( x , y, w, h );
+ }
+}
+
+void KexiTableView::setSpreadSheetMode()
+{
+ KexiDataAwareObjectInterface::setSpreadSheetMode();
+ //copy m_navPanelEnabled flag
+ Appearance a = d->appearance;
+ a.navigatorEnabled = m_navPanelEnabled;
+ setAppearance( a );
+}
+
+int KexiTableView::validRowNumber(const QString& text)
+{
+ bool ok=true;
+ int r = text.toInt(&ok);
+ if (!ok || r<1)
+ r = 1;
+ else if (r > (rows()+(isInsertingEnabled()?1:0)))
+ r = rows()+(isInsertingEnabled()?1:0);
+ return r-1;
+}
+
+void KexiTableView::moveToRecordRequested( uint r )
+{
+ if (r > uint(rows()+(isInsertingEnabled()?1:0)))
+ r = rows()+(isInsertingEnabled()?1:0);
+ setFocus();
+ selectRow( r );
+}
+
+void KexiTableView::moveToLastRecordRequested()
+{
+ setFocus();
+ selectRow(rows()>0 ? (rows()-1) : 0);
+}
+
+void KexiTableView::moveToPreviousRecordRequested()
+{
+ setFocus();
+ selectPrevRow();
+}
+
+void KexiTableView::moveToNextRecordRequested()
+{
+ setFocus();
+ selectNextRow();
+}
+
+void KexiTableView::moveToFirstRecordRequested()
+{
+ setFocus();
+ selectFirstRow();
+}
+
+void KexiTableView::copySelection()
+{
+ if (m_currentItem && m_curCol!=-1) {
+ KexiTableEdit *edit = tableEditorWidget( m_curCol );
+ QVariant defaultValue;
+ const bool defaultValueDisplayed
+ = isDefaultValueDisplayed(m_currentItem, m_curCol, &defaultValue);
+ if (edit) {
+ QVariant visibleValue;
+ getVisibleLookupValue(visibleValue, edit, m_currentItem, m_data->column(m_curCol));
+ edit->handleCopyAction(
+ defaultValueDisplayed ? defaultValue : m_currentItem->at( m_curCol ),
+ visibleValue );
+ }
+ }
+}
+
+void KexiTableView::cutSelection()
+{
+ //try to handle @ editor's level
+ KexiTableEdit *edit = tableEditorWidget( m_curCol );
+ if (edit)
+ edit->handleAction("edit_cut");
+}
+
+void KexiTableView::paste()
+{
+ //try to handle @ editor's level
+ KexiTableEdit *edit = tableEditorWidget( m_curCol );
+ if (edit)
+ edit->handleAction("edit_paste");
+}
+
+bool KexiTableView::eventFilter( QObject *o, QEvent *e )
+{
+ //don't allow to stole key my events by others:
+// kexidbg << "spontaneous " << e->spontaneous() << " type=" << e->type() << endl;
+
+ if (e->type()==QEvent::KeyPress) {
+ if (e->spontaneous() /*|| e->type()==QEvent::AccelOverride*/) {
+ QKeyEvent *ke = static_cast<QKeyEvent*>(e);
+ const int k = ke->key();
+ int s = ke->state();
+ //cell editor's events:
+ //try to handle the event @ editor's level
+ KexiTableEdit *edit = tableEditorWidget( m_curCol );
+ if (edit && edit->handleKeyPress(ke, m_editor==edit)) {
+ ke->accept();
+ return true;
+ }
+ else if (m_editor && (o==dynamic_cast<QObject*>(m_editor) || o==m_editor->widget())) {
+ if ( (k==Qt::Key_Tab && (s==Qt::NoButton || s==Qt::ShiftButton))
+ || (overrideEditorShortcutNeeded(ke))
+ || (k==Qt::Key_Enter || k==Qt::Key_Return || k==Qt::Key_Up || k==Qt::Key_Down)
+ || (k==Qt::Key_Left && m_editor->cursorAtStart())
+ || (k==Qt::Key_Right && m_editor->cursorAtEnd())
+ )
+ {
+ //try to steal the key press from editor or it's internal widget...
+ keyPressEvent(ke);
+ if (ke->isAccepted())
+ return true;
+ }
+ }
+ /*
+ else if (e->type()==QEvent::KeyPress && (o==this || (m_editor && o==m_editor->widget()))){//|| o==viewport())
+ keyPressEvent(ke);
+ if (ke->isAccepted())
+ return true;
+ }*/
+/*todo else if ((k==Qt::Key_Tab || k==(Qt::SHIFT|Qt::Key_Tab)) && o==d->navRowNumber) {
+ //tab key focuses tv
+ ke->accept();
+ setFocus();
+ return true;
+ }*/
+ }
+ }
+ else if (o==horizontalScrollBar()) {
+ if ((e->type()==QEvent::Show && !horizontalScrollBar()->isVisible())
+ || (e->type()==QEvent::Hide && horizontalScrollBar()->isVisible())) {
+ updateWidgetContentsSize();
+ }
+ }
+ else if (e->type()==QEvent::Leave) {
+ if (o==viewport() && d->appearance.rowMouseOverHighlightingEnabled
+ && d->appearance.persistentSelections)
+ {
+ if (d->highlightedRow!=-1) {
+ int oldRow = d->highlightedRow;
+ d->highlightedRow = -1;
+ updateRow(oldRow);
+ const bool dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
+ = d->appearance.rowHighlightingEnabled && !d->appearance.persistentSelections;
+ if (oldRow!=m_curRow && m_curRow>=0) {
+ if (!dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted)
+ //no highlight for now: show selection again
+ updateRow(m_curRow);
+ m_verticalHeader->setHighlightedRow(-1);
+ }
+ }
+ }
+ d->recentCellWithToolTip = QPoint(-1,-1);
+ }
+/* else if (e->type()==QEvent::FocusOut && o->inherits("QWidget")) {
+ //hp==true if currently focused widget is a child of this table view
+ const bool hp = KexiUtils::hasParent( static_cast<QWidget*>(o), focusWidget());
+ if (!hp && KexiUtils::hasParent( this, static_cast<QWidget*>(o))) {
+ //accept row editing if focus is moved to foreign widget
+ //(not a child, like eg. editor) from one of our table view's children
+ //or from table view itself
+ if (!acceptRowEdit()) {
+ static_cast<QWidget*>(o)->setFocus();
+ return true;
+ }
+ }
+ }*/
+ return QScrollView::eventFilter(o,e);
+}
+
+void KexiTableView::slotTopHeaderSizeChange(
+ int /*section*/, int /*oldSize*/, int /*newSize*/ )
+{
+ editorShowFocus( m_curRow, m_curCol );
+}
+
+void KexiTableView::setBottomMarginInternal(int pixels)
+{
+ d->internal_bottomMargin = pixels;
+}
+
+void KexiTableView::paletteChange( const QPalette &oldPalette )
+{
+ Q_UNUSED(oldPalette);
+ //update:
+ if (m_verticalHeader)
+ m_verticalHeader->setSelectionBackgroundColor( palette().active().highlight() );
+ if (m_horizontalHeader)
+ m_horizontalHeader->setSelectionBackgroundColor( palette().active().highlight() );
+}
+
+const KexiTableView::Appearance& KexiTableView::appearance() const
+{
+ return d->appearance;
+}
+
+void KexiTableView::setAppearance(const Appearance& a)
+{
+// if (d->appearance.fullRowSelection != a.fullRowSelection) {
+ if (a.fullRowSelection) {
+ d->rowHeight -= 1;
+ }
+ else {
+ d->rowHeight += 1;
+ }
+ if (m_verticalHeader)
+ m_verticalHeader->setCellHeight(d->rowHeight);
+ if (m_horizontalHeader) {
+ setMargins(
+ QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
+ m_horizontalHeader->sizeHint().height(), 0, 0);
+ }
+// }
+ if (a.rowHighlightingEnabled)
+ m_updateEntireRowWhenMovingToOtherRow = true;
+
+ if(!a.navigatorEnabled)
+ m_navPanel->hide();
+ else
+ m_navPanel->show();
+// }
+
+ d->highlightedRow = -1;
+//! @todo is setMouseTracking useful for other purposes?
+ viewport()->setMouseTracking(a.rowMouseOverHighlightingEnabled);
+
+ d->appearance = a;
+
+ setFont(font()); //this also updates contents
+}
+
+int KexiTableView::highlightedRow() const
+{
+ return d->highlightedRow;
+}
+
+void KexiTableView::setHighlightedRow(int row)
+{
+ if (row!=-1) {
+ row = QMIN(rows() - 1 + (isInsertingEnabled()?1:0), row);
+ row = QMAX(0, row);
+ ensureCellVisible(row, -1);
+ }
+ const int previouslyHighlightedRow = d->highlightedRow;
+ if (previouslyHighlightedRow == row) {
+ if (previouslyHighlightedRow!=-1)
+ updateRow(previouslyHighlightedRow);
+ return;
+ }
+ d->highlightedRow = row;
+ if (d->highlightedRow!=-1)
+ updateRow(d->highlightedRow);
+
+ if (previouslyHighlightedRow!=-1)
+ updateRow(previouslyHighlightedRow);
+
+ if (m_curRow>=0 && (previouslyHighlightedRow==-1 || previouslyHighlightedRow==m_curRow)
+ && d->highlightedRow!=m_curRow && !d->appearance.persistentSelections)
+ {
+ //currently selected row needs to be repainted
+ updateRow(m_curRow);
+ }
+}
+
+KexiTableItem *KexiTableView::highlightedItem() const
+{
+ return d->highlightedRow == -1 ? 0 : m_data->at(d->highlightedRow);
+}
+
+void KexiTableView::slotSettingsChanged(int category)
+{
+ if (category==KApplication::SETTINGS_SHORTCUTS) {
+ d->contextMenuKey = KGlobalSettings::contextMenuKey();
+ }
+}
+
+int KexiTableView::lastVisibleRow() const
+{
+ return rowAt( contentsY() );
+}
+
+#include "kexitableview.moc"
+