kexi

kexirecordnavigator.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
00003    Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
00004 
00005    This program is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This program is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this program; see the file COPYING.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qtoolbutton.h>
00022 #include <qlayout.h>
00023 #include <qlabel.h>
00024 #include <qvalidator.h>
00025 #include <qtooltip.h>
00026 #include <qscrollview.h>
00027 
00028 #include <klocale.h>
00029 #include <kiconloader.h>
00030 #include <klineedit.h>
00031 #include <kguiitem.h>
00032 #include <kstaticdeleter.h>
00033 
00034 #include "kexirecordnavigator.h"
00035 #include "kexirecordmarker.h"
00036 
00038 class KexiRecordNavigatorPrivate
00039 {
00040     public:
00041         KexiRecordNavigatorPrivate()
00042          : handler(0)
00043          , editingIndicatorLabel(0)
00044          , editingIndicatorEnabled(false)
00045          , editingIndicatorVisible(false)
00046         {
00047         }
00048         KexiRecordNavigatorHandler *handler;
00049         QHBoxLayout *lyr;
00050 
00051         QLabel *editingIndicatorLabel;
00052         bool editingIndicatorEnabled : 1;
00053         bool editingIndicatorVisible : 1;
00054 };
00055 
00056 //--------------------------------------------------
00057 
00058 KexiRecordNavigatorHandler::KexiRecordNavigatorHandler()
00059 {
00060 }
00061 
00062 KexiRecordNavigatorHandler::~KexiRecordNavigatorHandler()
00063 {
00064 }
00065 
00066 //--------------------------------------------------
00067 
00068 KexiRecordNavigator::KexiRecordNavigator(QWidget *parent, int leftMargin, const char *name)
00069  : QFrame(parent, name)
00070  , m_view(0)
00071  , m_isInsertingEnabled(true)
00072  , d( new KexiRecordNavigatorPrivate() )
00073 {
00074     if (parent->inherits("QScrollView"))
00075         setParentView( dynamic_cast<QScrollView*>(parent) );
00076     setFrameStyle(QFrame::NoFrame);
00077     d->lyr = new QHBoxLayout(this,0,0,"nav_lyr");
00078 
00079     m_textLabel = new QLabel(this);
00080     d->lyr->addWidget( m_textLabel  );
00081     setLabelText(i18n("Row:"));
00082         
00083     int bw = 6+SmallIcon("navigator_first").width(); //QMIN( horizontalScrollBar()->height(), 20);
00084     QFont f = font();
00085     f.setPixelSize((bw > 12) ? 12 : bw);
00086     QFontMetrics fm(f);
00087     m_nav1DigitWidth = fm.width("8");
00088 
00089     d->lyr->addWidget( m_navBtnFirst = new QToolButton(this) );
00090     m_navBtnFirst->setFixedWidth(bw);
00091     m_navBtnFirst->setFocusPolicy(NoFocus);
00092     m_navBtnFirst->setIconSet( SmallIconSet("navigator_first") );
00093     QToolTip::add(m_navBtnFirst, i18n("First row"));
00094     
00095     d->lyr->addWidget( m_navBtnPrev = new QToolButton(this) );
00096     m_navBtnPrev->setFixedWidth(bw);
00097     m_navBtnPrev->setFocusPolicy(NoFocus);
00098     m_navBtnPrev->setIconSet( SmallIconSet("navigator_prev") );
00099     m_navBtnPrev->setAutoRepeat(true);
00100     QToolTip::add(m_navBtnPrev, i18n("Previous row"));
00101     
00102     d->lyr->addSpacing( 6 );
00103     
00104     d->lyr->addWidget( m_navRecordNumber = new KLineEdit(this) );
00105     m_navRecordNumber->setAlignment(AlignRight | AlignVCenter);
00106     m_navRecordNumber->setFocusPolicy(ClickFocus);
00107     m_navRecordNumber->installEventFilter(this);
00108 //  m_navRowNumber->setFixedWidth(fw);
00109     m_navRecordNumberValidator = new QIntValidator(1, INT_MAX, this);
00110     m_navRecordNumber->setValidator(m_navRecordNumberValidator);
00111     m_navRecordNumber->installEventFilter(this);
00112     QToolTip::add(m_navRecordNumber, i18n("Current row number"));
00113     
00114     KLineEdit *lbl_of = new KLineEdit(i18n("of"), this);
00115     lbl_of->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
00116     lbl_of->setMaximumWidth(fm.width(lbl_of->text())+8);
00117     lbl_of->setReadOnly(true);
00118     lbl_of->setLineWidth(0);
00119     lbl_of->setFocusPolicy(NoFocus);
00120     lbl_of->setAlignment(AlignCenter);
00121     d->lyr->addWidget( lbl_of );
00122     
00123     d->lyr->addWidget( m_navRecordCount = new KLineEdit(this) );
00124     m_navRecordCount->setSizePolicy(QSizePolicy::Fixed,QSizePolicy::Preferred);
00125     m_navRecordCount->setReadOnly(true);
00126     m_navRecordCount->setLineWidth(0);
00127     m_navRecordCount->setFocusPolicy(NoFocus);
00128     m_navRecordCount->setAlignment(AlignLeft | AlignVCenter);
00129     QToolTip::add(m_navRecordCount, i18n("Number of rows"));
00130 
00131     lbl_of->setFont(f);
00132     m_navRecordNumber->setFont(f);
00133     m_navRecordCount->setFont(f);
00134     setFont(f);
00135 
00136     d->lyr->addWidget( m_navBtnNext = new QToolButton(this) );
00137     m_navBtnNext->setFixedWidth(bw);
00138     m_navBtnNext->setFocusPolicy(NoFocus);
00139     m_navBtnNext->setIconSet( SmallIconSet("navigator_next") );
00140     m_navBtnNext->setAutoRepeat(true);
00141     QToolTip::add(m_navBtnNext, i18n("Next row"));
00142     
00143     d->lyr->addWidget( m_navBtnLast = new QToolButton(this) );
00144     m_navBtnLast->setFixedWidth(bw);
00145     m_navBtnLast->setFocusPolicy(NoFocus);
00146     m_navBtnLast->setIconSet( SmallIconSet("navigator_last") );
00147     QToolTip::add(m_navBtnLast, i18n("Last row"));
00148     
00149     d->lyr->addSpacing( 6 );
00150     d->lyr->addWidget( m_navBtnNew = new QToolButton(this) );
00151     m_navBtnNew->setFixedWidth(bw);
00152     m_navBtnNew->setFocusPolicy(NoFocus);
00153     m_navBtnNew->setIconSet( SmallIconSet("navigator_new") );
00154     QToolTip::add(m_navBtnNew, i18n("New row"));
00155     m_navBtnNext->setEnabled(isInsertingEnabled());
00156     
00157     d->lyr->addSpacing( 6 );
00158     d->lyr->addStretch(10);
00159 
00160     connect(m_navBtnPrev,SIGNAL(clicked()),this,SLOT(slotPrevButtonClicked()));
00161     connect(m_navBtnNext,SIGNAL(clicked()),this,SLOT(slotNextButtonClicked()));
00162     connect(m_navBtnLast,SIGNAL(clicked()),this,SLOT(slotLastButtonClicked()));
00163     connect(m_navBtnFirst,SIGNAL(clicked()),this,SLOT(slotFirstButtonClicked()));
00164     connect(m_navBtnNew,SIGNAL(clicked()),this,SLOT(slotNewButtonClicked()));
00165 
00166     setRecordCount(0);
00167     setCurrentRecordNumber(0);
00168 
00169     updateGeometry(leftMargin);
00170 }
00171 
00172 KexiRecordNavigator::~KexiRecordNavigator()
00173 {
00174     delete d;
00175 }
00176 
00177 void KexiRecordNavigator::setInsertingEnabled(bool set)
00178 {
00179     if (m_isInsertingEnabled==set)
00180         return;
00181     m_isInsertingEnabled = set;
00182     if (isEnabled())
00183         m_navBtnNew->setEnabled( m_isInsertingEnabled );
00184 }
00185 
00186 void KexiRecordNavigator::setEnabled( bool set )
00187 {
00188     QFrame::setEnabled(set);
00189     if (set && !m_isInsertingEnabled)
00190         m_navBtnNew->setEnabled( false );
00191 }
00192 
00193 bool KexiRecordNavigator::eventFilter( QObject *o, QEvent *e )
00194 {
00195     if (o==m_navRecordNumber) {
00196         bool recordEntered = false;
00197         bool ret;
00198         if (e->type()==QEvent::KeyPress) {
00199             QKeyEvent *ke = static_cast<QKeyEvent*>(e);
00200             switch (ke->key()) {
00201             case Qt::Key_Escape: {
00202                 ke->accept();
00203                 m_navRecordNumber->undo();
00204                 if (m_view)
00205                     m_view->setFocus();
00206                 return true;
00207             }
00208             case Qt::Key_Enter:
00209             case Qt::Key_Return:
00210             case Qt::Key_Tab:
00211             case Qt::Key_BackTab: 
00212             {
00213                 recordEntered=true;
00214                 ke->accept(); //to avoid pressing Enter later
00215                 ret = true;
00216             }
00217             default:;
00218             }
00219         }
00220         else if (e->type()==QEvent::FocusOut) {
00221             if (static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Tab
00222                 && static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Backtab
00223                 && static_cast<QFocusEvent*>(e)->reason()!=QFocusEvent::Other)
00224                 recordEntered=true;
00225             ret = false;
00226         }
00227 
00228         if (recordEntered) {
00229             bool ok=true;
00230             uint r = m_navRecordNumber->text().toUInt(&ok);
00231             if (!ok || r<1)
00232                 r = (recordCount()>0)?1:0;
00233             if (m_view && (hasFocus() || e->type()==QEvent::KeyPress))
00234                 m_view->setFocus();
00235             setCurrentRecordNumber(r);
00236             emit recordNumberEntered(r);
00237             if (d->handler)
00238                 d->handler->moveToRecordRequested(r-1);
00239             return ret;
00240         }
00241     }
00242 /*
00243     bool ok=true;
00244     int r = text.toInt(&ok);
00245     if (!ok || r<1)
00246         r = 1;
00247     emit recordNumberEntered(r);*/
00248     return false;
00249 }
00250 
00251 void KexiRecordNavigator::setCurrentRecordNumber(uint r)
00252 {
00253     uint recCnt = recordCount();
00254     if (r>(recCnt+(m_isInsertingEnabled?1:0)))
00255         r = recCnt+(m_isInsertingEnabled?1:0);
00256     QString n;
00257     if (r>0)
00258         n = QString::number(r);
00259     else
00260         n = " ";
00261 //  if (d->navRecordNumber->text().length() != n.length()) {//resize
00262 //      d->navRecordNumber->setFixedWidth(
00263 //          d->nav1DigitWidth*QMAX( QMAX(n.length(),2)+1,d->navRecordCount->text().length()+1)+6 
00264 //      );
00265 //  }
00266 
00267     m_navRecordNumber->setText(n);
00268     m_navRecordCount->deselect();
00269     updateButtons(recCnt);
00270 }
00271 
00272 void KexiRecordNavigator::updateButtons(uint recCnt)
00273 {
00274     const uint r = currentRecordNumber();
00275     if (isEnabled()) {
00276         m_navBtnPrev->setEnabled(r > 1);
00277         m_navBtnFirst->setEnabled(r > 1);
00278         m_navBtnNext->setEnabled(r > 0 
00279             && r < (recCnt +(m_isInsertingEnabled?(1+d->editingIndicatorVisible/*if we're editing, next btn is avail.*/):0) ) );
00280         m_navBtnLast->setEnabled(r!=(recCnt+(m_isInsertingEnabled?1:0)) && (m_isInsertingEnabled || recCnt>0));
00281     }
00282 }
00283 
00284 void KexiRecordNavigator::setRecordCount(uint count)
00285 {
00286     const QString & n = QString::number(count);
00287     if (m_isInsertingEnabled && currentRecordNumber()==0) {
00288         setCurrentRecordNumber(1);
00289     }
00290     if (m_navRecordCount->text().length() != n.length()) {//resize
00291         m_navRecordCount->setFixedWidth(m_nav1DigitWidth*n.length()+6);
00292         
00293         if (m_view && m_view->horizontalScrollBar()->isVisible()) {
00294             //+width of the delta
00295             resize(width()+(n.length()-m_navRecordCount->text().length())*m_nav1DigitWidth, height());
00296 //          horizontalScrollBar()->move(d->navPanel->x()+d->navPanel->width()+20,horizontalScrollBar()->y());
00297         }
00298     }
00299     //update row number widget's width
00300     const int w = m_nav1DigitWidth*QMAX( QMAX(n.length(),2)+1,m_navRecordNumber->text().length()+1)+6;
00301     if (m_navRecordNumber->width()!=w) //resize
00302         m_navRecordNumber->setFixedWidth(w);
00303 
00304     m_navRecordCount->setText(n);
00305     m_navRecordCount->deselect();
00306     if (m_view)
00307         m_view->updateScrollBars();
00308     updateButtons(recordCount());
00309 }
00310 
00311 uint KexiRecordNavigator::currentRecordNumber() const
00312 {
00313     bool ok=true;
00314     int r = m_navRecordNumber->text().toInt(&ok);
00315     if (!ok || r<1)
00316         r = 0;
00317     return r;
00318 }
00319 
00320 uint KexiRecordNavigator::recordCount() const
00321 {
00322     bool ok=true;
00323     int r = m_navRecordCount->text().toInt(&ok);
00324     if (!ok || r<1)
00325         r = 0;
00326     return r;
00327 }
00328 
00329 void KexiRecordNavigator::setParentView(QScrollView *view)
00330 {
00331     m_view = view;
00332 }
00333 
00334 void KexiRecordNavigator::updateGeometry(int leftMargin)
00335 {
00336     QFrame::updateGeometry();
00337     if (m_view) {
00338         int navWidth;
00339         if (m_view->horizontalScrollBar()->isVisible()) {
00340             navWidth = sizeHint().width();
00341         }
00342         else {
00343             navWidth = leftMargin + m_view->clipper()->width();
00344         }
00345         
00346         setGeometry(
00347             m_view->frameWidth(),
00348             m_view->height() - m_view->horizontalScrollBar()->sizeHint().height()-m_view->frameWidth(),
00349             navWidth,
00350             m_view->horizontalScrollBar()->sizeHint().height()
00351         );
00352 
00353         m_view->updateScrollBars();
00354     }
00355 }
00356 
00357 void KexiRecordNavigator::setHBarGeometry( QScrollBar & hbar, int x, int y, int w, int h )
00358 {
00359     hbar.setGeometry( x + width(), y, w - width(), h );
00360 }
00361 
00362 void KexiRecordNavigator::setLabelText(const QString& text)
00363 {
00364     m_textLabel->setText(text.isEmpty() ? QString::null : (QString::fromLatin1(" ")+text+" "));
00365 }
00366 
00367 void KexiRecordNavigator::setInsertingButtonVisible(bool set)
00368 {
00369     if (set)
00370         m_navBtnNew->show();
00371     else
00372         m_navBtnNew->hide();
00373 }
00374 
00375 void KexiRecordNavigator::slotPrevButtonClicked()
00376 {
00377     emit prevButtonClicked();
00378     if (d->handler)
00379         d->handler->moveToPreviousRecordRequested();
00380 }
00381 
00382 void KexiRecordNavigator::slotNextButtonClicked()
00383 {
00384     emit nextButtonClicked();
00385     if (d->handler)
00386         d->handler->moveToNextRecordRequested();
00387 }
00388 
00389 void KexiRecordNavigator::slotLastButtonClicked()
00390 {
00391     emit lastButtonClicked();
00392     if (d->handler)
00393         d->handler->moveToLastRecordRequested();
00394 }
00395 
00396 void KexiRecordNavigator::slotFirstButtonClicked()
00397 {
00398     emit firstButtonClicked();
00399     if (d->handler)
00400         d->handler->moveToFirstRecordRequested();
00401 }
00402 
00403 void KexiRecordNavigator::slotNewButtonClicked()
00404 {
00405     emit newButtonClicked();
00406     if (d->handler)
00407         d->handler->addNewRecordRequested();
00408 }
00409 
00410 
00411 void KexiRecordNavigator::setRecordHandler(KexiRecordNavigatorHandler *handler)
00412 {
00413     d->handler = handler;
00414 }
00415 
00416 bool KexiRecordNavigator::editingIndicatorVisible() const
00417 {
00418     return d->editingIndicatorVisible;
00419 }
00420 
00421 bool KexiRecordNavigator::editingIndicatorEnabled() const
00422 {
00423     return d->editingIndicatorEnabled;
00424 }
00425 
00426 void KexiRecordNavigator::setEditingIndicatorEnabled(bool set)
00427 {
00428     d->editingIndicatorEnabled = set;
00429     if (d->editingIndicatorEnabled) {
00430         if (!d->editingIndicatorLabel) {
00431             d->editingIndicatorLabel = new QLabel(this);
00432             d->editingIndicatorLabel->setAlignment(Qt::AlignCenter);
00433             QPixmap pix;
00434             pix.convertFromImage( *KexiRecordMarker::penImage() );
00435             d->editingIndicatorLabel->setFixedWidth( pix.width() + 2*2 );
00436             d->lyr->insertWidget( 0, d->editingIndicatorLabel );
00437         }
00438         d->editingIndicatorLabel->show();
00439     }
00440     else {
00441         if (d->editingIndicatorLabel) {
00442             d->editingIndicatorLabel->hide();
00443         }
00444     }
00445 }
00446 
00447 void KexiRecordNavigator::showEditingIndicator(bool show)
00448 {
00449     d->editingIndicatorVisible = show;
00450     updateButtons(recordCount()); //this will refresh 'next btn'
00451     if (!d->editingIndicatorEnabled)
00452         return;
00453     if (d->editingIndicatorVisible) {
00454         QPixmap pix;
00455         pix.convertFromImage( *KexiRecordMarker::penImage() );
00456         d->editingIndicatorLabel->setPixmap( pix );
00457         QToolTip::add( d->editingIndicatorLabel, i18n("Editing indicator") );
00458     }
00459     else {
00460         d->editingIndicatorLabel->setPixmap( QPixmap() );
00461         QToolTip::remove( d->editingIndicatorLabel );
00462     }
00463 }
00464 
00465 //------------------------------------------------
00466 
00468 class KexiRecordNavigatorActionsInternal {
00469     public:
00470         KexiRecordNavigatorActionsInternal()
00471          : moveToFirstRecord(i18n("First row"), "navigator_first", i18n("Go to first row"))
00472          , moveToPreviousRecord(i18n("Previous row"), "navigator_prev", i18n("Go to previous row"))
00473          , moveToNextRecord(i18n("Next row"), "navigator_next", i18n("Go to next row"))
00474          , moveToLastRecord(i18n("Last row"), "navigator_last", i18n("Go to last row"))
00475          , moveToNewRecord(i18n("New row"), "navigator_new", i18n("Go to new row"))
00476         {
00477         }
00478         static void init();
00479         KGuiItem moveToFirstRecord;
00480         KGuiItem moveToPreviousRecord;
00481         KGuiItem moveToNextRecord;
00482         KGuiItem moveToLastRecord;
00483         KGuiItem moveToNewRecord;
00484 };
00485 
00486 static KStaticDeleter<KexiRecordNavigatorActionsInternal> KexiRecordNavigatorActions_deleter;
00487 KexiRecordNavigatorActionsInternal* KexiRecordNavigatorActions_internal = 0;
00488 
00489 void KexiRecordNavigatorActionsInternal::init()
00490 {
00491     if (!KexiRecordNavigatorActions_internal)
00492         KexiRecordNavigatorActions_deleter.setObject(KexiRecordNavigatorActions_internal, 
00493             new KexiRecordNavigatorActionsInternal());
00494 }
00495 
00496 const KGuiItem& KexiRecordNavigator::Actions::moveToFirstRecord()
00497 { KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToFirstRecord; }
00498 
00499 const KGuiItem& KexiRecordNavigator::Actions::moveToPreviousRecord()
00500 { KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToPreviousRecord; }
00501 
00502 const KGuiItem& KexiRecordNavigator::Actions::moveToNextRecord()
00503 { KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToNextRecord; }
00504 
00505 const KGuiItem& KexiRecordNavigator::Actions::moveToLastRecord()
00506 { KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToLastRecord; }
00507 
00508 const KGuiItem& KexiRecordNavigator::Actions::moveToNewRecord()
00509 { KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToNewRecord; }
00510 
00511 #include "kexirecordnavigator.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys