00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include <qpainter.h>
00028 #include <qkeycode.h>
00029 #include <qlineedit.h>
00030 #include <qcombobox.h>
00031 #include <qwmatrix.h>
00032 #include <qtimer.h>
00033 #include <qpopupmenu.h>
00034 #include <qcursor.h>
00035 #include <qstyle.h>
00036 #include <qlayout.h>
00037 #include <qlabel.h>
00038 #include <qwhatsthis.h>
00039
00040 #include <kglobal.h>
00041 #include <klocale.h>
00042 #include <kdebug.h>
00043 #include <kapplication.h>
00044 #include <kiconloader.h>
00045 #include <kmessagebox.h>
00046
00047 #ifndef KEXI_NO_PRINT
00048 # include <kprinter.h>
00049 #endif
00050
00051 #include "kexitableview.h"
00052 #include <kexiutils/utils.h>
00053 #include <kexiutils/validator.h>
00054
00055 #include "kexicelleditorfactory.h"
00056 #include "kexitableviewheader.h"
00057 #include "kexitableview_p.h"
00058 #include <widget/utils/kexirecordmarker.h>
00059 #include <widget/utils/kexidisplayutils.h>
00060 #include <kexidb/cursor.h>
00061
00062 KexiTableView::Appearance::Appearance(QWidget *widget)
00063 : alternateBackgroundColor( KGlobalSettings::alternateBackgroundColor() )
00064 {
00065
00066 if (qApp) {
00067 QPalette p = widget ? widget->palette() : qApp->palette();
00068 baseColor = p.active().base();
00069 textColor = p.active().text();
00070 borderColor = QColor(200,200,200);
00071 emptyAreaColor = p.active().color(QColorGroup::Base);
00072 rowHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), baseColor, 33, 66);
00073 rowMouseOverHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), baseColor, 10, 90);
00074 rowMouseOverAlternateHighlightingColor = KexiUtils::blendedColors(p.active().highlight(), alternateBackgroundColor, 10, 90);
00075 rowHighlightingTextColor = textColor;
00076 rowMouseOverHighlightingTextColor = textColor;
00077 }
00078 backgroundAltering = true;
00079 rowMouseOverHighlightingEnabled = true;
00080 rowHighlightingEnabled = true;
00081 persistentSelections = true;
00082 navigatorEnabled = true;
00083 fullRowSelection = false;
00084 gridEnabled = true;
00085 }
00086
00087
00088
00090 class KexiTableView::WhatsThis : public QWhatsThis
00091 {
00092 public:
00093 WhatsThis(KexiTableView* tv) : QWhatsThis(tv), m_tv(tv)
00094 {
00095 Q_ASSERT(tv);
00096 }
00097 virtual ~WhatsThis()
00098 {
00099 }
00100 virtual QString text( const QPoint & pos)
00101 {
00102 const int leftMargin = m_tv->verticalHeaderVisible() ? m_tv->verticalHeader()->width() : 0;
00103
00104
00105 if (KexiUtils::hasParent(m_tv->verticalHeader(), m_tv->childAt(pos))) {
00106 return i18n("Contains a pointer to the currently selected row");
00107 }
00108 else if (KexiUtils::hasParent(m_tv->m_navPanel, m_tv->childAt(pos))) {
00109 return i18n("Row navigator");
00110
00111 }
00112 KexiDB::Field *f = m_tv->field( m_tv->columnAt(pos.x()-leftMargin) );
00113 if (!f)
00114 return QString::null;
00115 return f->description().isEmpty() ? f->captionOrName() : f->description();
00116 }
00117 protected:
00118 KexiTableView *m_tv;
00119 };
00120
00121
00122
00123 KexiTableViewCellToolTip::KexiTableViewCellToolTip( KexiTableView * tableView )
00124 : QToolTip(tableView->viewport())
00125 , m_tableView(tableView)
00126 {
00127 }
00128
00129 KexiTableViewCellToolTip::~KexiTableViewCellToolTip()
00130 {
00131 remove(parentWidget());
00132 }
00133
00134 void KexiTableViewCellToolTip::maybeTip( const QPoint & p )
00135 {
00136 const QPoint cp( m_tableView->viewportToContents( p ) );
00137 const int row = m_tableView->rowAt( cp.y(), true );
00138 const int col = m_tableView->columnAt( cp.x() );
00139
00140
00141 if (col>=0 && row>=0) {
00142 KexiTableEdit *editor = m_tableView->tableEditorWidget( col );
00143 const bool insertRowSelected = m_tableView->isInsertingEnabled() && row==m_tableView->rows();
00144 KexiTableItem *item = insertRowSelected ? m_tableView->m_insertItem : m_tableView->itemAt( row );
00145 if (editor && item && (col < (int)item->count())) {
00146 int w = m_tableView->columnWidth( col );
00147 int h = m_tableView->rowHeight();
00148 int x = 0;
00149 int y_offset = 0;
00150 int align = Qt::SingleLine | Qt::AlignVCenter;
00151 QString txtValue;
00152 QVariant cellValue;
00153 KexiTableViewColumn *tvcol = m_tableView->column(col);
00154 if (!m_tableView->getVisibleLookupValue(cellValue, editor, item, tvcol))
00155 cellValue = insertRowSelected ? editor->displayedField()->defaultValue() : item->at(col);
00156 const bool focused = m_tableView->selectedItem() == item && col == m_tableView->currentColumn();
00157 editor->setupContents( 0, focused, cellValue, txtValue, align, x, y_offset, w, h );
00158 QRect realRect(m_tableView->columnPos(col)-m_tableView->contentsX(),
00159 m_tableView->rowPos(row)-m_tableView->contentsY(), w, h);
00160 if (editor->showToolTipIfNeeded(
00161 txtValue.isEmpty() ? item->at(col) : QVariant(txtValue),
00162 realRect, m_tableView->fontMetrics(), focused))
00163 {
00164 QString squeezedTxtValue;
00165 if (txtValue.length() > 50)
00166 squeezedTxtValue = txtValue.left(100) + "...";
00167 else
00168 squeezedTxtValue = txtValue;
00169 tip( realRect, squeezedTxtValue );
00170 }
00171 }
00172 }
00173 }
00174
00175
00176
00177 KexiTableView::KexiTableView(KexiTableViewData* data, QWidget* parent, const char* name)
00178 : QScrollView(parent, name, Qt::WStaticContents )
00179 , KexiRecordNavigatorHandler()
00180 , KexiSharedActionClient()
00181 , KexiDataAwareObjectInterface()
00182 {
00183
00184
00185 d = new KexiTableViewPrivate(this);
00186
00187 connect( kapp, SIGNAL( settingsChanged(int) ), SLOT( slotSettingsChanged(int) ) );
00188 slotSettingsChanged(KApplication::SETTINGS_SHORTCUTS);
00189
00190 m_data = new KexiTableViewData();
00191 m_owner = true;
00192
00193 setResizePolicy(Manual);
00194 viewport()->setBackgroundMode(Qt::NoBackground);
00195
00196 viewport()->setFocusPolicy(WheelFocus);
00197 setFocusPolicy(WheelFocus);
00198
00199
00200
00201 viewport()->installEventFilter(this);
00202
00203
00204 setBackgroundMode(Qt::PaletteBackground);
00205
00206
00207
00208
00209
00210
00211
00212 d->diagonalGrayPattern = QBrush(d->appearance.borderColor, Qt::BDiagPattern);
00213
00214 setLineWidth(1);
00215 horizontalScrollBar()->installEventFilter(this);
00216 horizontalScrollBar()->raise();
00217 verticalScrollBar()->raise();
00218
00219
00220 m_popupMenu = new KPopupMenu(this, "contextMenu");
00221 #if 0 //moved to mainwindow's actions
00222 d->menu_id_addRecord = m_popupMenu->insertItem(i18n("Add Record"), this, SLOT(addRecord()), Qt::CTRL+Qt::Key_Insert);
00223 d->menu_id_removeRecord = m_popupMenu->insertItem(
00224 kapp->iconLoader()->loadIcon("button_cancel", KIcon::Small),
00225 i18n("Remove Record"), this, SLOT(removeRecord()), Qt::CTRL+Qt::Key_Delete);
00226 #endif
00227
00228 #ifdef Q_WS_WIN
00229 d->rowHeight = fontMetrics().lineSpacing() + 4;
00230 #else
00231 d->rowHeight = fontMetrics().lineSpacing() + 1;
00232 #endif
00233
00234 if(d->rowHeight < 17)
00235 d->rowHeight = 17;
00236
00237 d->pUpdateTimer = new QTimer(this);
00238
00239
00240
00241
00242 m_horizontalHeader = new KexiTableViewHeader(this, "topHeader");
00243 m_horizontalHeader->setSelectionBackgroundColor( palette().active().highlight() );
00244 m_horizontalHeader->setOrientation(Qt::Horizontal);
00245 m_horizontalHeader->setTracking(false);
00246 m_horizontalHeader->setMovingEnabled(false);
00247 connect(m_horizontalHeader, SIGNAL(sizeChange(int,int,int)), this, SLOT(slotTopHeaderSizeChange(int,int,int)));
00248
00249 m_verticalHeader = new KexiRecordMarker(this, "rm");
00250 m_verticalHeader->setSelectionBackgroundColor( palette().active().highlight() );
00251 m_verticalHeader->setCellHeight(d->rowHeight);
00252
00253 m_verticalHeader->setCurrentRow(-1);
00254
00255 setMargins(
00256 QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
00257 m_horizontalHeader->sizeHint().height(), 0, 0);
00258
00259 setupNavigator();
00260
00261
00262
00263
00264
00265
00266 if (data)
00267 setData( data );
00268
00269 #if 0//(js) doesn't work!
00270 d->scrollTimer = new QTimer(this);
00271 connect(d->scrollTimer, SIGNAL(timeout()), this, SLOT(slotAutoScroll()));
00272 #endif
00273
00274
00275
00276
00277 setAcceptDrops(true);
00278 viewport()->setAcceptDrops(true);
00279
00280
00281 connect(horizontalScrollBar(), SIGNAL(valueChanged(int)), m_horizontalHeader, SLOT(setOffset(int)));
00282 connect(verticalScrollBar(), SIGNAL(valueChanged(int)), m_verticalHeader, SLOT(setOffset(int)));
00283 connect(m_horizontalHeader, SIGNAL(sizeChange(int, int, int)), this, SLOT(slotColumnWidthChanged(int, int, int)));
00284 connect(m_horizontalHeader, SIGNAL(sectionHandleDoubleClicked(int)), this, SLOT(slotSectionHandleDoubleClicked(int)));
00285 connect(m_horizontalHeader, SIGNAL(clicked(int)), this, SLOT(sortColumnInternal(int)));
00286
00287 connect(d->pUpdateTimer, SIGNAL(timeout()), this, SLOT(slotUpdate()));
00288
00289
00290 updateScrollBars();
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300 setAppearance(d->appearance);
00301
00302 d->cellToolTip = new KexiTableViewCellToolTip(this);
00303 new WhatsThis(this);
00304 }
00305
00306 KexiTableView::~KexiTableView()
00307 {
00308 cancelRowEdit();
00309
00310 KexiTableViewData *data = m_data;
00311 m_data = 0;
00312 if (m_owner) {
00313 if (data)
00314 data->deleteLater();
00315 }
00316 delete d;
00317 }
00318
00319 void KexiTableView::clearVariables()
00320 {
00321 KexiDataAwareObjectInterface::clearVariables();
00322 d->clearVariables();
00323 }
00324
00325
00326
00327
00328
00329
00330 void KexiTableView::setupNavigator()
00331 {
00332 updateScrollBars();
00333
00334 m_navPanel = new KexiRecordNavigator(this, leftMargin(), "navPanel");
00335 m_navPanel->setRecordHandler(this);
00336 m_navPanel->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Preferred);
00337 }
00338
00339 void KexiTableView::initDataContents()
00340 {
00341 updateWidgetContentsSize();
00342
00343 KexiDataAwareObjectInterface::initDataContents();
00344
00345 m_navPanel->showEditingIndicator(false);
00346 }
00347
00348 void KexiTableView::addHeaderColumn(const QString& caption, const QString& description,
00349 const QIconSet& icon, int width)
00350 {
00351 const int nr = m_horizontalHeader->count();
00352 if (icon.isNull())
00353 m_horizontalHeader->addLabel(caption, width);
00354 else
00355 m_horizontalHeader->addLabel(icon, caption, width);
00356
00357 if (!description.isEmpty())
00358 m_horizontalHeader->setToolTip(nr, description);
00359 }
00360
00361 void KexiTableView::updateWidgetContentsSize()
00362 {
00363 QSize s(tableSize());
00364 resizeContents(s.width(), s.height());
00365 }
00366
00367 void KexiTableView::slotRowsDeleted( const QValueList<int> &rows )
00368 {
00369 viewport()->repaint();
00370 updateWidgetContentsSize();
00371 setCursorPosition(QMAX(0, (int)m_curRow - (int)rows.count()), -1, true);
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381 void KexiTableView::setFont( const QFont &font )
00382 {
00383 QScrollView::setFont(font);
00384 updateFonts(true);
00385 }
00386
00387 void KexiTableView::updateFonts(bool repaint)
00388 {
00389 #ifdef Q_WS_WIN
00390 d->rowHeight = fontMetrics().lineSpacing() + 4;
00391 #else
00392 d->rowHeight = fontMetrics().lineSpacing() + 1;
00393 #endif
00394 if (d->appearance.fullRowSelection) {
00395 d->rowHeight -= 1;
00396 }
00397 if(d->rowHeight < 17)
00398 d->rowHeight = 17;
00399
00400
00401 setMargins(
00402 QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
00403 m_horizontalHeader->sizeHint().height(), 0, 0);
00404
00405 m_verticalHeader->setCellHeight(d->rowHeight);
00406
00407 KexiDisplayUtils::initDisplayForAutonumberSign(d->autonumberSignDisplayParameters, this);
00408 KexiDisplayUtils::initDisplayForDefaultValue(d->defaultValueDisplayParameters, this);
00409
00410 if (repaint)
00411 updateContents();
00412 }
00413
00414 void KexiTableView::updateAllVisibleRowsBelow(int row)
00415 {
00416
00417 int r = rowAt(clipper()->height()+contentsY());
00418 if (r==-1) {
00419 r = rows()+1+(isInsertingEnabled()?1:0);
00420 }
00421
00422 int leftcol = m_horizontalHeader->sectionAt( m_horizontalHeader->offset() );
00423
00424 updateContents( columnPos( leftcol ), rowPos(row),
00425 clipper()->width(), clipper()->height() - (rowPos(row) - contentsY()) );
00426 }
00427
00428 void KexiTableView::clearColumnsInternal(bool )
00429 {
00430 while(m_horizontalHeader->count()>0)
00431 m_horizontalHeader->removeLabel(0);
00432 }
00433
00434 void KexiTableView::slotUpdate()
00435 {
00436
00437
00438
00440
00441
00442 updateContents();
00443 updateScrollBars();
00444 if (m_navPanel)
00445 m_navPanel->updateGeometry(leftMargin());
00446
00447
00448 updateWidgetContentsSize();
00449
00450
00451
00452
00453
00454 }
00455
00456 int KexiTableView::currentLocalSortingOrder() const
00457 {
00458 if (m_horizontalHeader->sortIndicatorSection()==-1)
00459 return 0;
00460 return (m_horizontalHeader->sortIndicatorOrder() == Qt::Ascending) ? 1 : -1;
00461 }
00462
00463 void KexiTableView::setLocalSortingOrder(int col, int order)
00464 {
00465 if (order == 0)
00466 col = -1;
00467 if (col>=0)
00468 m_horizontalHeader->setSortIndicator(col, (order==1) ? Qt::Ascending : Qt::Descending);
00469 }
00470
00471 int KexiTableView::currentLocalSortColumn() const
00472 {
00473 return m_horizontalHeader->sortIndicatorSection();
00474 }
00475
00476 void KexiTableView::updateGUIAfterSorting()
00477 {
00478 int cw = columnWidth(m_curCol);
00479 int rh = rowHeight();
00480
00481
00482 center(columnPos(m_curCol) + cw / 2, rowPos(m_curRow) + rh / 2);
00483
00484
00485
00486
00487 updateContents();
00488
00489 }
00490
00491 QSizePolicy KexiTableView::sizePolicy() const
00492 {
00493
00494 return QSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
00495 }
00496
00497 QSize KexiTableView::sizeHint() const
00498 {
00499 const QSize &ts = tableSize();
00500 int w = QMAX( ts.width() + leftMargin()+ verticalScrollBar()->sizeHint().width() + 2*2,
00501 (m_navPanel->isVisible() ? m_navPanel->width() : 0) );
00502 int h = QMAX( ts.height()+topMargin()+horizontalScrollBar()->sizeHint().height(),
00503 minimumSizeHint().height() );
00504 w = QMIN( w, qApp->desktop()->width()*3/4 );
00505 h = QMIN( h, qApp->desktop()->height()*3/4 );
00506
00507
00508
00509 return QSize(w, h);
00510
00511
00512
00513
00514
00515
00516
00517 }
00518
00519 QSize KexiTableView::minimumSizeHint() const
00520 {
00521 return QSize(
00522 leftMargin() + ((columns()>0)?columnWidth(0):KEXI_DEFAULT_DATA_COLUMN_WIDTH) + 2*2,
00523 d->rowHeight*5/2 + topMargin() + (m_navPanel && m_navPanel->isVisible() ? m_navPanel->height() : 0)
00524 );
00525 }
00526
00527 void KexiTableView::createBuffer(int width, int height)
00528 {
00529 if(!d->pBufferPm)
00530 d->pBufferPm = new QPixmap(width, height);
00531 else
00532 if(d->pBufferPm->width() < width || d->pBufferPm->height() < height)
00533 d->pBufferPm->resize(width, height);
00534
00535 }
00536
00537
00538 inline void KexiTableView::paintRow(KexiTableItem *item,
00539 QPainter *pb, int r, int rowp, int cx, int cy,
00540 int colfirst, int collast, int maxwc)
00541 {
00542 if (!item)
00543 return;
00544
00545
00546
00547 if (colfirst==-1)
00548 colfirst=0;
00549 if (collast==-1)
00550 collast=columns()-1;
00551
00552 int transly = rowp-cy;
00553
00554 if (d->appearance.rowHighlightingEnabled && r == m_curRow && !d->appearance.fullRowSelection) {
00555 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowHighlightingColor);
00556 }
00557 else if (d->appearance.rowMouseOverHighlightingEnabled && r == d->highlightedRow) {
00558 if(d->appearance.backgroundAltering && (r%2 != 0))
00559 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowMouseOverAlternateHighlightingColor);
00560 else
00561 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.rowMouseOverHighlightingColor);
00562 }
00563 else {
00564 if(d->appearance.backgroundAltering && (r%2 != 0))
00565 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.alternateBackgroundColor);
00566 else
00567 pb->fillRect(0, transly, maxwc, d->rowHeight, d->appearance.baseColor);
00568 }
00569
00570 for(int c = colfirst; c <= collast; c++)
00571 {
00572
00573 int colp = columnPos(c);
00574 if (colp==-1)
00575 continue;
00576 int colw = columnWidth(c);
00577 int translx = colp-cx;
00578
00579
00580 pb->saveWorldMatrix();
00581 pb->translate(translx, transly);
00582 paintCell( pb, item, c, r, QRect(colp, rowp, colw, d->rowHeight));
00583 pb->restoreWorldMatrix();
00584 }
00585
00586 if (m_dragIndicatorLine>=0) {
00587 int y_line = -1;
00588 if (r==(rows()-1) && m_dragIndicatorLine==rows()) {
00589 y_line = transly+d->rowHeight-3;
00590 }
00591 if (m_dragIndicatorLine==r) {
00592 y_line = transly+1;
00593 }
00594 if (y_line>=0) {
00595 RasterOp op = pb->rasterOp();
00596 pb->setRasterOp(XorROP);
00597 pb->setPen( QPen(Qt::white, 3) );
00598 pb->drawLine(0, y_line, maxwc, y_line);
00599 pb->setRasterOp(op);
00600 }
00601 }
00602 }
00603
00604 void KexiTableView::drawContents( QPainter *p, int cx, int cy, int cw, int ch)
00605 {
00606 if (d->disableDrawContents)
00607 return;
00608 int colfirst = columnAt(cx);
00609 int rowfirst = rowAt(cy);
00610 int collast = columnAt(cx + cw-1);
00611 int rowlast = rowAt(cy + ch-1);
00612 bool inserting = isInsertingEnabled();
00613 bool plus1row = false;
00614 bool paintOnlyInsertRow = false;
00615
00616
00617
00618
00619 if (rowlast == -1) {
00620 rowlast = rows() - 1;
00621 plus1row = inserting;
00622 if (rowfirst == -1) {
00623 if (rowAt(cy - d->rowHeight) != -1) {
00624 paintOnlyInsertRow = true;
00625
00626 }
00627 }
00628 }
00629
00630
00631
00632 if ( collast == -1 )
00633 collast = columns() - 1;
00634
00635 if (colfirst>collast) {
00636 int tmp = colfirst;
00637 colfirst = collast;
00638 collast = tmp;
00639 }
00640 if (rowfirst>rowlast) {
00641 int tmp = rowfirst;
00642 rowfirst = rowlast;
00643 rowlast = tmp;
00644 }
00645
00646
00647
00648
00649
00650 if (rowfirst == -1 || colfirst == -1) {
00651 if (!paintOnlyInsertRow && !plus1row) {
00652 paintEmptyArea(p, cx, cy, cw, ch);
00653 return;
00654 }
00655 }
00656
00657 createBuffer(cw, ch);
00658 if(d->pBufferPm->isNull())
00659 return;
00660 QPainter *pb = new QPainter(d->pBufferPm, this);
00661
00662
00663
00664 int maxwc = columnPos(columns() - 1) + columnWidth(columns() - 1);
00665
00666
00667 pb->fillRect(cx, cy, cw, ch, d->appearance.baseColor);
00668
00669 int rowp;
00670 int r;
00671 if (paintOnlyInsertRow) {
00672 r = rows();
00673 rowp = rowPos(r);
00674 }
00675 else {
00676 QPtrListIterator<KexiTableItem> it = m_data->iterator();
00677 it += rowfirst;
00678 rowp = rowPos(rowfirst);
00679 for (r = rowfirst;r <= rowlast; r++, ++it, rowp+=d->rowHeight) {
00680 paintRow(it.current(), pb, r, rowp, cx, cy, colfirst, collast, maxwc);
00681 }
00682 }
00683
00684 if (plus1row) {
00685 paintRow(m_insertItem, pb, r, rowp, cx, cy, colfirst, collast, maxwc);
00686 }
00687
00688 delete pb;
00689
00690 p->drawPixmap(cx,cy,*d->pBufferPm, 0,0,cw,ch);
00691
00692
00693 paintEmptyArea(p, cx, cy, cw, ch);
00694 }
00695
00696 bool KexiTableView::isDefaultValueDisplayed(KexiTableItem *item, int col, QVariant* value)
00697 {
00698 const bool cursorAtInsertRowOrEditingNewRow = (item == m_insertItem || (m_newRowEditing && m_currentItem == item));
00699 KexiTableViewColumn *tvcol;
00700 if (cursorAtInsertRowOrEditingNewRow
00701 && (tvcol = m_data->column(col))
00702 && hasDefaultValueAt(*tvcol)
00703 && !tvcol->field()->isAutoIncrement())
00704 {
00705 if (value)
00706 *value = tvcol->field()->defaultValue();
00707 return true;
00708 }
00709 return false;
00710 }
00711
00712 void KexiTableView::paintCell(QPainter* p, KexiTableItem *item, int col, int row, const QRect &cr, bool print)
00713 {
00714 p->save();
00715 Q_UNUSED(print);
00716 int w = cr.width();
00717 int h = cr.height();
00718 int x2 = w - 1;
00719 int y2 = h - 1;
00720
00721
00722
00723
00724
00725
00726 QPen pen(p->pen());
00727
00728 if (d->appearance.gridEnabled) {
00729 p->setPen(d->appearance.borderColor);
00730 p->drawLine( x2, 0, x2, y2 );
00731 p->drawLine( 0, y2, x2, y2 );
00732 }
00733 p->setPen(pen);
00734
00735 if (m_editor && row == m_curRow && col == m_curCol
00736 && m_editor->hasFocusableWidget()
00737 ) {
00738 p->restore();
00739 return;
00740 }
00741
00742 KexiTableEdit *edit = tableEditorWidget( col, true );
00743
00744
00745
00746 int x = edit ? edit->leftMargin() : 0;
00747 int y_offset=0;
00748
00749 int align = Qt::SingleLine | Qt::AlignVCenter;
00750 QString txt;
00751
00752 KexiTableViewColumn *tvcol = m_data->column(col);
00753
00754 QVariant cellValue;
00755 if (col < (int)item->count()) {
00756 if (m_currentItem == item) {
00757 if (m_editor && row == m_curRow && col == m_curCol
00758 && !m_editor->hasFocusableWidget())
00759 {
00760
00761
00762
00763 cellValue = m_editor->value();
00764 }
00765 else {
00766
00767
00768 cellValue = *bufferedValueAt(col);
00769 }
00770 }
00771 else {
00772 cellValue = item->at(col);
00773 }
00774 }
00775
00776 bool defaultValueDisplayed = isDefaultValueDisplayed(item, col);
00777
00778 if ((item == m_insertItem ) && cellValue.isNull()) {
00779 if (!tvcol->field()->isAutoIncrement() && !tvcol->field()->defaultValue().isNull()) {
00780
00781
00782 cellValue = tvcol->field()->defaultValue();
00783 defaultValueDisplayed = true;
00784 }
00785 }
00786
00787 const bool columnReadOnly = tvcol->isReadOnly();
00788 const bool dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
00789 = d->appearance.rowHighlightingEnabled && !d->appearance.persistentSelections
00790 && m_curRow >= 0 && row != m_curRow;
00791
00792
00793 QPen defaultPen;
00794 const bool usesSelectedTextColor = edit && edit->usesSelectedTextColor();
00795 if (defaultValueDisplayed) {
00796 if (col == m_curCol && row == m_curRow && usesSelectedTextColor)
00797 defaultPen = d->defaultValueDisplayParameters.selectedTextColor;
00798 else
00799 defaultPen = d->defaultValueDisplayParameters.textColor;
00800 }
00801 else if (d->appearance.fullRowSelection
00802 && (row == d->highlightedRow || (row == m_curRow && d->highlightedRow==-1))
00803 && usesSelectedTextColor )
00804 {
00805 defaultPen = d->appearance.rowHighlightingTextColor;
00806 }
00807 else if (d->appearance.fullRowSelection && row == m_curRow && usesSelectedTextColor)
00808 {
00809 defaultPen = d->appearance.textColor;
00810 }
00811 else if (m_currentItem == item && col == m_curCol && !columnReadOnly
00812 && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
00813 && usesSelectedTextColor)
00814 {
00815 defaultPen = colorGroup().highlightedText();
00816 }
00817 else if (d->appearance.rowHighlightingEnabled && row == m_curRow
00818 && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
00819 && usesSelectedTextColor)
00820 {
00821 defaultPen = d->appearance.rowHighlightingTextColor;
00822 }
00823 else if (d->appearance.rowMouseOverHighlightingEnabled && row == d->highlightedRow
00824 && !dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
00825 && usesSelectedTextColor)
00826 {
00827 defaultPen = d->appearance.rowMouseOverHighlightingTextColor;
00828 }
00829 else
00830 defaultPen = d->appearance.textColor;
00831
00832 if (edit) {
00833 if (defaultValueDisplayed)
00834 p->setFont( d->defaultValueDisplayParameters.font );
00835 p->setPen( defaultPen );
00836
00837
00838 getVisibleLookupValue(cellValue, edit, item, tvcol);
00839
00840 edit->setupContents( p, m_currentItem == item && col == m_curCol,
00841 cellValue, txt, align, x, y_offset, w, h );
00842 }
00843 if (!d->appearance.gridEnabled)
00844 y_offset++;
00845
00846 if (d->appearance.fullRowSelection && d->appearance.fullRowSelection) {
00847
00848 }
00849 if (m_currentItem == item && (col == m_curCol || d->appearance.fullRowSelection)) {
00850 if (edit && ((d->appearance.rowHighlightingEnabled && !d->appearance.fullRowSelection) || (row == m_curRow && d->highlightedRow==-1 && d->appearance.fullRowSelection)))
00851 edit->paintSelectionBackground( p, isEnabled(), txt, align, x, y_offset, w, h,
00852 isEnabled() ? colorGroup().highlight() : QColor(200,200,200),
00853 p->fontMetrics(), columnReadOnly, d->appearance.fullRowSelection );
00854 }
00855
00856 if (!edit) {
00857 p->fillRect(0, 0, x2, y2, d->diagonalGrayPattern);
00858 }
00859
00860
00861 if(m_currentItem == item && col == m_curCol
00862 && !d->appearance.fullRowSelection)
00863 {
00864
00865
00866 if (isEnabled()) {
00867 p->setPen(d->appearance.textColor);
00868 }
00869 else {
00870 QPen gray_pen(p->pen());
00871 gray_pen.setColor(d->appearance.borderColor);
00872 p->setPen(gray_pen);
00873 }
00874 if (edit)
00875 edit->paintFocusBorders( p, cellValue, 0, 0, x2, y2 );
00876 else
00877 p->drawRect(0, 0, x2, y2);
00878 }
00879
00881 if ((!m_newRowEditing && item == m_insertItem)
00882 || (m_newRowEditing && item == m_currentItem && cellValue.isNull())) {
00883
00884 if (tvcol->field()->isAutoIncrement()) {
00885
00886
00887
00888
00889 KexiDisplayUtils::paintAutonumberSign(d->autonumberSignDisplayParameters, p,
00890 x, y_offset, w - x - x - ((align & Qt::AlignLeft)?2:0), h, align);
00891
00892 }
00893 }
00894
00895
00896 if (!txt.isEmpty()) {
00897 if (defaultValueDisplayed)
00898 p->setFont( d->defaultValueDisplayParameters.font );
00899 p->setPen( defaultPen );
00900 p->drawText(x, y_offset, w - (x + x)- ((align & Qt::AlignLeft)?2:0), h,
00901 align, txt);
00902 }
00903 p->restore();
00904 }
00905
00906 QPoint KexiTableView::contentsToViewport2( const QPoint &p )
00907 {
00908 return QPoint( p.x() - contentsX(), p.y() - contentsY() );
00909 }
00910
00911 void KexiTableView::contentsToViewport2( int x, int y, int& vx, int& vy )
00912 {
00913 const QPoint v = contentsToViewport2( QPoint( x, y ) );
00914 vx = v.x();
00915 vy = v.y();
00916 }
00917
00918 QPoint KexiTableView::viewportToContents2( const QPoint& vp )
00919 {
00920 return QPoint( vp.x() + contentsX(),
00921 vp.y() + contentsY() );
00922 }
00923
00924 void KexiTableView::paintEmptyArea( QPainter *p, int cx, int cy, int cw, int ch )
00925 {
00926
00927
00928
00929
00930 QSize ts( tableSize() );
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940 contentsToViewport2( cx, cy, cx, cy );
00941 QRegion reg( QRect( cx, cy, cw, ch ) );
00942
00943
00944
00945
00946
00947 reg = reg.subtract( QRect( QPoint( 0, 0 ), ts
00948 -QSize(0,QMAX((m_navPanel ? m_navPanel->height() : 0), horizontalScrollBar()->sizeHint().height())
00949 - (horizontalScrollBar()->isVisible() ? horizontalScrollBar()->sizeHint().height()/2 : 0)
00950 + (horizontalScrollBar()->isVisible() ? 0 :
00951 d->internal_bottomMargin
00952
00953 )
00954
00955 + contentsY()
00956
00957 )
00958 ) );
00959
00960
00961
00962 QMemArray<QRect> r = reg.rects();
00963 for ( int i = 0; i < (int)r.count(); i++ ) {
00964 QRect rect( viewportToContents2(r[i].topLeft()), r[i].size() );
00965
00966
00967
00968
00969 p->fillRect( rect, d->appearance.emptyAreaColor );
00970
00971 }
00972 }
00973
00974 void KexiTableView::contentsMouseDoubleClickEvent(QMouseEvent *e)
00975 {
00976
00977 m_contentsMousePressEvent_dblClick = true;
00978 contentsMousePressEvent(e);
00979 m_contentsMousePressEvent_dblClick = false;
00980
00981 if(m_currentItem)
00982 {
00983 if(d->editOnDoubleClick && columnEditable(m_curCol) && columnType(m_curCol) != KexiDB::Field::Boolean) {
00984 KexiTableEdit *edit = tableEditorWidget( m_curCol, true );
00985 if (edit && edit->handleDoubleClick()) {
00986
00987 }
00988 else {
00989 startEditCurrentCell();
00990
00991 }
00992 }
00993
00994 emit itemDblClicked(m_currentItem, m_curRow, m_curCol);
00995 }
00996 }
00997
00998 void KexiTableView::contentsMousePressEvent( QMouseEvent* e )
00999 {
01000
01001 setFocus();
01002 if(m_data->count()==0 && !isInsertingEnabled()) {
01003 QScrollView::contentsMousePressEvent( e );
01004 return;
01005 }
01006
01007 if (columnAt(e->pos().x())==-1) {
01008 QScrollView::contentsMousePressEvent( e );
01009 return;
01010 }
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020 if (!d->moveCursorOnMouseRelease) {
01021 if (!handleContentsMousePressOrRelease(e, false))
01022 return;
01023 }
01024
01025
01026 if(e->button() == Qt::RightButton)
01027 {
01028 showContextMenu(e->globalPos());
01029 }
01030 else if(e->button() == Qt::LeftButton)
01031 {
01032 if(columnType(m_curCol) == KexiDB::Field::Boolean && columnEditable(m_curCol))
01033 {
01034
01035 int s = QMAX(d->rowHeight - 5, 12);
01036 s = QMIN( d->rowHeight-3, s );
01037 s = QMIN( columnWidth(m_curCol)-3, s );
01038 const QRect r( columnPos(m_curCol) + QMAX( columnWidth(m_curCol)/2 - s/2, 0 ), rowPos(m_curRow) +d->rowHeight/2 - s/2 , s, s);
01039
01040 if (r.contains(e->pos())) {
01041
01042
01043 boolToggled();
01044 }
01045 }
01046 #if 0 //js: TODO
01047 else if(columnType(m_curCol) == QVariant::StringList && columnEditable(m_curCol))
01048 {
01049 createEditor(m_curRow, m_curCol);
01050 }
01051 #endif
01052 }
01053
01054 }
01055
01056 void KexiTableView::contentsMouseReleaseEvent( QMouseEvent* e )
01057 {
01058
01059 if(m_data->count()==0 && !isInsertingEnabled())
01060 return;
01061
01062 if (d->moveCursorOnMouseRelease)
01063 handleContentsMousePressOrRelease(e, true);
01064
01065 int col = columnAt(e->pos().x());
01066 int row = rowAt(e->pos().y());
01067
01068 if (!m_currentItem || col==-1 || row==-1 || col!=m_curCol || row!=m_curRow)
01069 return;
01070
01071 QScrollView::contentsMouseReleaseEvent( e );
01072
01073 emit itemMouseReleased(m_currentItem, m_curRow, m_curCol);
01074 }
01075
01076 bool KexiTableView::handleContentsMousePressOrRelease(QMouseEvent* e, bool release)
01077 {
01078
01079 int oldRow = m_curRow;
01080 int oldCol = m_curCol;
01081 kdDebug(44021) << "oldRow=" << oldRow <<" oldCol=" << oldCol <<endl;
01082 bool onInsertItem = false;
01083
01084 int newrow, newcol;
01085
01086 if (isInsertingEnabled()) {
01087 if (rowAt(e->pos().y())==-1) {
01088 newrow = rowAt(e->pos().y() - d->rowHeight);
01089 if (newrow==-1 && m_data->count()>0) {
01090 if (release)
01091 QScrollView::contentsMouseReleaseEvent( e );
01092 else
01093 QScrollView::contentsMousePressEvent( e );
01094 return false;
01095 }
01096 newrow++;
01097 kdDebug(44021) << "Clicked just on 'insert' row." << endl;
01098 onInsertItem=true;
01099 }
01100 else {
01101
01102 newrow = rowAt(e->pos().y());
01103 }
01104 }
01105 else {
01106 if (rowAt(e->pos().y())==-1 || columnAt(e->pos().x())==-1) {
01107 if (release)
01108 QScrollView::contentsMouseReleaseEvent( e );
01109 else
01110 QScrollView::contentsMousePressEvent( e );
01111 return false;
01112 }
01113
01114 newrow = rowAt(e->pos().y());
01115 }
01116 newcol = columnAt(e->pos().x());
01117
01118 if(e->button() != Qt::NoButton) {
01119 setCursorPosition(newrow,newcol);
01120 }
01121 return true;
01122 }
01123
01124 void KexiTableView::showContextMenu(const QPoint& _pos)
01125 {
01126 if (!d->contextMenuEnabled || m_popupMenu->count()<1)
01127 return;
01128 QPoint pos(_pos);
01129 if (pos==QPoint(-1,-1)) {
01130 pos = viewport()->mapToGlobal( QPoint( columnPos(m_curCol), rowPos(m_curRow) + d->rowHeight ) );
01131 }
01132
01133
01134 selectRow(m_curRow);
01135 m_popupMenu->exec(pos);
01136
01137
01138
01139
01140
01141 }
01142
01143 void KexiTableView::contentsMouseMoveEvent( QMouseEvent *e )
01144 {
01145 int row;
01146 const int col = columnAt(e->x());
01147 if (col < 0) {
01148 row = -1;
01149 } else {
01150 row = rowAt( e->y(), true );
01151 if (row > (rows() - 1 + (isInsertingEnabled()?1:0)))
01152 row = -1;
01153 }
01154
01155
01156 if (d->appearance.rowMouseOverHighlightingEnabled) {
01157 if (row != d->highlightedRow) {
01158 const int oldRow = d->highlightedRow;
01159 d->highlightedRow = row;
01160 updateRow(oldRow);
01161 updateRow(d->highlightedRow);
01162
01163 updateRow(m_curRow);
01164 m_verticalHeader->setHighlightedRow(d->highlightedRow);
01165 }
01166 }
01167
01168 #if 0//(js) doesn't work!
01169
01170
01171 int x,y;
01172 contentsToViewport(e->x(), e->y(), x, y);
01173
01174 if(y > visibleHeight())
01175 {
01176 d->needAutoScroll = true;
01177 d->scrollTimer->start(70, false);
01178 d->scrollDirection = ScrollDown;
01179 }
01180 else if(y < 0)
01181 {
01182 d->needAutoScroll = true;
01183 d->scrollTimer->start(70, false);
01184 d->scrollDirection = ScrollUp;
01185 }
01186 else if(x > visibleWidth())
01187 {
01188 d->needAutoScroll = true;
01189 d->scrollTimer->start(70, false);
01190 d->scrollDirection = ScrollRight;
01191 }
01192 else if(x < 0)
01193 {
01194 d->needAutoScroll = true;
01195 d->scrollTimer->start(70, false);
01196 d->scrollDirection = ScrollLeft;
01197 }
01198 else
01199 {
01200 d->needAutoScroll = false;
01201 d->scrollTimer->stop();
01202 contentsMousePressEvent(e);
01203 }
01204 #endif
01205 QScrollView::contentsMouseMoveEvent(e);
01206 }
01207
01208 #if 0//(js) doesn't work!
01209 void KexiTableView::contentsMouseReleaseEvent(QMouseEvent *)
01210 {
01211 if(d->needAutoScroll)
01212 {
01213 d->scrollTimer->stop();
01214 }
01215 }
01216 #endif
01217
01218 static bool overrideEditorShortcutNeeded(QKeyEvent *e)
01219 {
01220
01221 return e->key() == Qt::Key_Delete && e->state()==Qt::ControlButton;
01222 }
01223
01224 bool KexiTableView::shortCutPressed( QKeyEvent *e, const QCString &action_name )
01225 {
01226 const int k = e->key();
01227 KAction *action = m_sharedActions[action_name];
01228 if (action) {
01229 if (!action->isEnabled())
01230 return false;
01231 if (action->shortcut() == KShortcut( KKey(e) )) {
01232
01233 if (overrideEditorShortcutNeeded(e)) {
01234 return true;
01235 }
01236 return false;
01237 }
01238 }
01239
01240
01241
01242 if (action_name=="data_save_row")
01243 return (k == Qt::Key_Return || k == Qt::Key_Enter) && e->state()==Qt::ShiftButton;
01244 if (action_name=="edit_delete_row")
01245 return k == Qt::Key_Delete && e->state()==Qt::ControlButton;
01246 if (action_name=="edit_delete")
01247 return k == Qt::Key_Delete && e->state()==Qt::NoButton;
01248 if (action_name=="edit_edititem")
01249 return k == Qt::Key_F2 && e->state()==Qt::NoButton;
01250 if (action_name=="edit_insert_empty_row")
01251 return k == Qt::Key_Insert && e->state()==(Qt::ShiftButton | Qt::ControlButton);
01252
01253 return false;
01254 }
01255
01256 void KexiTableView::keyPressEvent(QKeyEvent* e)
01257 {
01258 if (!hasData())
01259 return;
01260
01261
01262 const int k = e->key();
01263 const bool ro = isReadOnly();
01264 QWidget *w = focusWidget();
01265
01266
01267 if (!w || w!=viewport() && w!=this && (!m_editor || !KexiUtils::hasParent(dynamic_cast<QObject*>(m_editor), w))) {
01268
01269 e->ignore();
01270 return;
01271 }
01272 if (d->skipKeyPress) {
01273 d->skipKeyPress=false;
01274 e->ignore();
01275 return;
01276 }
01277
01278 if(m_currentItem == 0 && (m_data->count() > 0 || isInsertingEnabled()))
01279 {
01280 setCursorPosition(0,0);
01281 }
01282 else if(m_data->count() == 0 && !isInsertingEnabled())
01283 {
01284 e->accept();
01285 return;
01286 }
01287
01288 if(m_editor) {
01289 if (k == Qt::Key_Escape) {
01290 cancelEditor();
01291 e->accept();
01292 return;
01293 } else if (k == Qt::Key_Return || k == Qt::Key_Enter) {
01294 if (columnType(m_curCol) == KexiDB::Field::Boolean) {
01295 boolToggled();
01296 }
01297 else {
01298 acceptEditor();
01299 }
01300 e->accept();
01301 return;
01302 }
01303 }
01304 else if (m_rowEditing) {
01305 if (shortCutPressed( e, "data_save_row")) {
01306 kexidbg << "shortCutPressed!!!" <<endl;
01307 acceptRowEdit();
01308 return;
01309 }
01310 }
01311
01312 if(k == Qt::Key_Return || k == Qt::Key_Enter)
01313 {
01314 emit itemReturnPressed(m_currentItem, m_curRow, m_curCol);
01315 }
01316
01317 int curRow = m_curRow;
01318 int curCol = m_curCol;
01319
01320 const bool nobtn = e->state()==NoButton;
01321 bool printable = false;
01322
01323
01324 if (!ro) {
01325 if (shortCutPressed(e, "edit_delete_row")) {
01326 deleteCurrentRow();
01327 e->accept();
01328 return;
01329 } else if (shortCutPressed(e, "edit_delete")) {
01330 deleteAndStartEditCurrentCell();
01331 e->accept();
01332 return;
01333 }
01334 else if (shortCutPressed(e, "edit_insert_empty_row")) {
01335 insertEmptyRow();
01336 e->accept();
01337 return;
01338 }
01339 }
01340
01341
01342
01343
01344
01345
01346
01347
01348
01349
01350
01351 if (k == Qt::Key_Shift || k == Qt::Key_Alt || k == Qt::Key_Control || k == Qt::Key_Meta) {
01352 e->ignore();
01353 }
01354 else if (KexiDataAwareObjectInterface::handleKeyPress(e, curRow, curCol, d->appearance.fullRowSelection)) {
01355 if (e->isAccepted())
01356 return;
01357 }
01358 else if (k == Qt::Key_Backspace && nobtn) {
01359 if (!ro && columnType(curCol) != KexiDB::Field::Boolean && columnEditable(curCol))
01360 createEditor(curRow, curCol, QString::null, true);
01361 }
01362 else if (k == Qt::Key_Space) {
01363 if (nobtn && !ro && columnEditable(curCol)) {
01364 if (columnType(curCol) == KexiDB::Field::Boolean) {
01365 boolToggled();
01366 }
01367 else
01368 printable = true;
01369 }
01370 }
01371 else if (k == Qt::Key_Escape) {
01372 if (nobtn && m_rowEditing) {
01373 cancelRowEdit();
01374 return;
01375 }
01376 }
01377 else {
01378
01379 if (nobtn && (k==Qt::Key_Tab || k==Qt::Key_Right)) {
01381
01382 if (acceptEditor()) {
01383 if (curCol == (columns() - 1)) {
01384 if (curRow < (rows()-1+(isInsertingEnabled()?1:0))) {
01385 curRow++;
01386 curCol = 0;
01387 }
01388 }
01389 else
01390 curCol++;
01391 }
01392 }
01393 else if ((e->state()==Qt::ShiftButton && k==Qt::Key_Tab)
01394 || (nobtn && k==Qt::Key_Backtab)
01395 || (e->state()==Qt::ShiftButton && k==Qt::Key_Backtab)
01396 || (nobtn && k==Qt::Key_Left)
01397 ) {
01399
01400 if (acceptEditor()) {
01401 if (curCol == 0) {
01402 if (curRow>0) {
01403 curRow--;
01404 curCol = columns() - 1;
01405 }
01406 }
01407 else
01408 curCol--;
01409 }
01410 }
01411 else if (nobtn && k==d->contextMenuKey) {
01412 showContextMenu();
01413 }
01414 else {
01415 KexiTableEdit *edit = tableEditorWidget( m_curCol );
01416 if (edit && edit->handleKeyPress(e, m_editor==edit)) {
01417
01418 e->accept();
01419 return;
01420 }
01421 else if ( nobtn && (k==Qt::Key_Enter || k==Qt::Key_Return || shortCutPressed(e, "edit_edititem")) ) {
01422
01423 startEditOrToggleValue();
01424 }
01425 else {
01426 kexidbg << "KexiTableView::KeyPressEvent(): default" << endl;
01427 if (e->text().isEmpty() || !e->text().isEmpty() && !e->text()[0].isPrint() ) {
01428 kdDebug(44021) << "NOT PRINTABLE: 0x0" << QString("%1").arg(k,0,16) <<endl;
01429
01430 QScrollView::keyPressEvent(e);
01431 return;
01432 }
01433 printable = true;
01434 }
01435 }
01436 }
01437
01438 if (printable && !ro) {
01439 KexiTableViewColumn *tvcol = m_data->column(curCol);
01440 if (tvcol->acceptsFirstChar(e->text()[0])) {
01441 kdDebug(44021) << "KexiTableView::KeyPressEvent(): ev pressed: acceptsFirstChar()==true" << endl;
01442
01443 createEditor(curRow, curCol, e->text(), true);
01444 }
01445 else {
01446
01447 kdDebug(44021) << "KexiTableView::KeyPressEvent(): ev pressed: acceptsFirstChar()==false" << endl;
01448 }
01449 }
01450
01451 m_vScrollBarValueChanged_enabled=false;
01452
01453
01454 setCursorPosition(curRow, curCol);
01455
01456 m_vScrollBarValueChanged_enabled=true;
01457
01458 e->accept();
01459 }
01460
01461 void KexiTableView::emitSelected()
01462 {
01463 if(m_currentItem)
01464 emit itemSelected(m_currentItem);
01465 }
01466
01467 int KexiTableView::rowsPerPage() const
01468 {
01469 return visibleHeight() / d->rowHeight;
01470 }
01471
01472 KexiDataItemInterface *KexiTableView::editor( int col, bool ignoreMissingEditor )
01473 {
01474 if (!m_data || col<0 || col>=columns())
01475 return 0;
01476 KexiTableViewColumn *tvcol = m_data->column(col);
01477
01478
01479
01480 KexiTableEdit *editor = d->editors[ tvcol ];
01481 if (editor)
01482 return editor;
01483
01484
01485
01486 editor = KexiCellEditorFactory::createEditor(*tvcol, this);
01487 if (!editor) {
01488 if (!ignoreMissingEditor) {
01489
01490 cancelRowEdit();
01491 }
01492 return 0;
01493 }
01494 editor->hide();
01495 if (m_data->cursor() && m_data->cursor()->query())
01496 editor->createInternalEditor(*m_data->cursor()->query());
01497
01498 connect(editor,SIGNAL(editRequested()),this,SLOT(slotEditRequested()));
01499 connect(editor,SIGNAL(cancelRequested()),this,SLOT(cancelEditor()));
01500 connect(editor,SIGNAL(acceptRequested()),this,SLOT(acceptEditor()));
01501
01502 editor->resize(columnWidth(col)-1, rowHeight()-1);
01503 editor->installEventFilter(this);
01504 if (editor->widget())
01505 editor->widget()->installEventFilter(this);
01506
01507 d->editors.insert( tvcol, editor );
01508 return editor;
01509 }
01510
01511 void KexiTableView::editorShowFocus( int , int col )
01512 {
01513 KexiDataItemInterface *edit = editor( col );
01514
01515
01516
01517
01518
01519 if (edit) {
01520 kexidbg<< "KexiTableView::editorShowFocus() : IN" << endl;
01521 QRect rect = cellGeometry( m_curRow, m_curCol );
01522
01523 edit->showFocus( rect, isReadOnly() || m_data->column(col)->isReadOnly() );
01524 }
01525 }
01526
01527 void KexiTableView::slotEditRequested()
01528 {
01529 createEditor(m_curRow, m_curCol);
01530 }
01531
01532 void KexiTableView::reloadData() {
01533 KexiDataAwareObjectInterface::reloadData();
01534 updateContents();
01535 }
01536
01537 void KexiTableView::createEditor(int row, int col, const QString& addText, bool removeOld)
01538 {
01539 kdDebug(44021) << "KexiTableView::createEditor('"<<addText<<"',"<<removeOld<<")"<<endl;
01540 if (isReadOnly()) {
01541 kdDebug(44021) << "KexiTableView::createEditor(): DATA IS READ ONLY!"<<endl;
01542 return;
01543 }
01544
01545 if (m_data->column(col)->isReadOnly()) {
01546 kdDebug(44021) << "KexiTableView::createEditor(): COL IS READ ONLY!"<<endl;
01547 return;
01548 }
01549
01550 const bool startRowEdit = !m_rowEditing;
01551
01552 if (!m_rowEditing) {
01553
01554 m_data->clearRowEditBuffer();
01555
01556 m_rowEditing = true;
01557
01558 m_verticalHeader->setEditRow(m_curRow);
01559 if (isInsertingEnabled() && m_currentItem==m_insertItem) {
01560
01561 m_newRowEditing = true;
01562
01563 m_data->append( m_insertItem );
01564
01565 m_insertItem = m_data->createItem();
01566 m_verticalHeader->addLabel();
01567 m_verticalHeaderAlreadyAdded = true;
01568 updateWidgetContentsSize();
01569
01570 updateContents(columnPos(0), rowPos(row), viewport()->width(), d->rowHeight*2);
01571
01572
01573 ensureVisible(columnPos(m_curCol), rowPos(row+1)+d->rowHeight-1, columnWidth(m_curCol), d->rowHeight);
01574
01575 m_verticalHeader->setOffset(contentsY());
01576 }
01577 }
01578
01579 KexiTableEdit *editorWidget = tableEditorWidget( col );
01580 m_editor = editorWidget;
01581 if (!editorWidget)
01582 return;
01583
01584 m_editor->setValue(*bufferedValueAt(col, !removeOld), addText, removeOld);
01585 if (m_editor->hasFocusableWidget()) {
01586 moveChild(editorWidget, columnPos(m_curCol), rowPos(m_curRow));
01587
01588 editorWidget->resize(columnWidth(m_curCol)-1, rowHeight()-1);
01589 editorWidget->show();
01590
01591 m_editor->setFocus();
01592 }
01593
01594 if (startRowEdit) {
01595 m_navPanel->showEditingIndicator(true);
01596
01597 emit rowEditStarted(m_curRow);
01598 }
01599 }
01600
01601 void KexiTableView::focusInEvent(QFocusEvent* e)
01602 {
01603 Q_UNUSED(e);
01604 updateCell(m_curRow, m_curCol);
01605 }
01606
01607 void KexiTableView::focusOutEvent(QFocusEvent* e)
01608 {
01609 KexiDataAwareObjectInterface::focusOutEvent(e);
01610 }
01611
01612 bool KexiTableView::focusNextPrevChild(bool )
01613 {
01614 return false;
01615
01616
01617
01618 }
01619
01620 void KexiTableView::resizeEvent(QResizeEvent *e)
01621 {
01622 QScrollView::resizeEvent(e);
01623
01624
01625 if (m_navPanel)
01626 m_navPanel->updateGeometry(leftMargin());
01627
01628
01629 if ((contentsHeight() - e->size().height()) <= d->rowHeight) {
01630 slotUpdate();
01631 triggerUpdate();
01632 }
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649 }
01650
01651 void KexiTableView::viewportResizeEvent( QResizeEvent *e )
01652 {
01653 QScrollView::viewportResizeEvent( e );
01654 updateGeometries();
01655
01656 }
01657
01658 void KexiTableView::showEvent(QShowEvent *e)
01659 {
01660 QScrollView::showEvent(e);
01661 if (!d->maximizeColumnsWidthOnShow.isEmpty()) {
01662 maximizeColumnsWidth(d->maximizeColumnsWidthOnShow);
01663 d->maximizeColumnsWidthOnShow.clear();
01664 }
01665
01666 if (m_initDataContentsOnShow) {
01667
01668 m_initDataContentsOnShow = false;
01669 initDataContents();
01670 }
01671 else {
01672
01673 QSize s(tableSize());
01674
01675
01676 resizeContents(s.width(),s.height());
01677 }
01678 updateGeometries();
01679
01680
01681 if (d->ensureCellVisibleOnShow!=QPoint(-1,-1)) {
01682 ensureCellVisible( d->ensureCellVisibleOnShow.x(), d->ensureCellVisibleOnShow.y() );
01683 d->ensureCellVisibleOnShow = QPoint(-1,-1);
01684 }
01685 if (m_navPanel)
01686 m_navPanel->updateGeometry(leftMargin());
01687
01688 }
01689
01690 void KexiTableView::contentsDragMoveEvent(QDragMoveEvent *e)
01691 {
01692 if (!hasData())
01693 return;
01694 if (m_dropsAtRowEnabled) {
01695 QPoint p = e->pos();
01696 int row = rowAt(p.y());
01697 KexiTableItem *item = 0;
01698
01699 if ((p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
01700 row++;
01701 }
01702 item = m_data->at(row);
01703 emit dragOverRow(item, row, e);
01704 if (e->isAccepted()) {
01705 if (m_dragIndicatorLine>=0 && m_dragIndicatorLine != row) {
01706
01707 updateRow(m_dragIndicatorLine);
01708 }
01709 if (m_dragIndicatorLine != row) {
01710 m_dragIndicatorLine = row;
01711 updateRow(m_dragIndicatorLine);
01712 }
01713 }
01714 else {
01715 if (m_dragIndicatorLine>=0) {
01716
01717 updateRow(m_dragIndicatorLine);
01718 }
01719 m_dragIndicatorLine = -1;
01720 }
01721 }
01722 else
01723 e->acceptAction(false);
01724
01725
01726
01727
01728
01729
01730
01731
01732
01733
01734 }
01735
01736 void KexiTableView::contentsDropEvent(QDropEvent *e)
01737 {
01738 if (!hasData())
01739 return;
01740 if (m_dropsAtRowEnabled) {
01741
01742 if (m_dragIndicatorLine>=0) {
01743 int row2update = m_dragIndicatorLine;
01744 m_dragIndicatorLine = -1;
01745 updateRow(row2update);
01746 }
01747 QPoint p = e->pos();
01748 int row = rowAt(p.y());
01749 if ((p.y() % d->rowHeight) > (d->rowHeight*2/3) ) {
01750 row++;
01751 }
01752 KexiTableItem *item = m_data->at(row);
01753 KexiTableItem *newItem = 0;
01754 emit droppedAtRow(item, row, e, newItem);
01755 if (newItem) {
01756 const int realRow = (row==m_curRow ? -1 : row);
01757 insertItem(newItem, realRow);
01758 setCursorPosition(row, 0);
01759
01760 }
01761 }
01762 }
01763
01764 void KexiTableView::viewportDragLeaveEvent( QDragLeaveEvent *e )
01765 {
01766 Q_UNUSED(e);
01767 if (!hasData())
01768 return;
01769 if (m_dropsAtRowEnabled) {
01770
01771 if (m_dragIndicatorLine>=0) {
01772 int row2update = m_dragIndicatorLine;
01773 m_dragIndicatorLine = -1;
01774 updateRow(row2update);
01775 }
01776 }
01777 }
01778
01779 void KexiTableView::updateCell(int row, int col)
01780 {
01781
01782 updateContents(cellGeometry(row, col));
01783
01784
01785
01786
01787 }
01788
01789 void KexiTableView::updateCurrentCell()
01790 {
01791 updateCell(m_curRow, m_curCol);
01792 }
01793
01794 void KexiTableView::updateRow(int row)
01795 {
01796
01797 if (row < 0 || row >= (rows() + 2 ))
01798 return;
01799
01800
01801
01802
01803
01804 updateContents( QRect( contentsX(), rowPos(row), clipper()->width(), rowHeight() ) );
01805 }
01806
01807 void KexiTableView::slotColumnWidthChanged( int, int, int )
01808 {
01809 QSize s(tableSize());
01810 int w = contentsWidth();
01811 viewport()->setUpdatesEnabled(false);
01812 resizeContents( s.width(), s.height() );
01813 viewport()->setUpdatesEnabled(true);
01814 if (contentsWidth() < w) {
01815 updateContents(contentsX(), 0, viewport()->width(), contentsHeight());
01816
01817 }
01818 else {
01819
01820 updateContents(contentsX(), 0, viewport()->width(), contentsHeight());
01821
01822 }
01823
01824
01825 QWidget *editorWidget = dynamic_cast<QWidget*>(m_editor);
01826 if (editorWidget)
01827 {
01828 editorWidget->resize(columnWidth(m_curCol)-1, rowHeight()-1);
01829 moveChild(editorWidget, columnPos(m_curCol), rowPos(m_curRow));
01830 }
01831 updateGeometries();
01832 updateScrollBars();
01833 if (m_navPanel)
01834 m_navPanel->updateGeometry(leftMargin());
01835
01836 }
01837
01838 void KexiTableView::slotSectionHandleDoubleClicked( int section )
01839 {
01840 adjustColumnWidthToContents(section);
01841 slotColumnWidthChanged(0,0,0);
01842 }
01843
01844
01845 void KexiTableView::updateGeometries()
01846 {
01847 QSize ts = tableSize();
01848 if (m_horizontalHeader->offset() && ts.width() < (m_horizontalHeader->offset() + m_horizontalHeader->width()))
01849 horizontalScrollBar()->setValue(ts.width() - m_horizontalHeader->width());
01850
01851
01852 m_horizontalHeader->setGeometry(leftMargin() + 1, 1, visibleWidth(), topMargin());
01853 m_verticalHeader->setGeometry(1, topMargin() + 1, leftMargin(), visibleHeight());
01854 }
01855
01856 int KexiTableView::columnWidth(int col) const
01857 {
01858 if (!hasData())
01859 return 0;
01860 int vcID = m_data->visibleColumnID( col );
01861 return (vcID==-1) ? 0 : m_horizontalHeader->sectionSize( vcID );
01862 }
01863
01864 int KexiTableView::rowHeight() const
01865 {
01866 return d->rowHeight;
01867 }
01868
01869 int KexiTableView::columnPos(int col) const
01870 {
01871 if (!hasData())
01872 return 0;
01873
01874 int c = QMIN(col, (int)m_data->columnsCount()-1), vcID = 0;
01875 while (c>=0 && (vcID=m_data->visibleColumnID( c ))==-1)
01876 c--;
01877 if (c<0)
01878 return 0;
01879 if (c==col)
01880 return m_horizontalHeader->sectionPos(vcID);
01881 return m_horizontalHeader->sectionPos(vcID)+m_horizontalHeader->sectionSize(vcID);
01882 }
01883
01884 int KexiTableView::rowPos(int row) const
01885 {
01886 return d->rowHeight*row;
01887 }
01888
01889 int KexiTableView::columnAt(int pos) const
01890 {
01891 if (!hasData())
01892 return -1;
01893 int r = m_horizontalHeader->sectionAt(pos);
01894 if (r<0)
01895 return r;
01896 return m_data->globalColumnID( r );
01897
01898
01899
01900
01901 }
01902
01903 int KexiTableView::rowAt(int pos, bool ignoreEnd) const
01904 {
01905 if (!hasData())
01906 return -1;
01907 pos /=d->rowHeight;
01908 if (pos < 0)
01909 return 0;
01910 if ((pos >= (int)m_data->count()) && !ignoreEnd)
01911 return -1;
01912 return pos;
01913 }
01914
01915 QRect KexiTableView::cellGeometry(int row, int col) const
01916 {
01917 return QRect(columnPos(col), rowPos(row),
01918 columnWidth(col), rowHeight());
01919 }
01920
01921 QSize KexiTableView::tableSize() const
01922 {
01923 if ((rows()+ (isInsertingEnabled()?1:0) ) > 0 && columns() > 0) {
01924
01925
01926
01927
01928
01929
01930
01931
01932
01933
01934
01935 QSize s(
01936 columnPos( columns() - 1 ) + columnWidth( columns() - 1 ),
01937
01938 rowPos( rows()-1+(isInsertingEnabled()?1:0) ) + d->rowHeight
01939 + (horizontalScrollBar()->isVisible() ? 0 : horizontalScrollBar()->sizeHint().height())
01940 + d->internal_bottomMargin
01941
01942
01943
01944
01945
01946
01947
01948
01949
01950
01951
01952
01953
01954
01955 + margin()
01956
01957 );
01958
01959
01960 return s;
01961
01962 }
01963 return QSize(0,0);
01964 }
01965
01966 void KexiTableView::ensureCellVisible(int row, int col)
01967 {
01968 if (!isVisible()) {
01969
01970 d->ensureCellVisibleOnShow = QPoint(row,col);
01971 return;
01972 }
01973
01974
01975 QRect r( columnPos(col==-1 ? m_curCol : col), rowPos(row) +(d->appearance.fullRowSelection?1:0),
01976 columnWidth(col==-1 ? m_curCol : col), rowHeight());
01977
01978
01979
01980
01981
01982
01983
01984
01985
01986 if (m_navPanel && m_navPanel->isVisible() && horizontalScrollBar()->isHidden()) {
01987
01988 r.setBottom(r.bottom()+m_navPanel->height());
01989 }
01990
01991 QPoint pcenter = r.center();
01992 ensureVisible(pcenter.x(), pcenter.y(), r.width()/2, r.height()/2);
01993
01994
01995
01996 }
01997
01998 void KexiTableView::updateAfterCancelRowEdit()
01999 {
02000 KexiDataAwareObjectInterface::updateAfterCancelRowEdit();
02001 m_navPanel->showEditingIndicator(false);
02002 }
02003
02004 void KexiTableView::updateAfterAcceptRowEdit()
02005 {
02006 KexiDataAwareObjectInterface::updateAfterAcceptRowEdit();
02007 m_navPanel->showEditingIndicator(false);
02008 }
02009
02010 bool KexiTableView::getVisibleLookupValue(QVariant& cellValue, KexiTableEdit *edit,
02011 KexiTableItem *item, KexiTableViewColumn *tvcol) const
02012 {
02013 if (edit->columnInfo() && edit->columnInfo()->indexForVisibleLookupValue()!=-1
02014 && edit->columnInfo()->indexForVisibleLookupValue() < (int)item->count())
02015 {
02016 const QVariant *visibleFieldValue = 0;
02017 if (m_currentItem == item && m_data->rowEditBuffer()) {
02018 visibleFieldValue = m_data->rowEditBuffer()->at(
02019 *tvcol->visibleLookupColumnInfo, false );
02020 }
02021
02022 if (visibleFieldValue)
02023
02024 cellValue = *visibleFieldValue;
02025 else
02026 cellValue = item->at( edit->columnInfo()->indexForVisibleLookupValue() );
02027 return true;
02028 }
02029 return false;
02030 }
02031
02032
02033 void KexiTableView::removeEditor()
02034 {
02035 if (!m_editor)
02036 return;
02037 KexiDataAwareObjectInterface::removeEditor();
02038 viewport()->setFocus();
02039 }
02040
02041 void KexiTableView::slotRowRepaintRequested(KexiTableItem& item)
02042 {
02043 updateRow( m_data->findRef(&item) );
02044 }
02045
02046
02047 void KexiTableView::slotAutoScroll()
02048 {
02049 kdDebug(44021) << "KexiTableView::slotAutoScroll()" <<endl;
02050 if (!d->needAutoScroll)
02051 return;
02052
02053 switch(d->scrollDirection)
02054 {
02055 case ScrollDown:
02056 setCursorPosition(m_curRow + 1, m_curCol);
02057 break;
02058
02059 case ScrollUp:
02060 setCursorPosition(m_curRow - 1, m_curCol);
02061 break;
02062 case ScrollLeft:
02063 setCursorPosition(m_curRow, m_curCol - 1);
02064 break;
02065
02066 case ScrollRight:
02067 setCursorPosition(m_curRow, m_curCol + 1);
02068 break;
02069 }
02070 }
02071
02072 #ifndef KEXI_NO_PRINT
02073 void
02074 KexiTableView::print(KPrinter &)
02075 {
02076
02077 #if 0
02078 int leftMargin = printer.margins().width() + 2 + d->rowHeight;
02079 int topMargin = printer.margins().height() + 2;
02080
02081 int bottomMargin = 0;
02082 kdDebug(44021) << "KexiTableView::print: bottom = " << bottomMargin << endl;
02083
02084 QPainter p(&printer);
02085
02086 KexiTableItem *i;
02087 int width = leftMargin;
02088 for(int col=0; col < columns(); col++)
02089 {
02090 p.fillRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, QBrush(Qt::gray));
02091 p.drawRect(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight);
02092 p.drawText(width, topMargin - d->rowHeight, columnWidth(col), d->rowHeight, Qt::AlignLeft | Qt::AlignVCenter,
02093 m_horizontalHeader->label(col));
02094 width = width + columnWidth(col);
02095 }
02096
02097 int yOffset = topMargin;
02098 int row = 0;
02099 int right = 0;
02100 for(i = m_data->first(); i; i = m_data->next())
02101 {
02102 if(!i->isInsertItem())
02103 { kdDebug(44021) << "KexiTableView::print: row = " << row << " y = " << yOffset << endl;
02104 int xOffset = leftMargin;
02105 for(int col=0; col < columns(); col++)
02106 {
02107 kdDebug(44021) << "KexiTableView::print: col = " << col << " x = " << xOffset << endl;
02108 p.saveWorldMatrix();
02109 p.translate(xOffset, yOffset);
02110 paintCell(&p, i, col, QRect(0, 0, columnWidth(col) + 1, d->rowHeight), true);
02111 p.restoreWorldMatrix();
02112
02113 xOffset = xOffset + columnWidth(col);
02114 right = xOffset;
02115 }
02116
02117 row++;
02118 yOffset = topMargin + row * d->rowHeight;
02119 }
02120
02121 if(yOffset > 900)
02122 {
02123 p.drawLine(leftMargin, topMargin, leftMargin, yOffset);
02124 p.drawLine(leftMargin, topMargin, right - 1, topMargin);
02125 printer.newPage();
02126 yOffset = topMargin;
02127 row = 0;
02128 }
02129 }
02130 p.drawLine(leftMargin, topMargin, leftMargin, yOffset);
02131 p.drawLine(leftMargin, topMargin, right - 1, topMargin);
02132
02133
02134 p.end();
02135 #endif
02136 }
02137 #endif
02138
02139 QString KexiTableView::columnCaption(int colNum) const
02140 {
02141 return m_horizontalHeader->label(colNum);
02142 }
02143
02144 KexiDB::Field* KexiTableView::field(int colNum) const
02145 {
02146 if (!m_data || !m_data->column(colNum))
02147 return 0;
02148 return m_data->column(colNum)->field();
02149 }
02150
02151 void KexiTableView::adjustColumnWidthToContents(int colNum)
02152 {
02153 if (!hasData())
02154 return;
02155 if (colNum==-1) {
02156 const int cols = columns();
02157 for (int i=0; i<cols; i++)
02158 adjustColumnWidthToContents(i);
02159 return;
02160 }
02161
02162 int indexOfVisibleColumn = (m_data->column(colNum) && m_data->column(colNum)->columnInfo)
02163 ? m_data->column(colNum)->columnInfo->indexForVisibleLookupValue() : -1;
02164 if (-1==indexOfVisibleColumn)
02165 indexOfVisibleColumn = colNum;
02166
02167 if (indexOfVisibleColumn < 0)
02168 return;
02169
02170 QPtrListIterator<KexiTableItem> it = m_data->iterator();
02171 if (it.current() && it.current()->count()<=(uint)indexOfVisibleColumn)
02172 return;
02173
02174 KexiCellEditorFactoryItem *item = KexiCellEditorFactory::item( columnType(indexOfVisibleColumn) );
02175 if (!item)
02176 return;
02177 QFontMetrics fm(fontMetrics());
02178 int maxw = horizontalHeaderVisible()
02179 ? fm.width( m_horizontalHeader->label( colNum ) ) : 0;
02180 if (maxw == 0 && m_data->isEmpty())
02181 return;
02182
02184
02185 KexiTableEdit *ed = tableEditorWidget( colNum );
02186 if (ed) {
02187 for (it = m_data->iterator(); it.current(); ++it) {
02188 const int wfw = ed->widthForValue( it.current()->at( indexOfVisibleColumn ), fm );
02189 maxw = QMAX( maxw, wfw );
02190 }
02191 const bool focused = currentColumn() == colNum;
02192 maxw += (fm.width(" ") + ed->leftMargin() + ed->rightMargin(focused));
02193 }
02194 if (maxw < KEXITV_MINIMUM_COLUMN_WIDTH )
02195 maxw = KEXITV_MINIMUM_COLUMN_WIDTH;
02196 kexidbg << "KexiTableView: setColumnWidth(colNum=" << colNum
02197 << ", indexOfVisibleColumn=" << indexOfVisibleColumn << ", width=" << maxw <<" )" << endl;
02198 setColumnWidth( colNum, maxw );
02199 }
02200
02201 void KexiTableView::setColumnWidth(int colNum, int width)
02202 {
02203 if (columns()<=colNum || colNum < 0)
02204 return;
02205 const int oldWidth = m_horizontalHeader->sectionSize( colNum );
02206 m_horizontalHeader->resizeSection( colNum, width );
02207 slotTopHeaderSizeChange( colNum, oldWidth, m_horizontalHeader->sectionSize( colNum ) );
02208 }
02209
02210 void KexiTableView::maximizeColumnsWidth( const QValueList<int> &columnList )
02211 {
02212 if (!isVisible()) {
02213 d->maximizeColumnsWidthOnShow += columnList;
02214 return;
02215 }
02216 if (width() <= m_horizontalHeader->headerWidth())
02217 return;
02218
02219 QValueList<int> cl, sortedList = columnList;
02220 qHeapSort(sortedList);
02221 int i=-999;
02222
02223 QValueList<int>::ConstIterator it, end( sortedList.constEnd() );
02224 for ( it = sortedList.constBegin(); it != end; ++it) {
02225 if (i != (*it)) {
02226 cl += (*it);
02227 i = (*it);
02228 }
02229 }
02230
02231 int sizeToAdd = (width() - m_horizontalHeader->headerWidth()) / cl.count() - verticalHeader()->width();
02232 if (sizeToAdd<=0)
02233 return;
02234 end = cl.constEnd();
02235 for ( it = cl.constBegin(); it != end; ++it) {
02236 int w = m_horizontalHeader->sectionSize(*it);
02237 if (w>0) {
02238 m_horizontalHeader->resizeSection(*it, w+sizeToAdd);
02239 }
02240 }
02241 updateContents();
02242 editorShowFocus( m_curRow, m_curCol );
02243 }
02244
02245 void KexiTableView::adjustHorizontalHeaderSize()
02246 {
02247 m_horizontalHeader->adjustHeaderSize();
02248 }
02249
02250 void KexiTableView::setColumnStretchEnabled( bool set, int colNum )
02251 {
02252 m_horizontalHeader->setStretchEnabled( set, colNum );
02253 }
02254
02255 void KexiTableView::setEditableOnDoubleClick(bool set)
02256 {
02257 d->editOnDoubleClick = set;
02258 }
02259 bool KexiTableView::editableOnDoubleClick() const
02260 {
02261 return d->editOnDoubleClick;
02262 }
02263
02264 bool KexiTableView::verticalHeaderVisible() const
02265 {
02266 return m_verticalHeader->isVisible();
02267 }
02268
02269 void KexiTableView::setVerticalHeaderVisible(bool set)
02270 {
02271 int left_width;
02272 if (set) {
02273 m_verticalHeader->show();
02274 left_width = QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight);
02275 }
02276 else {
02277 m_verticalHeader->hide();
02278 left_width = 0;
02279 }
02280 setMargins( left_width, horizontalHeaderVisible() ? m_horizontalHeader->sizeHint().height() : 0, 0, 0);
02281 }
02282
02283 bool KexiTableView::horizontalHeaderVisible() const
02284 {
02285 return d->horizontalHeaderVisible;
02286 }
02287
02288 void KexiTableView::setHorizontalHeaderVisible(bool set)
02289 {
02290 int top_height;
02291 d->horizontalHeaderVisible = set;
02292 if (set) {
02293 m_horizontalHeader->show();
02294 top_height = m_horizontalHeader->sizeHint().height();
02295 }
02296 else {
02297 m_horizontalHeader->hide();
02298 top_height = 0;
02299 }
02300 setMargins( verticalHeaderVisible() ? m_verticalHeader->width() : 0, top_height, 0, 0);
02301 }
02302
02303 void KexiTableView::triggerUpdate()
02304 {
02305
02306
02307 d->pUpdateTimer->start(20, true);
02308
02309 }
02310
02311 void KexiTableView::setHBarGeometry( QScrollBar & hbar, int x, int y, int w, int h )
02312 {
02313
02314 kdDebug(44021)<<"KexiTableView::setHBarGeometry"<<endl;
02315 if (d->appearance.navigatorEnabled) {
02316 m_navPanel->setHBarGeometry( hbar, x, y, w, h );
02317 }
02318 else {
02319 hbar.setGeometry( x , y, w, h );
02320 }
02321 }
02322
02323 void KexiTableView::setSpreadSheetMode()
02324 {
02325 KexiDataAwareObjectInterface::setSpreadSheetMode();
02326
02327 Appearance a = d->appearance;
02328 a.navigatorEnabled = m_navPanelEnabled;
02329 setAppearance( a );
02330 }
02331
02332 int KexiTableView::validRowNumber(const QString& text)
02333 {
02334 bool ok=true;
02335 int r = text.toInt(&ok);
02336 if (!ok || r<1)
02337 r = 1;
02338 else if (r > (rows()+(isInsertingEnabled()?1:0)))
02339 r = rows()+(isInsertingEnabled()?1:0);
02340 return r-1;
02341 }
02342
02343 void KexiTableView::moveToRecordRequested( uint r )
02344 {
02345 if (r > uint(rows()+(isInsertingEnabled()?1:0)))
02346 r = rows()+(isInsertingEnabled()?1:0);
02347 setFocus();
02348 selectRow( r );
02349 }
02350
02351 void KexiTableView::moveToLastRecordRequested()
02352 {
02353 setFocus();
02354 selectRow(rows()>0 ? (rows()-1) : 0);
02355 }
02356
02357 void KexiTableView::moveToPreviousRecordRequested()
02358 {
02359 setFocus();
02360 selectPrevRow();
02361 }
02362
02363 void KexiTableView::moveToNextRecordRequested()
02364 {
02365 setFocus();
02366 selectNextRow();
02367 }
02368
02369 void KexiTableView::moveToFirstRecordRequested()
02370 {
02371 setFocus();
02372 selectFirstRow();
02373 }
02374
02375 void KexiTableView::copySelection()
02376 {
02377 if (m_currentItem && m_curCol!=-1) {
02378 KexiTableEdit *edit = tableEditorWidget( m_curCol );
02379 QVariant defaultValue;
02380 const bool defaultValueDisplayed
02381 = isDefaultValueDisplayed(m_currentItem, m_curCol, &defaultValue);
02382 if (edit) {
02383 QVariant visibleValue;
02384 getVisibleLookupValue(visibleValue, edit, m_currentItem, m_data->column(m_curCol));
02385 edit->handleCopyAction(
02386 defaultValueDisplayed ? defaultValue : m_currentItem->at( m_curCol ),
02387 visibleValue );
02388 }
02389 }
02390 }
02391
02392 void KexiTableView::cutSelection()
02393 {
02394
02395 KexiTableEdit *edit = tableEditorWidget( m_curCol );
02396 if (edit)
02397 edit->handleAction("edit_cut");
02398 }
02399
02400 void KexiTableView::paste()
02401 {
02402
02403 KexiTableEdit *edit = tableEditorWidget( m_curCol );
02404 if (edit)
02405 edit->handleAction("edit_paste");
02406 }
02407
02408 bool KexiTableView::eventFilter( QObject *o, QEvent *e )
02409 {
02410
02411
02412
02413 if (e->type()==QEvent::KeyPress) {
02414 if (e->spontaneous() ) {
02415 QKeyEvent *ke = static_cast<QKeyEvent*>(e);
02416 const int k = ke->key();
02417 int s = ke->state();
02418
02419
02420 KexiTableEdit *edit = tableEditorWidget( m_curCol );
02421 if (edit && edit->handleKeyPress(ke, m_editor==edit)) {
02422 ke->accept();
02423 return true;
02424 }
02425 else if (m_editor && (o==dynamic_cast<QObject*>(m_editor) || o==m_editor->widget())) {
02426 if ( (k==Qt::Key_Tab && (s==Qt::NoButton || s==Qt::ShiftButton))
02427 || (overrideEditorShortcutNeeded(ke))
02428 || (k==Qt::Key_Enter || k==Qt::Key_Return || k==Qt::Key_Up || k==Qt::Key_Down)
02429 || (k==Qt::Key_Left && m_editor->cursorAtStart())
02430 || (k==Qt::Key_Right && m_editor->cursorAtEnd())
02431 )
02432 {
02433
02434 keyPressEvent(ke);
02435 if (ke->isAccepted())
02436 return true;
02437 }
02438 }
02439
02440
02441
02442
02443
02444
02445
02446
02447
02448
02449
02450
02451 }
02452 }
02453 else if (o==horizontalScrollBar()) {
02454 if ((e->type()==QEvent::Show && !horizontalScrollBar()->isVisible())
02455 || (e->type()==QEvent::Hide && horizontalScrollBar()->isVisible())) {
02456 updateWidgetContentsSize();
02457 }
02458 }
02459 else if (e->type()==QEvent::Leave) {
02460 if (o==viewport() && d->appearance.rowMouseOverHighlightingEnabled
02461 && d->appearance.persistentSelections)
02462 {
02463 if (d->highlightedRow!=-1) {
02464 int oldRow = d->highlightedRow;
02465 d->highlightedRow = -1;
02466 updateRow(oldRow);
02467 const bool dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted
02468 = d->appearance.rowHighlightingEnabled && !d->appearance.persistentSelections;
02469 if (oldRow!=m_curRow && m_curRow>=0) {
02470 if (!dontPaintNonpersistentSelectionBecauseDifferentRowHasBeenHighlighted)
02471
02472 updateRow(m_curRow);
02473 m_verticalHeader->setHighlightedRow(-1);
02474 }
02475 }
02476 }
02477 d->recentCellWithToolTip = QPoint(-1,-1);
02478 }
02479
02480
02481
02482
02483
02484
02485
02486
02487
02488
02489
02490
02491
02492 return QScrollView::eventFilter(o,e);
02493 }
02494
02495 void KexiTableView::slotTopHeaderSizeChange(
02496 int , int , int )
02497 {
02498 editorShowFocus( m_curRow, m_curCol );
02499 }
02500
02501 void KexiTableView::setBottomMarginInternal(int pixels)
02502 {
02503 d->internal_bottomMargin = pixels;
02504 }
02505
02506 void KexiTableView::paletteChange( const QPalette &oldPalette )
02507 {
02508 Q_UNUSED(oldPalette);
02509
02510 if (m_verticalHeader)
02511 m_verticalHeader->setSelectionBackgroundColor( palette().active().highlight() );
02512 if (m_horizontalHeader)
02513 m_horizontalHeader->setSelectionBackgroundColor( palette().active().highlight() );
02514 }
02515
02516 const KexiTableView::Appearance& KexiTableView::appearance() const
02517 {
02518 return d->appearance;
02519 }
02520
02521 void KexiTableView::setAppearance(const Appearance& a)
02522 {
02523
02524 if (a.fullRowSelection) {
02525 d->rowHeight -= 1;
02526 }
02527 else {
02528 d->rowHeight += 1;
02529 }
02530 if (m_verticalHeader)
02531 m_verticalHeader->setCellHeight(d->rowHeight);
02532 if (m_horizontalHeader) {
02533 setMargins(
02534 QMIN(m_horizontalHeader->sizeHint().height(), d->rowHeight),
02535 m_horizontalHeader->sizeHint().height(), 0, 0);
02536 }
02537
02538 if (a.rowHighlightingEnabled)
02539 m_updateEntireRowWhenMovingToOtherRow = true;
02540
02541 if(!a.navigatorEnabled)
02542 m_navPanel->hide();
02543 else
02544 m_navPanel->show();
02545
02546
02547 d->highlightedRow = -1;
02549 viewport()->setMouseTracking(a.rowMouseOverHighlightingEnabled);
02550
02551 d->appearance = a;
02552
02553 setFont(font());
02554 }
02555
02556 int KexiTableView::highlightedRow() const
02557 {
02558 return d->highlightedRow;
02559 }
02560
02561 void KexiTableView::setHighlightedRow(int row)
02562 {
02563 if (row!=-1) {
02564 row = QMIN(rows() - 1 + (isInsertingEnabled()?1:0), row);
02565 row = QMAX(0, row);
02566 ensureCellVisible(row, -1);
02567 }
02568 const int previouslyHighlightedRow = d->highlightedRow;
02569 if (previouslyHighlightedRow == row) {
02570 if (previouslyHighlightedRow!=-1)
02571 updateRow(previouslyHighlightedRow);
02572 return;
02573 }
02574 d->highlightedRow = row;
02575 if (d->highlightedRow!=-1)
02576 updateRow(d->highlightedRow);
02577
02578 if (previouslyHighlightedRow!=-1)
02579 updateRow(previouslyHighlightedRow);
02580
02581 if (m_curRow>=0 && (previouslyHighlightedRow==-1 || previouslyHighlightedRow==m_curRow)
02582 && d->highlightedRow!=m_curRow && !d->appearance.persistentSelections)
02583 {
02584
02585 updateRow(m_curRow);
02586 }
02587 }
02588
02589 KexiTableItem *KexiTableView::highlightedItem() const
02590 {
02591 return d->highlightedRow == -1 ? 0 : m_data->at(d->highlightedRow);
02592 }
02593
02594 void KexiTableView::slotSettingsChanged(int category)
02595 {
02596 if (category==KApplication::SETTINGS_SHORTCUTS) {
02597 d->contextMenuKey = KGlobalSettings::contextMenuKey();
02598 }
02599 }
02600
02601 int KexiTableView::lastVisibleRow() const
02602 {
02603 return rowAt( contentsY() );
02604 }
02605
02606 #include "kexitableview.moc"
02607