/* This file is part of the KDE project Copyright (C) 2002 Till Busch Copyright (C) 2003 Lucijan Busch Copyright (C) 2003 Daniel Molkentin Copyright (C) 2003 Joseph Wenninger Copyright (C) 2003-2006 Jaroslaw Staniek 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 Original Project: buX (www.bux.at) */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef KEXI_NO_PRINT # include #endif #include "kexitableview.h" #include #include #include "kexicelleditorfactory.h" #include "kexitableviewheader.h" #include "kexitableview_p.h" #include #include #include KexiTableView::Appearance::Appearance(TQWidget *widget) : alternateBackgroundColor( TDEGlobalSettings::alternateBackgroundColor() ) { //set defaults if (tqApp) { TQPalette p = widget ? widget->palette() : tqApp->palette(); baseColor = p.active().base(); textColor = p.active().text(); borderColor = TQColor(200,200,200); emptyAreaColor = p.active().color(TQColorGroup::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 TQWhatsThis { public: WhatsThis(KexiTableView* tv) : TQWhatsThis(tv), m_tv(tv) { Q_ASSERT(tv); } virtual ~WhatsThis() { } virtual TQString text( const TQPoint & 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(TQT_TQOBJECT(m_tv->verticalHeader()), TQT_TQOBJECT(m_tv->childAt(pos)))) { return i18n("Contains a pointer to the currently selected row"); } else if (KexiUtils::hasParent(TQT_TQOBJECT(m_tv->m_navPanel), TQT_TQOBJECT(m_tv->childAt(pos)))) { return i18n("Row navigator"); // return TQWhatsThis::textFor(m_tv->m_navPanel, TQPoint( pos.x(), pos.y() - m_tv->height() + bottomMargin )); } KexiDB::Field *f = m_tv->field( m_tv->columnAt(pos.x()-leftMargin) ); if (!f) return TQString(); return f->description().isEmpty() ? f->captionOrName() : f->description(); } protected: KexiTableView *m_tv; }; //----------------------------------------- KexiTableViewCellToolTip::KexiTableViewCellToolTip( KexiTableView * tableView ) : TQToolTip(tableView->viewport()) , m_tableView(tableView) { } KexiTableViewCellToolTip::~KexiTableViewCellToolTip() { remove(parentWidget()); } void KexiTableViewCellToolTip::maybeTip( const TQPoint & p ) { const TQPoint 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 = TQt::SingleLine | TQt::AlignVCenter; TQString txtValue; TQVariant 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 ); TQRect 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) : TQVariant(txtValue), realRect, m_tableView->fontMetrics(), focused)) { TQString squeezedTxtValue; if (txtValue.length() > 50) squeezedTxtValue = txtValue.left(100) + "..."; else squeezedTxtValue = txtValue; tip( realRect, squeezedTxtValue ); } } } } //----------------------------------------- KexiTableView::KexiTableView(KexiTableViewData* data, TQWidget* parent, const char* name) : TQScrollView(parent, name, /*TQt::WRepaintNoErase | */TQt::WStaticContents /*| TQt::WResizeNoErase*/) , KexiRecordNavigatorHandler() , KexiSharedActionClient() , KexiDataAwareObjectInterface() { //not needed KexiTableView::initCellEditorFactories(); d = new KexiTableViewPrivate(this); connect( kapp, TQT_SIGNAL( settingsChanged(int) ), TQT_SLOT( slotSettingsChanged(int) ) ); slotSettingsChanged(TDEApplication::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(TQt::NoBackground); // viewport()->setFocusPolicy(TQ_StrongFocus); viewport()->setFocusPolicy(TQ_WheelFocus); setFocusPolicy(TQ_WheelFocus); //<--- !!!!! important (was NoFocus), // otherwise TQApplication::setActiveWindow() won't activate // this widget when needed! // setFocusProxy(viewport()); viewport()->installEventFilter(this); //setup colors defaults setBackgroundMode(TQt::PaletteBackground); // setEmptyAreaColor(d->appearance.baseColor);//palette().active().color(TQColorGroup::Base)); // d->baseColor = colorGroup().base(); // d->textColor = colorGroup().text(); // d->altColor = TDEGlobalSettings::alternateBackgroundColor(); // d->grayColor = TQColor(200,200,200); d->diagonalGrayPattern = TQBrush(d->appearance.borderColor, TQt::BDiagPattern); setLineWidth(1); horizontalScrollBar()->installEventFilter(this); horizontalScrollBar()->raise(); verticalScrollBar()->raise(); //context menu m_popupMenu = new TDEPopupMenu(this, "contextMenu"); #if 0 //moved to mainwindow's actions d->menu_id_addRecord = m_popupMenu->insertItem(i18n("Add Record"), this, TQT_SLOT(addRecord()), TQt::CTRL+TQt::Key_Insert); d->menu_id_removeRecord = m_popupMenu->insertItem( kapp->iconLoader()->loadIcon("button_cancel", TDEIcon::Small), i18n("Remove Record"), this, TQT_SLOT(removeRecord()), TQt::CTRL+TQt::Key_Delete); #endif #ifdef TQ_WS_WIN d->rowHeight = fontMetrics().lineSpacing() + 4; #else d->rowHeight = fontMetrics().lineSpacing() + 1; #endif if(d->rowHeight < 17) d->rowHeight = 17; d->pUpdateTimer = new TQTimer(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, TQT_SIGNAL(sizeChange(int,int,int)), this, TQT_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( TQMIN(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 TQTimer(this); connect(d->scrollTimer, TQT_SIGNAL(timeout()), this, TQT_SLOT(slotAutoScroll())); #endif // setBackgroundAltering(true); // setFullRowSelectionEnabled(false); setAcceptDrops(true); viewport()->setAcceptDrops(true); // Connect header, table and scrollbars connect(horizontalScrollBar(), TQT_SIGNAL(valueChanged(int)), m_horizontalHeader, TQT_SLOT(setOffset(int))); connect(verticalScrollBar(), TQT_SIGNAL(valueChanged(int)), m_verticalHeader, TQT_SLOT(setOffset(int))); connect(m_horizontalHeader, TQT_SIGNAL(sizeChange(int, int, int)), this, TQT_SLOT(slotColumnWidthChanged(int, int, int))); connect(m_horizontalHeader, TQT_SIGNAL(sectionHandleDoubleClicked(int)), this, TQT_SLOT(slotSectionHandleDoubleClicked(int))); connect(m_horizontalHeader, TQT_SIGNAL(clicked(int)), this, TQT_SLOT(sortColumnInternal(int))); connect(d->pUpdateTimer, TQT_SIGNAL(timeout()), this, TQT_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(TDEActionCollection *ac) { emit reloadActions(ac); }*/ void KexiTableView::setupNavigator() { updateScrollBars(); m_navPanel = new KexiRecordNavigator(this, leftMargin(), "navPanel"); m_navPanel->setRecordHandler(this); m_navPanel->setSizePolicy(TQSizePolicy::Minimum,TQSizePolicy::Preferred); } void KexiTableView::initDataContents() { updateWidgetContentsSize(); KexiDataAwareObjectInterface::initDataContents(); m_navPanel->showEditingIndicator(false); } void KexiTableView::addHeaderColumn(const TQString& caption, const TQString& description, const TQIconSet& 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() { TQSize s(tableSize()); resizeContents(s.width(), s.height()); } void KexiTableView::slotRowsDeleted( const TQValueList &rows ) { viewport()->repaint(); updateWidgetContentsSize(); setCursorPosition(TQMAX(0, (int)m_curRow - (int)rows.count()), -1, true); } /*void KexiTableView::addDropFilter(const TQString &filter) { d->dropFilters.append(filter); viewport()->setAcceptDrops(true); }*/ void KexiTableView::setFont( const TQFont &font ) { TQScrollView::setFont(font); updateFonts(true); } void KexiTableView::updateFonts(bool repaint) { #ifdef TQ_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( TQMIN(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; // TQSize 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() == TQt::Ascending) ? 1 : -1; } void KexiTableView::setLocalSortingOrder(int col, int order) { if (order == 0) col = -1; if (col>=0) m_horizontalHeader->setSortIndicator(col, (order==1) ? TQt::Ascending : TQt::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); } TQSizePolicy KexiTableView::sizePolicy() const { // this widget is expandable return TQSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); } TQSize KexiTableView::sizeHint() const { const TQSize &ts = tableSize(); int w = TQMAX( ts.width() + leftMargin()+ verticalScrollBar()->sizeHint().width() + 2*2, (m_navPanel->isVisible() ? m_navPanel->width() : 0) ); int h = TQMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(), minimumSizeHint().height() ); w = TQMIN( w, tqApp->desktop()->width()*3/4 ); //stretch h = TQMIN( h, tqApp->desktop()->height()*3/4 ); //stretch // kexidbg << "KexiTableView::sizeHint()= " <width() : 0) ), //+ TQMIN(m_verticalHeader->width(),d->rowHeight) + margin()*2, TQMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(), minimumSizeHint().height() ) );*/ // TQMAX(ts.height() + topMargin(), minimumSizeHint().height()) ); } TQSize KexiTableView::minimumSizeHint() const { return TQSize( 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 TQPixmap(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, TQPainter *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, TQRect(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( TQPen(TQt::white, 3) ); pb->drawLine(0, y_line, maxwc, y_line); pb->setRasterOp(op); } } } void KexiTableView::drawContents( TQPainter *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) << TQString(" 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="<pBufferPm->isNull()) return; TQPainter *pb = new TQPainter(d->pBufferPm, this); // pb->fillRect(0, 0, cw, ch, colorGroup().base()); // int maxwc = TQMIN(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 { TQPtrListIterator 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, TQVariant* 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(TQPainter* p, KexiTableItem *item, int col, int row, const TQRect &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="<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 TQPen defaultPen; const bool usesSelectedTextColor = edit && edit->usesSelectedTextColor(); if (defaultValueDisplayed) { if (col == m_curCol && row == m_curRow && usesSelectedTextColor) defaultPen = TQPen(d->defaultValueDisplayParameters.selectedTextColor); else defaultPen = TQPen(d->defaultValueDisplayParameters.textColor); } else if (d->appearance.fullRowSelection && (row == d->highlightedRow || (row == m_curRow && d->highlightedRow==-1)) && usesSelectedTextColor ) { defaultPen = TQPen(d->appearance.rowHighlightingTextColor); //special case: highlighted row } else if (d->appearance.fullRowSelection && row == m_curRow && usesSelectedTextColor) { defaultPen = TQPen(d->appearance.textColor); //special case for full row selection } else if (m_currentItem == item && col == m_curCol && !columnReadOnly && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted && usesSelectedTextColor) { defaultPen = TQPen(colorGroup().highlightedText()); //selected text } else if (d->appearance.rowHighlightingEnabled && row == m_curRow && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted && usesSelectedTextColor) { defaultPen = TQPen(d->appearance.rowHighlightingTextColor); } else if (d->appearance.rowMouseOverHighlightingEnabled && row == d->highlightedRow && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted && usesSelectedTextColor) { defaultPen = TQPen(d->appearance.rowMouseOverHighlightingTextColor); } else defaultPen = TQPen(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() : TQColor(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 ("<field()->isAutoIncrement()) { //"autonumber" column // txt = i18n("(autonumber)"); // autonumber = true; // if (autonumber) { KexiDisplayUtils::paintAutonumberSign(d->autonumberSignDisplayParameters, p, x, y_offset, w - x - x - ((align & TQt::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 & TQt::AlignLeft)?2:0)/*right space*/, h, align, txt); } p->restore(); } TQPoint KexiTableView::contentsToViewport2( const TQPoint &p ) { return TQPoint( p.x() - contentsX(), p.y() - contentsY() ); } void KexiTableView::contentsToViewport2( int x, int y, int& vx, int& vy ) { const TQPoint v = contentsToViewport2( TQPoint( x, y ) ); vx = v.x(); vy = v.y(); } TQPoint KexiTableView::viewportToContents2( const TQPoint& vp ) { return TQPoint( vp.x() + contentsX(), vp.y() + contentsY() ); } void KexiTableView::paintEmptyArea( TQPainter *p, int cx, int cy, int cw, int ch ) { // tqDebug("%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 TQSize ts( tableSize() ); // ts.setWidth( TQMIN( ts.width(), visibleWidth() ) ); // ts.setHeight( TQMIN( ts.height() - (m_navPanel ? m_navPanel->height() : 0), visibleHeight()) ); /* kdDebug(44021) << TQString(" (cx:%1 cy:%2 cw:%3 ch:%4)") .arg(cx).arg(cy).arg(cw).arg(ch) << endl; kdDebug(44021) << TQString(" (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 ); TQRegion reg( TQRect( cx, cy, cw, ch ) ); //kexidbg << "---cy-- " << contentsY() << endl; // Subtract the table from it // reg = reg.subtract( TQRect( TQPoint( 0, 0 ), ts-TQSize(0,m_navPanel->isVisible() ? m_navPanel->height() : 0) ) ); reg = reg.subtract( TQRect( TQPoint( 0, 0 ), ts -TQSize(0,TQMAX((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( TQRect( TQPoint( 0, 0 ), ts ) ); // And draw the rectangles (transformed inc contents coordinates as needed) TQMemArray r = reg.rects(); for ( int i = 0; i < (int)r.count(); i++ ) { TQRect rect( viewportToContents2(r[i].topLeft()), r[i].size() ); /* kdDebug(44021) << TQString("- 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( TQRect(viewportToContents2(r[i].topLeft()),r[i].size()), d->emptyAreaColor ); p->fillRect( rect, d->appearance.emptyAreaColor ); // p->fillRect( TQRect(viewportToContents2(r[i].topLeft()),r[i].size()), viewport()->backgroundBrush() ); } } void KexiTableView::contentsMouseDoubleClickEvent(TQMouseEvent *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, TQString()); } } emit itemDblClicked(m_currentItem, m_curRow, m_curCol); } } void KexiTableView::contentsMousePressEvent( TQMouseEvent* e ) { // kdDebug(44021) << "KexiTableView::contentsMousePressEvent() ??" << endl; setFocus(); if(m_data->count()==0 && !isInsertingEnabled()) { TQScrollView::contentsMousePressEvent( e ); return; } if (columnAt(e->pos().x())==-1) { //outside a colums TQScrollView::contentsMousePressEvent( e ); return; } // d->contentsMousePressEvent_ev = *e; // d->contentsMousePressEvent_enabled = true; // TQTimer::singleShot(2000, this, TQT_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( TQMouseEvent* e ) by now the current items should be set, if not -> error + crash"<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 = TQMAX(d->rowHeight - 5, 12); s = TQMIN( d->rowHeight-3, s ); s = TQMIN( columnWidth(m_curCol)-3, s ); //avoid too large box 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); //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) == TQVariant::StringList && columnEditable(m_curCol)) { createEditor(m_curRow, m_curCol); } #endif } //ScrollView::contentsMousePressEvent( e ); } void KexiTableView::contentsMouseReleaseEvent( TQMouseEvent* 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; TQScrollView::contentsMouseReleaseEvent( e ); emit itemMouseReleased(m_currentItem, m_curRow, m_curCol); } bool KexiTableView::handleContentsMousePressOrRelease(TQMouseEvent* e, bool release) { // remember old focus cell int oldRow = m_curRow; int oldCol = m_curCol; kdDebug(44021) << "oldRow=" << oldRow <<" oldCol=" << oldCol <pos().y())==-1) { newrow = rowAt(e->pos().y() - d->rowHeight); if (newrow==-1 && m_data->count()>0) { if (release) TQScrollView::contentsMouseReleaseEvent( e ); else TQScrollView::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) TQScrollView::contentsMouseReleaseEvent( e ); else TQScrollView::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 TQPoint& _pos) { if (!d->contextMenuEnabled || m_popupMenu->count()<1) return; TQPoint pos(_pos); if (pos==TQPoint(-1,-1)) { pos = viewport()->mapToGlobal( TQPoint( 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( TQMouseEvent *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="<state()==TQt::ShiftButton; if (action_name=="edit_delete_row") return k == TQt::Key_Delete && e->state()==TQt::ControlButton; if (action_name=="edit_delete") return k == TQt::Key_Delete && e->state()==Qt::NoButton; if (action_name=="edit_edititem") return k == TQt::Key_F2 && e->state()==Qt::NoButton; if (action_name=="edit_insert_empty_row") return k == TQt::Key_Insert && e->state()==(TQt::ShiftButton | TQt::ControlButton); return false; } void KexiTableView::keyPressEvent(TQKeyEvent* e) { if (!hasData()) return; // kexidbg << "KexiTableView::keyPressEvent: key=" <key() << " txt=" <text()<key(); const bool ro = isReadOnly(); TQWidget *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 || TQT_BASE_OBJECT(w)!=TQT_BASE_OBJECT(viewport()) && TQT_TQOBJECT(w)!=TQT_TQOBJECT(this) && (!m_editor || !KexiUtils::hasParent(TQT_TQOBJECT(dynamic_cast(m_editor)), TQT_TQOBJECT(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 == TQt::Key_Escape) { cancelEditor(); e->accept(); return; } else if (k == TQt::Key_Return || k == TQt::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!!!" <state()==Qt::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 TQt::Key_Delete: if (e->state()==TQt::ControlButton) {//remove current row deleteCurrentRow(); } else if (nobtn) {//remove contents of the current cell deleteAndStartEditCurrentCell(); } break;*/ // bool _return; if (k == TQt::Key_Shift || k == TQt::Key_Alt || k == TQt::Key_Control || k == TQt::Key_Meta) { e->ignore(); } else if (KexiDataAwareObjectInterface::handleKeyPress(e, curRow, curCol, d->appearance.fullRowSelection)) { if (e->isAccepted()) return; } else if (k == TQt::Key_Backspace && nobtn) { if (!ro && columnType(curCol) != KexiDB::Field::Boolean && columnEditable(curCol)) createEditor(curRow, curCol, TQString(), true); } else if (k == TQt::Key_Space) { if (nobtn && !ro && columnEditable(curCol)) { if (columnType(curCol) == KexiDB::Field::Boolean) { boolToggled(); } else printable = true; //just space key } } else if (k == TQt::Key_Escape) { if (nobtn && m_rowEditing) { cancelRowEdit(); return; } } else { //others: if (nobtn && (k==TQt::Key_Tab || k==TQt::Key_Right)) { //! \todo add option for stopping at 1st column for TQt::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()==TQt::ShiftButton && k==TQt::Key_Tab) || (nobtn && k==TQt::Key_Backtab) || (e->state()==TQt::ShiftButton && k==TQt::Key_Backtab) || (nobtn && k==TQt::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) { //TQt::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==TQt::Key_Enter || k==TQt::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" << TQString("%1").arg(k,0,16) <ignore(); TQScrollView::keyPressEvent(e); return; } printable = true; } } } //finally: we've printable char: if (printable && !ro) { KexiTableViewColumn *tvcol = m_data->column(curCol); if (tvcol->acceptsFirstChar(TQString(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,TQT_SIGNAL(editRequested()),this,TQT_SLOT(slotEditRequested())); connect(editor,TQT_SIGNAL(cancelRequested()),this,TQT_SLOT(cancelEditor())); connect(editor,TQT_SIGNAL(acceptRequested()),this,TQT_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; TQRect 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 TQString& addText, bool removeOld) { kdDebug(44021) << "KexiTableView::createEditor('"<column(col)->isReadOnly()) {//d->pColumnModes.at(d->numCols-1) & ColumnReadOnly) kdDebug(44021) << "KexiTableView::createEditor(): COL IS READ ONLY!"<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.): tqApp->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(TQFocusEvent* e) { Q_UNUSED(e); updateCell(m_curRow, m_curCol); } void KexiTableView::focusOutEvent(TQFocusEvent* e) { KexiDataAwareObjectInterface::focusOutEvent(e); } bool KexiTableView::focusNextPrevChild(bool /*next*/) { return false; //special Tab/BackTab meaning /* if (m_editor) return true; return TQScrollView::focusNextPrevChild(next);*/ } void KexiTableView::resizeEvent(TQResizeEvent *e) { TQScrollView::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( TQResizeEvent *e ) { TQScrollView::viewportResizeEvent( e ); updateGeometries(); // erase(); repaint(); } void KexiTableView::showEvent(TQShowEvent *e) { TQScrollView::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 TQSize s(tableSize()); // TQRect 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!=TQPoint(-1,-1)) { ensureCellVisible( d->ensureCellVisibleOnShow.x(), d->ensureCellVisibleOnShow.y() ); d->ensureCellVisibleOnShow = TQPoint(-1,-1); //reset the flag } if (m_navPanel) m_navPanel->updateGeometry(leftMargin()); // updateNavPanelGeometry(); } void KexiTableView::contentsDragMoveEvent(TQDragMoveEvent *e) { if (!hasData()) return; if (m_dropsAtRowEnabled) { TQPoint 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); /* TQStringList::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(TQDropEvent *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); } TQPoint 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( TQDragLeaveEvent *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("<= (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 << TQRect( columnPos( leftcol ), rowPos(row), clipper()->width(), rowHeight() ) << endl; // updateContents( TQRect( columnPos( leftcol ), rowPos(row), clipper()->width(), rowHeight() ) ); //columnPos(rightcol)+columnWidth(rightcol), rowHeight() ) ); updateContents( TQRect( contentsX(), rowPos(row), clipper()->width(), rowHeight() ) ); //columnPos(rightcol)+columnWidth(rightcol), rowHeight() ) ); } void KexiTableView::slotColumnWidthChanged( int, int, int ) { TQSize 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()); TQWidget *editorWidget = dynamic_cast(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() { TQSize 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 = TQMIN(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("<rowHeight; if (pos < 0) return 0; if ((pos >= (int)m_data->count()) && !ignoreEnd) return -1; return pos; } TQRect KexiTableView::cellGeometry(int row, int col) const { return TQRect(columnPos(col), rowPos(row), columnWidth(col), rowHeight()); } TQSize 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 // + TQMAX(m_navPanel ? m_navPanel->height() : 0, horizontalScrollBar()->sizeHint().height()) + (m_navPanel->isVisible() ? TQMAX( m_navPanel->height(), horizontalScrollBar()->sizeHint().height() ) :0 ) + margin() << endl; */ // kexidbg<< m_navPanel->isVisible() <<" "<height()<<" " // <sizeHint().height()<<" "<sizeHint().height()/2; TQSize 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) // + TQMAX( (m_navPanel && m_navPanel->isVisible()) ? m_navPanel->height() : 0, // horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height() : 0) // + (m_navPanel->isVisible() // ? TQMAX( 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 TQSize(0,0); } void KexiTableView::ensureCellVisible(int row, int col/*=-1*/) { if (!isVisible()) { //the table is invisible: we can't ensure visibility now d->ensureCellVisibleOnShow = TQPoint(row,col); return; } //quite clever: ensure the cell is visible: TQRect 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()); } TQPoint 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(TQVariant& cellValue, KexiTableEdit *edit, KexiTableItem *item, KexiTableViewColumn *tvcol) const { if (edit->columnInfo() && edit->columnInfo()->indexForVisibleLookupValue()!=-1 && edit->columnInfo()->indexForVisibleLookupValue() < (int)item->count()) { const TQVariant *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()" <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; TQPainter p(&printer); KexiTableItem *i; int width = leftMargin; for(int col=0; col < columns(); col++) { p.fillRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, TQBrush(TQt::gray)); p.drawRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight); p.drawText(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, TQt::AlignLeft | TQt::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, TQRect(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 TQString 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; icolumn(colNum) && m_data->column(colNum)->columnInfo) ? m_data->column(colNum)->columnInfo->indexForVisibleLookupValue() : -1; if (-1==indexOfVisibleColumn) indexOfVisibleColumn = colNum; if (indexOfVisibleColumn < 0) return; TQPtrListIterator it = m_data->iterator(); if (it.current() && it.current()->count()<=(uint)indexOfVisibleColumn) return; KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item( columnType(indexOfVisibleColumn) ); if (!item) return; TQFontMetrics 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 = TQMAX( 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 TQValueList &columnList ) { if (!isVisible()) { d->maximizeColumnsWidthOnShow += columnList; return; } if (width() <= m_horizontalHeader->headerWidth()) return; //sort the list and make it unique TQValueList cl, sortedList = columnList; qHeapSort(sortedList); int i=-999; TQValueList::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 = TQMIN(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( TQScrollBar & hbar, int x, int y, int w, int h ) { /*todo*/ kdDebug(44021)<<"KexiTableView::setHBarGeometry"<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 TQString& 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 ); TQVariant defaultValue; const bool defaultValueDisplayed = isDefaultValueDisplayed(m_currentItem, m_curCol, &defaultValue); if (edit) { TQVariant 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( TQObject *o, TQEvent *e ) { //don't allow to stole key my events by others: // kexidbg << "spontaneous " << e->spontaneous() << " type=" << e->type() << endl; if (e->type()==TQEvent::KeyPress) { if (e->spontaneous() /*|| e->type()==TQEvent::AccelOverride*/) { TQKeyEvent *ke = TQT_TQKEYEVENT(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(m_editor) || TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(m_editor->widget()))) { if ( (k==TQt::Key_Tab && (s==Qt::NoButton || s==TQt::ShiftButton)) || (overrideEditorShortcutNeeded(ke)) || (k==TQt::Key_Enter || k==TQt::Key_Return || k==TQt::Key_Up || k==TQt::Key_Down) || (k==TQt::Key_Left && m_editor->cursorAtStart()) || (k==TQt::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()==TQEvent::KeyPress && (o==this || (m_editor && o==m_editor->widget()))){//|| o==viewport()) keyPressEvent(ke); if (ke->isAccepted()) return true; }*/ /*todo else if ((k==TQt::Key_Tab || k==(TQt::SHIFT|TQt::Key_Tab)) && o==d->navRowNumber) { //tab key focuses tv ke->accept(); setFocus(); return true; }*/ } } else if (TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(horizontalScrollBar())) { if ((e->type()==TQEvent::Show && !horizontalScrollBar()->isVisible()) || (e->type()==TQEvent::Hide && horizontalScrollBar()->isVisible())) { updateWidgetContentsSize(); } } else if (e->type()==TQEvent::Leave) { if (TQT_BASE_OBJECT(o)==TQT_BASE_OBJECT(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 = TQPoint(-1,-1); } /* else if (e->type()==TQEvent::FocusOut && o->inherits(TQWIDGET_OBJECT_NAME_STRING)) { //hp==true if currently focused widget is a child of this table view const bool hp = KexiUtils::hasParent( static_cast(o), focusWidget()); if (!hp && KexiUtils::hasParent( this, static_cast(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(o)->setFocus(); return true; } } }*/ return TQScrollView::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 TQPalette &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( TQMIN(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 = TQMIN(rows() - 1 + (isInsertingEnabled()?1:0), row); row = TQMAX(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==TDEApplication::SETTINGS_SHORTCUTS) { d->contextMenuKey = TDEGlobalSettings::contextMenuKey(); } } int KexiTableView::lastVisibleRow() const { return rowAt( contentsY() ); } #include "kexitableview.moc"