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