kexirecordnavigator.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2004 Lucijan Busch <lucijan@kde.org>
3 Copyright (C) 2003-2004 Jaroslaw Staniek <js@iidea.pl>
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this program; see the file COPYING. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqtoolbutton.h>
22#include <tqlayout.h>
23#include <tqlabel.h>
24#include <tqvalidator.h>
25#include <tqtooltip.h>
26#include <tqscrollview.h>
27
28#include <tdelocale.h>
29#include <kiconloader.h>
30#include <klineedit.h>
31#include <kguiitem.h>
32#include <kstaticdeleter.h>
33
34#include "kexirecordnavigator.h"
35#include "kexirecordmarker.h"
36
38class KexiRecordNavigatorPrivate
39{
40 public:
41 KexiRecordNavigatorPrivate()
42 : handler(0)
43 , editingIndicatorLabel(0)
44 , editingIndicatorEnabled(false)
45 , editingIndicatorVisible(false)
46 {
47 }
49 TQHBoxLayout *lyr;
50
51 TQLabel *editingIndicatorLabel;
52 bool editingIndicatorEnabled : 1;
53 bool editingIndicatorVisible : 1;
54};
55
56//--------------------------------------------------
57
58KexiRecordNavigatorHandler::KexiRecordNavigatorHandler()
59{
60}
61
62KexiRecordNavigatorHandler::~KexiRecordNavigatorHandler()
63{
64}
65
66//--------------------------------------------------
67
68KexiRecordNavigator::KexiRecordNavigator(TQWidget *parent, int leftMargin, const char *name)
69 : TQFrame(parent, name)
70 , m_view(0)
71 , m_isInsertingEnabled(true)
72 , d( new KexiRecordNavigatorPrivate() )
73{
74 if (parent->inherits("TQScrollView"))
75 setParentView( dynamic_cast<TQScrollView*>(parent) );
76 setFrameStyle(TQFrame::NoFrame);
77 d->lyr = new TQHBoxLayout(this,0,0,"nav_lyr");
78
79 m_textLabel = new TQLabel(this);
80 d->lyr->addWidget( m_textLabel );
81 setLabelText(i18n("Row:"));
82
83 int bw = 6+SmallIcon("navigator_first").width(); //TQMIN( horizontalScrollBar()->height(), 20);
84 TQFont f = font();
85 f.setPixelSize((bw > 12) ? 12 : bw);
86 TQFontMetrics fm(f);
87 m_nav1DigitWidth = fm.width("8");
88
89 d->lyr->addWidget( m_navBtnFirst = new TQToolButton(this) );
90 m_navBtnFirst->setFixedWidth(bw);
91 m_navBtnFirst->setFocusPolicy(TQWidget::NoFocus);
92 m_navBtnFirst->setIconSet( SmallIconSet("navigator_first") );
93 TQToolTip::add(m_navBtnFirst, i18n("First row"));
94
95 d->lyr->addWidget( m_navBtnPrev = new TQToolButton(this) );
96 m_navBtnPrev->setFixedWidth(bw);
97 m_navBtnPrev->setFocusPolicy(TQWidget::NoFocus);
98 m_navBtnPrev->setIconSet( SmallIconSet("navigator_prev") );
99 m_navBtnPrev->setAutoRepeat(true);
100 TQToolTip::add(m_navBtnPrev, i18n("Previous row"));
101
102 d->lyr->addSpacing( 6 );
103
104 d->lyr->addWidget( m_navRecordNumber = new KLineEdit(this) );
105 m_navRecordNumber->setAlignment(AlignRight | AlignVCenter);
106 m_navRecordNumber->setFocusPolicy(TQWidget::ClickFocus);
107 m_navRecordNumber->installEventFilter(this);
108// m_navRowNumber->setFixedWidth(fw);
109 m_navRecordNumberValidator = new TQIntValidator(1, INT_MAX, this);
110 m_navRecordNumber->setValidator(m_navRecordNumberValidator);
111 m_navRecordNumber->installEventFilter(this);
112 TQToolTip::add(m_navRecordNumber, i18n("Current row number"));
113
114 KLineEdit *lbl_of = new KLineEdit(i18n("of"), this);
115 lbl_of->setSizePolicy(TQSizePolicy::Fixed,TQSizePolicy::Preferred);
116 lbl_of->setMaximumWidth(fm.width(lbl_of->text())+8);
117 lbl_of->setReadOnly(true);
118 lbl_of->setLineWidth(0);
119 lbl_of->setFocusPolicy(TQWidget::NoFocus);
120 lbl_of->setAlignment(AlignCenter);
121 d->lyr->addWidget( lbl_of );
122
123 d->lyr->addWidget( m_navRecordCount = new KLineEdit(this) );
124 m_navRecordCount->setSizePolicy(TQSizePolicy::Fixed,TQSizePolicy::Preferred);
125 m_navRecordCount->setReadOnly(true);
126 m_navRecordCount->setLineWidth(0);
127 m_navRecordCount->setFocusPolicy(TQWidget::NoFocus);
128 m_navRecordCount->setAlignment(AlignLeft | AlignVCenter);
129 TQToolTip::add(m_navRecordCount, i18n("Number of rows"));
130
131 lbl_of->setFont(f);
132 m_navRecordNumber->setFont(f);
133 m_navRecordCount->setFont(f);
134 setFont(f);
135
136 d->lyr->addWidget( m_navBtnNext = new TQToolButton(this) );
137 m_navBtnNext->setFixedWidth(bw);
138 m_navBtnNext->setFocusPolicy(TQWidget::NoFocus);
139 m_navBtnNext->setIconSet( SmallIconSet("navigator_next") );
140 m_navBtnNext->setAutoRepeat(true);
141 TQToolTip::add(m_navBtnNext, i18n("Next row"));
142
143 d->lyr->addWidget( m_navBtnLast = new TQToolButton(this) );
144 m_navBtnLast->setFixedWidth(bw);
145 m_navBtnLast->setFocusPolicy(TQWidget::NoFocus);
146 m_navBtnLast->setIconSet( SmallIconSet("navigator_last") );
147 TQToolTip::add(m_navBtnLast, i18n("Last row"));
148
149 d->lyr->addSpacing( 6 );
150 d->lyr->addWidget( m_navBtnNew = new TQToolButton(this) );
151 m_navBtnNew->setFixedWidth(bw);
152 m_navBtnNew->setFocusPolicy(TQWidget::NoFocus);
153 m_navBtnNew->setIconSet( SmallIconSet("navigator_new") );
154 TQToolTip::add(m_navBtnNew, i18n("New row"));
155 m_navBtnNext->setEnabled(isInsertingEnabled());
156
157 d->lyr->addSpacing( 6 );
158 d->lyr->addStretch(10);
159
160 connect(m_navBtnPrev,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotPrevButtonClicked()));
161 connect(m_navBtnNext,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotNextButtonClicked()));
162 connect(m_navBtnLast,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotLastButtonClicked()));
163 connect(m_navBtnFirst,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotFirstButtonClicked()));
164 connect(m_navBtnNew,TQ_SIGNAL(clicked()),this,TQ_SLOT(slotNewButtonClicked()));
165
166 setRecordCount(0);
167 setCurrentRecordNumber(0);
168
169 updateGeometry(leftMargin);
170}
171
172KexiRecordNavigator::~KexiRecordNavigator()
173{
174 delete d;
175}
176
178{
179 if (m_isInsertingEnabled==set)
180 return;
181 m_isInsertingEnabled = set;
182 if (isEnabled())
183 m_navBtnNew->setEnabled( m_isInsertingEnabled );
184}
185
186void KexiRecordNavigator::setEnabled( bool set )
187{
188 TQFrame::setEnabled(set);
189 if (set && !m_isInsertingEnabled)
190 m_navBtnNew->setEnabled( false );
191}
192
193bool KexiRecordNavigator::eventFilter( TQObject *o, TQEvent *e )
194{
195 if (o==m_navRecordNumber) {
196 bool recordEntered = false;
197 bool ret;
198 if (e->type()==TQEvent::KeyPress) {
199 TQKeyEvent *ke = static_cast<TQKeyEvent*>(e);
200 switch (ke->key()) {
201 case TQt::Key_Escape: {
202 ke->accept();
203 m_navRecordNumber->undo();
204 if (m_view)
205 m_view->setFocus();
206 return true;
207 }
208 case TQt::Key_Enter:
209 case TQt::Key_Return:
210 case TQt::Key_Tab:
211 case TQt::Key_BackTab:
212 {
213 recordEntered=true;
214 ke->accept(); //to avoid pressing Enter later
215 ret = true;
216 }
217 default:;
218 }
219 }
220 else if (e->type()==TQEvent::FocusOut) {
221 if (static_cast<TQFocusEvent*>(e)->reason()!=TQFocusEvent::Tab
222 && static_cast<TQFocusEvent*>(e)->reason()!=TQFocusEvent::Backtab
223 && static_cast<TQFocusEvent*>(e)->reason()!=TQFocusEvent::Other)
224 recordEntered=true;
225 ret = false;
226 }
227
228 if (recordEntered) {
229 bool ok=true;
230 uint r = m_navRecordNumber->text().toUInt(&ok);
231 if (!ok || r<1)
232 r = (recordCount()>0)?1:0;
233 if (m_view && (hasFocus() || e->type()==TQEvent::KeyPress))
234 m_view->setFocus();
236 emit recordNumberEntered(r);
237 if (d->handler)
238 d->handler->moveToRecordRequested(r-1);
239 return ret;
240 }
241 }
242/*
243 bool ok=true;
244 int r = text.toInt(&ok);
245 if (!ok || r<1)
246 r = 1;
247 emit recordNumberEntered(r);*/
248 return false;
249}
250
252{
253 uint recCnt = recordCount();
254 if (r>(recCnt+(m_isInsertingEnabled?1:0)))
255 r = recCnt+(m_isInsertingEnabled?1:0);
256 TQString n;
257 if (r>0)
258 n = TQString::number(r);
259 else
260 n = " ";
261// if (d->navRecordNumber->text().length() != n.length()) {//resize
262// d->navRecordNumber->setFixedWidth(
263// d->nav1DigitWidth*TQMAX( TQMAX(n.length(),2)+1,d->navRecordCount->text().length()+1)+6
264// );
265// }
266
267 m_navRecordNumber->setText(n);
268 m_navRecordCount->deselect();
269 updateButtons(recCnt);
270}
271
272void KexiRecordNavigator::updateButtons(uint recCnt)
273{
274 const uint r = currentRecordNumber();
275 if (isEnabled()) {
276 m_navBtnPrev->setEnabled(r > 1);
277 m_navBtnFirst->setEnabled(r > 1);
278 m_navBtnNext->setEnabled(r > 0
279 && r < (recCnt +(m_isInsertingEnabled?(1+d->editingIndicatorVisible/*if we're editing, next btn is avail.*/):0) ) );
280 m_navBtnLast->setEnabled(r!=(recCnt+(m_isInsertingEnabled?1:0)) && (m_isInsertingEnabled || recCnt>0));
281 }
282}
283
285{
286 const TQString & n = TQString::number(count);
287 if (m_isInsertingEnabled && currentRecordNumber()==0) {
289 }
290 if (m_navRecordCount->text().length() != n.length()) {//resize
291 m_navRecordCount->setFixedWidth(m_nav1DigitWidth*n.length()+6);
292
293 if (m_view && m_view->horizontalScrollBar()->isVisible()) {
294 //+width of the delta
295 resize(width()+(n.length()-m_navRecordCount->text().length())*m_nav1DigitWidth, height());
296// horizontalScrollBar()->move(d->navPanel->x()+d->navPanel->width()+20,horizontalScrollBar()->y());
297 }
298 }
299 //update row number widget's width
300 const int w = m_nav1DigitWidth*TQMAX( TQMAX(n.length(),2)+1,m_navRecordNumber->text().length()+1)+6;
301 if (m_navRecordNumber->width()!=w) //resize
302 m_navRecordNumber->setFixedWidth(w);
303
304 m_navRecordCount->setText(n);
305 m_navRecordCount->deselect();
306 if (m_view)
307 m_view->updateScrollBars();
308 updateButtons(recordCount());
309}
310
312{
313 bool ok=true;
314 int r = m_navRecordNumber->text().toInt(&ok);
315 if (!ok || r<1)
316 r = 0;
317 return r;
318}
319
321{
322 bool ok=true;
323 int r = m_navRecordCount->text().toInt(&ok);
324 if (!ok || r<1)
325 r = 0;
326 return r;
327}
328
329void KexiRecordNavigator::setParentView(TQScrollView *view)
330{
331 m_view = view;
332}
333
334void KexiRecordNavigator::updateGeometry(int leftMargin)
335{
336 TQFrame::updateGeometry();
337 if (m_view) {
338 int navWidth;
339 if (m_view->horizontalScrollBar()->isVisible()) {
340 navWidth = sizeHint().width();
341 }
342 else {
343 navWidth = leftMargin + m_view->clipper()->width();
344 }
345
346 setGeometry(
347 m_view->frameWidth(),
348 m_view->height() - m_view->horizontalScrollBar()->sizeHint().height()-m_view->frameWidth(),
349 navWidth,
350 m_view->horizontalScrollBar()->sizeHint().height()
351 );
352
353 m_view->updateScrollBars();
354 }
355}
356
357void KexiRecordNavigator::setHBarGeometry( TQScrollBar & hbar, int x, int y, int w, int h )
358{
359 hbar.setGeometry( x + width(), y, w - width(), h );
360}
361
362void KexiRecordNavigator::setLabelText(const TQString& text)
363{
364 m_textLabel->setText(text.isEmpty() ? TQString() : (TQString::fromLatin1(" ")+text+" "));
365}
366
368{
369 if (set)
370 m_navBtnNew->show();
371 else
372 m_navBtnNew->hide();
373}
374
375void KexiRecordNavigator::slotPrevButtonClicked()
376{
377 emit prevButtonClicked();
378 if (d->handler)
379 d->handler->moveToPreviousRecordRequested();
380}
381
382void KexiRecordNavigator::slotNextButtonClicked()
383{
384 emit nextButtonClicked();
385 if (d->handler)
386 d->handler->moveToNextRecordRequested();
387}
388
389void KexiRecordNavigator::slotLastButtonClicked()
390{
391 emit lastButtonClicked();
392 if (d->handler)
393 d->handler->moveToLastRecordRequested();
394}
395
396void KexiRecordNavigator::slotFirstButtonClicked()
397{
398 emit firstButtonClicked();
399 if (d->handler)
400 d->handler->moveToFirstRecordRequested();
401}
402
403void KexiRecordNavigator::slotNewButtonClicked()
404{
405 emit newButtonClicked();
406 if (d->handler)
407 d->handler->addNewRecordRequested();
408}
409
410
412{
413 d->handler = handler;
414}
415
417{
418 return d->editingIndicatorVisible;
419}
420
422{
423 return d->editingIndicatorEnabled;
424}
425
427{
428 d->editingIndicatorEnabled = set;
429 if (d->editingIndicatorEnabled) {
430 if (!d->editingIndicatorLabel) {
431 d->editingIndicatorLabel = new TQLabel(this);
432 d->editingIndicatorLabel->setAlignment(TQt::AlignCenter);
433 TQPixmap pix;
434 pix.convertFromImage( *KexiRecordMarker::penImage() );
435 d->editingIndicatorLabel->setFixedWidth( pix.width() + 2*2 );
436 d->lyr->insertWidget( 0, d->editingIndicatorLabel );
437 }
438 d->editingIndicatorLabel->show();
439 }
440 else {
441 if (d->editingIndicatorLabel) {
442 d->editingIndicatorLabel->hide();
443 }
444 }
445}
446
448{
449 d->editingIndicatorVisible = show;
450 updateButtons(recordCount()); //this will refresh 'next btn'
451 if (!d->editingIndicatorEnabled)
452 return;
453 if (d->editingIndicatorVisible) {
454 TQPixmap pix;
455 pix.convertFromImage( *KexiRecordMarker::penImage() );
456 d->editingIndicatorLabel->setPixmap( pix );
457 TQToolTip::add( d->editingIndicatorLabel, i18n("Editing indicator") );
458 }
459 else {
460 d->editingIndicatorLabel->setPixmap( TQPixmap() );
461 TQToolTip::remove( d->editingIndicatorLabel );
462 }
463}
464
465//------------------------------------------------
466
468class KexiRecordNavigatorActionsInternal {
469 public:
470 KexiRecordNavigatorActionsInternal()
471 : moveToFirstRecord(i18n("First row"), "navigator_first", i18n("Go to first row"))
472 , moveToPreviousRecord(i18n("Previous row"), "navigator_prev", i18n("Go to previous row"))
473 , moveToNextRecord(i18n("Next row"), "navigator_next", i18n("Go to next row"))
474 , moveToLastRecord(i18n("Last row"), "navigator_last", i18n("Go to last row"))
475 , moveToNewRecord(i18n("New row"), "navigator_new", i18n("Go to new row"))
476 {
477 }
478 static void init();
479 KGuiItem moveToFirstRecord;
480 KGuiItem moveToPreviousRecord;
481 KGuiItem moveToNextRecord;
482 KGuiItem moveToLastRecord;
483 KGuiItem moveToNewRecord;
484};
485
486static KStaticDeleter<KexiRecordNavigatorActionsInternal> KexiRecordNavigatorActions_deleter;
487KexiRecordNavigatorActionsInternal* KexiRecordNavigatorActions_internal = 0;
488
489void KexiRecordNavigatorActionsInternal::init()
490{
491 if (!KexiRecordNavigatorActions_internal)
492 KexiRecordNavigatorActions_deleter.setObject(KexiRecordNavigatorActions_internal,
493 new KexiRecordNavigatorActionsInternal());
494}
495
496const KGuiItem& KexiRecordNavigator::Actions::moveToFirstRecord()
497{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToFirstRecord; }
498
499const KGuiItem& KexiRecordNavigator::Actions::moveToPreviousRecord()
500{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToPreviousRecord; }
501
502const KGuiItem& KexiRecordNavigator::Actions::moveToNextRecord()
503{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToNextRecord; }
504
505const KGuiItem& KexiRecordNavigator::Actions::moveToLastRecord()
506{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToLastRecord; }
507
508const KGuiItem& KexiRecordNavigator::Actions::moveToNewRecord()
509{ KexiRecordNavigatorActionsInternal::init(); return KexiRecordNavigatorActions_internal->moveToNewRecord; }
510
511#include "kexirecordnavigator.moc"
KexiRecordNavigatorHandler interface handles requests generated by KexiRecordNavigator.
void setInsertingButtonVisible(bool set)
void setLabelText(const TQString &text)
void showEditingIndicator(bool show)
void setInsertingEnabled(bool set)
void setEditingIndicatorEnabled(bool set)
void setRecordCount(uint count)
void setHBarGeometry(TQScrollBar &hbar, int x, int y, int w, int h)
void setRecordHandler(KexiRecordNavigatorHandler *handler)
KLineEdit * m_navRecordCount
readonly counter