1 /***************************************************************************
2 kraftview.cpp - Interactive document view
3 -------------------
4 begin : Mit Dez 31 19:24:05 CET 2003
5 copyright : (C) 2003 by Klaas Freitag
6 email : freitag@kde.org
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 // include files for Qt
19 #include <QLayout>
20 #include <QLabel>
21 #include <QScrollArea>
22 #include <QStackedWidget>
23 #include <QSizePolicy>
24 #include <QTextEdit>
25 #include <QSignalMapper>
26 #include <QTabWidget>
27 #include <QColor>
28 #include <QSplitter>
29 #include <QToolTip>
30 #include <QFont>
31 #include <QResizeEvent>
32 #include <QPalette>
33 #include <QTimer>
34 #include <QScrollBar>
35 #include <QComboBox>
36 #include <QDateTimeEdit>
37 #include <QMessageBox>
38
39 #include <QDebug>
40 #include <QDialog>
41 #include <QDialogButtonBox>
42 #include <QPushButton>
43 #include <QVBoxLayout>
44
45 // application specific includes
46 #include "kraftdb.h"
47 #include "kraftsettings.h"
48 #include "kraftview.h"
49 #include "kraftdoc.h"
50 #include "ui_docheader.h"
51 #include "documentman.h"
52 #include "docassistant.h"
53 #include "positionviewwidget.h"
54 #include "ui_docfooter.h"
55 #include "docposition.h"
56 #include "unitmanager.h"
57 #include "docpostcard.h"
58 #include "kataloglistview.h"
59 #include "katalogman.h"
60 #include "templkatalog.h"
61 #include "templkataloglistview.h"
62 #include "catalogselection.h"
63 #include "kraftdocheaderedit.h"
64 #include "kraftdocpositionsedit.h"
65 #include "kraftdocfooteredit.h"
66 #include "inserttempldialog.h"
67 #include "defaultprovider.h"
68 #include "stockmaterial.h"
69 #include "templtopositiondialogbase.h"
70 #include "doctype.h"
71 #include "catalogtemplate.h"
72 #include "importitemdialog.h"
73 #include "addressprovider.h"
74 #include "addressselectordialog.h"
75 #include "format.h"
76
77 #define NO_TAX 0
78 #define RED_TAX 1
79 #define FULL_TAX 2
80 #define INDI_TAX 3
81
KraftView(QWidget * parent)82 KraftView::KraftView(QWidget *parent) :
83 KraftViewBase( parent ),
84 mHelpLabel(nullptr), mRememberAmount( -1 ), mModified( false ),
85 mTaxBefore( -1 ), mDocPosEditorIndx( -1 )
86 {
87 setWindowTitle( i18n("Document" ) );
88 setModal( false );
89 QVBoxLayout *mainLayout = new QVBoxLayout;
90 setLayout(mainLayout);
91
92
93 mDetailHeader = new QLabel;
94 mDetailHeader->setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Fixed ) );
95 mDetailHeader->setFrameStyle( QFrame::Box + QFrame::Plain );
96 mDetailHeader->setLineWidth( 1 );
97 mDetailHeader->setAutoFillBackground(true);
98
99 mAddressProvider = new AddressProvider( this );
100 connect( mAddressProvider, SIGNAL(lookupResult(QString,KContacts::Addressee)),
101 this, SLOT( slotAddresseeFound(QString,KContacts::Addressee)));
102
103 QPalette palette;
104 palette.setColor(mDetailHeader->backgroundRole(), QColor( "darkBlue" ));
105 palette.setColor(mDetailHeader->foregroundRole(), QColor( "white "));
106 mDetailHeader->setPalette( palette );
107 mDetailHeader->setTextFormat( Qt::PlainText );
108 mDetailHeader->setFixedHeight( 40 ); // FIXME
109 QFont f = mDetailHeader->font();
110 f.setPointSize( qRound( 1.4 * f.pointSize() ) );
111 f.setBold( true );
112 mDetailHeader->setFont( f );
113 mainLayout->addWidget( mDetailHeader );
114
115 mCSplit = new QSplitter(this);
116 mainLayout->addWidget( mCSplit );
117
118 mViewStack = new QStackedWidget;
119 mCSplit->addWidget( mViewStack );
120
121 // qDebug () << "mViewSTack height is " << mViewStack->height() << endl;
122
123 mAssistant = new DocAssistant( mCSplit );
124 mCSplit->addWidget( mAssistant );
125
126 /* catalog template selection signal */
127 connect(mAssistant, &DocAssistant::templatesToDocument,
128 this, &KraftView::slotAddItems);
129
130 /* signal to toggle the visibility of the template section in the assistant */
131 connect( mAssistant, SIGNAL( toggleShowTemplates( bool ) ),
132 this, SLOT( slotShowTemplates( bool ) ) );
133
134 /* signal that brings a new address to the document */
135 connect( mAssistant, SIGNAL( headerTextTemplate( const QString& ) ),
136 this, SLOT( slotNewHeaderText( const QString& ) ) );
137
138 connect( mAssistant, SIGNAL( footerTextTemplate( const QString& ) ),
139 this, SLOT( slotNewFooterText( const QString& ) ) );
140
141 connect( mAssistant, SIGNAL( selectPage( int ) ),
142 this, SLOT( slotSwitchToPage( int ) ) );
143
144 mAssistant->slotSelectDocPart( KraftDoc::Header );
145
146 setupMappers();
147
148 QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel);
149 QPushButton *okButton = buttonBox->button(QDialogButtonBox::Ok);
150 okButton->setDefault(true);
151 okButton->setShortcut(Qt::CTRL | Qt::Key_Return);
152 connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
153 connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
154 mainLayout->addWidget(buttonBox);
155
156
157 }
158
~KraftView()159 KraftView::~KraftView()
160 {
161 // qDebug () << "KRAFTVIEW going away." << endl;
162 }
163
setupMappers()164 void KraftView::setupMappers()
165 {
166
167 mDeleteMapper = new QSignalMapper( this );
168 connect( mDeleteMapper, SIGNAL( mapped(int)),
169 this, SLOT( slotDeletePosition( int ) ) );
170
171 mMoveUpMapper = new QSignalMapper( this );
172 connect( mMoveUpMapper, SIGNAL( mapped(int)),
173 this, SLOT( slotMovePositionUp( int ) ) );
174
175 mMoveDownMapper = new QSignalMapper( this );
176 connect( mMoveDownMapper, SIGNAL( mapped(int)),
177 this, SLOT( slotMovePositionDown( int ) ) );
178
179 mLockPositionMapper = new QSignalMapper( this );
180 connect( mLockPositionMapper, SIGNAL( mapped( int )),
181 this, SLOT( slotLockPosition( int ) ) );
182
183 mUnlockPositionMapper = new QSignalMapper( this );
184 connect( mUnlockPositionMapper, SIGNAL( mapped( int )),
185 this, SLOT( slotUnlockPosition( int ) ) );
186
187 mModifiedMapper = new QSignalMapper( this );
188 connect( mModifiedMapper, SIGNAL( mapped( int ) ),
189 this, SLOT( slotPositionModified( int ) ) );
190 // block signals as long as the widget is built up.
191 // unblocking happens in redrawDocument()
192 mModifiedMapper->blockSignals(true);
193 }
194
setup(DocGuardedPtr doc)195 void KraftView::setup( DocGuardedPtr doc )
196 {
197 KraftViewBase::setup(doc);
198
199 if ( KraftSettings::self()->docViewSplitter().count() == 2 ) {
200 mCSplit->setSizes( KraftSettings::self()->docViewSplitter() );
201 }
202
203 setupDocHeaderView();
204 setupItems();
205 setupFooter();
206 setWindowTitle( m_doc->docIdentifier() );
207 slotSwitchToPage( KraftDoc::Header );
208
209 if( doc->isNew() ) {
210 mModified = true;
211 }
212 }
213
214
slotSwitchToPage(int id)215 void KraftView::slotSwitchToPage( int id )
216 {
217 // check if the wanted part is already visible
218 if ( mViewStack->currentWidget() == mViewStack->widget( id ) ) return;
219
220
221 mViewStack->setCurrentIndex( id );
222
223 KraftDocEdit *edit =
224 static_cast<KraftDocEdit *>( mViewStack->currentWidget() );
225
226 mDetailHeader->setText( edit->title() );
227
228 QPalette palette;
229 palette.setColor(mDetailHeader->backgroundRole(), edit->color());
230 // FIXME: color
231 palette.setColor(mDetailHeader->foregroundRole(), QColor( "#00008b" ));
232 mDetailHeader->setPalette( palette );
233
234 mAssistant->slotSelectDocPart( mViewStack->currentIndex() );
235 }
236
slotShowTemplates(bool)237 void KraftView::slotShowTemplates( bool )
238 {
239 }
240
setupDocHeaderView()241 void KraftView::setupDocHeaderView()
242 {
243 KraftDocHeaderEdit *edit = new KraftDocHeaderEdit(this);
244
245 mHeaderId = mViewStack->addWidget( edit ); // , KraftDoc::Header );
246
247 m_headerEdit = edit->docHeaderEdit();
248
249 m_headerEdit->m_cbType->clear();
250 // m_headerEdit->m_cbType->insertStringList( DefaultProvider::self()->docTypes() );
251 m_headerEdit->m_cbType->insertItems(-1, DocType::allLocalised() );
252 m_headerEdit->mButtLang->hide();
253
254 const QString predecessorDbId = m_doc->predecessorDbId();
255 bool predecIsVisible = false;
256 if( !predecessorDbId.isEmpty() ) {
257 DocGuardedPtr predecDoc = DocumentMan::self()->openDocument(predecessorDbId);
258 if( predecDoc ) {
259 const QString id = predecDoc->docIdentifier();
260 const QString link = QString("<a href=\"doc://show?id=%1\">%2</a>").arg(predecessorDbId).arg(id);
261 m_headerEdit->_labFollowup->setText( i18n("Successor of %1", link));
262 predecIsVisible = true;
263 connect( m_headerEdit->_labFollowup, SIGNAL(linkActivated(QString)),
264 this, SLOT(slotLinkClicked(QString)));
265 delete predecDoc;
266 }
267 }
268 m_headerEdit->_labFollowup->setVisible(predecIsVisible);
269
270 connect( m_headerEdit->m_cbType, SIGNAL( activated( const QString& ) ),
271 this, SLOT( slotDocTypeChanged( const QString& ) ) );
272
273 connect( m_headerEdit->mButtLang, SIGNAL( clicked() ),
274 this, SLOT( slotLanguageSettings() ) );
275 connect( edit, SIGNAL( modified() ),
276 this, SLOT( slotModifiedHeader() ) );
277 connect( edit, SIGNAL(pickAddressee()), this, SLOT(slotPickAddressee()) );
278 }
279
slotLinkClicked(const QString & link)280 void KraftView::slotLinkClicked(const QString& link)
281 {
282 QUrl u(link);
283 if( u.scheme() == "doc" && u.host() == "show" ) {
284 const QString ident = u.queryItemValue("id");
285 qDebug() << "Link clicked to open document " << ident;
286 emit openROView( ident );
287 }
288 }
289
setupItems()290 void KraftView::setupItems()
291 {
292 KraftDocPositionsEdit *edit = new KraftDocPositionsEdit(this);
293 mDocPosEditorIndx = mViewStack->addWidget( edit ); // , KraftDoc::Positions );
294
295 m_positionScroll = edit->positionScroll();
296
297 connect( edit, SIGNAL( addPositionClicked() ), SLOT( slotAddNewItem() ) );
298 connect( edit, SIGNAL( addExtraClicked() ), SLOT( slotAddExtraPosition() ) );
299 connect( edit, SIGNAL( importItemsClicked() ), SLOT( slotImportItems() ) );
300
301 }
302
redrawDocument()303 void KraftView::redrawDocument( )
304 {
305 KraftDoc *doc = getDocument();
306 if( !doc ) {
307 // qDebug () << "ERR: No document available in view, return!" << endl;
308 } else {
309 // qDebug () << "** Starting redraw of document " << doc << endl;
310 }
311
312 /* header: date and document type */
313 QDate date = doc->date();
314 m_headerEdit->m_dateEdit->setDate( date );
315 m_headerEdit->m_cbType->setCurrentIndex(m_headerEdit->m_cbType->findText( doc->docType() ));
316
317 /* header: address */
318 mContactUid = doc->addressUid();
319 QString address = doc->address();
320
321 // qDebug () << "Loaded address uid from database " << mContactUid << endl;
322 if( ! mContactUid.isEmpty() ) {
323 mAddressProvider->lookupAddressee( mContactUid );
324 }
325
326 if( !address.isEmpty() ) {
327 // custom address stored in the document.
328 // qDebug() << "custom address came in: " << address << endl;
329 m_headerEdit->m_postAddressEdit->setText( address );
330 }
331
332 if( !doc->salut().isEmpty() ) {
333 m_headerEdit->m_letterHead->insertItem(-1, doc->salut() );
334 m_headerEdit->m_letterHead->setCurrentIndex(m_headerEdit->m_letterHead->findText( doc->salut() ));
335 }
336 /* pre- and post text */
337 m_headerEdit->m_teEntry->setText( doc->preText() );
338 m_headerEdit->m_whiteboardEdit->setText( doc->whiteboard() );
339 m_headerEdit->mProjectLabelEdit->setText( doc->projectLabel() );
340 m_footerEdit->ui()->m_teSummary->setText( doc->postText() );
341 const QString goodbye = doc->goodbye();
342 m_footerEdit->slotSetGreeting(goodbye);
343
344 mAssistant->slotSetDocType( doc->docType() );
345
346 redrawDocPositions( );
347 slotDocTypeChanged( doc->docType() );
348 refreshPostCard();
349 mModifiedMapper->blockSignals(false);
350
351 // mModified = false;
352 }
353
slotPickAddressee()354 void KraftView::slotPickAddressee()
355 {
356 AddressSelectorDialog dialog(this);
357
358 if( dialog.exec() ) {
359 const KContacts::Addressee contact = dialog.addressee();
360 slotNewAddress( contact );
361 }
362 }
363
slotAddresseeFound(const QString & uid,const KContacts::Addressee & contact)364 void KraftView::slotAddresseeFound( const QString& uid, const KContacts::Addressee& contact )
365 {
366 if( contact.isEmpty() ) {
367 const QString err = mAddressProvider->errorMsg(uid);
368 if( !err.isEmpty() ) {
369 qDebug () << "Error while looking up address for uid" << uid << ":" << err;
370 }
371 } else {
372 slotNewAddress( contact, false );
373 qDebug () << "No contact found for uid " << uid;
374 }
375 }
376
slotNewAddress(const KContacts::Addressee & contact,bool interactive)377 void KraftView::slotNewAddress( const KContacts::Addressee& contact, bool interactive )
378 {
379
380 Addressee adr( contact );
381
382 if( contact.isEmpty() ) {
383 return;
384 }
385 QString newAddress = mAddressProvider->formattedAddress( contact );
386 const QString currAddress = m_headerEdit->m_postAddressEdit->toPlainText();
387
388 bool replace = true;
389 m_headerEdit->m_labName->setText( contact.realName() );
390
391 if( currAddress.isEmpty() ) {
392 replace = true;
393 } else if( currAddress != newAddress ) {
394 // non empty and current different from new address
395 // need to ask first if we overwrite
396 if( interactive ) {
397 QMessageBox msgBox;
398 msgBox.setText(i18n( "The address label is not empty and different from the selected one.<br/>"
399 "Do you really want to replace it with the text shown below?<pre>%1</pre>", newAddress));
400
401 msgBox.setStandardButtons(QMessageBox::Yes| QMessageBox::No);
402 msgBox.setDefaultButton(QMessageBox::Yes);
403 int ret = msgBox.exec();
404
405 if ( ret != QMessageBox::Yes) {
406 replace = false;
407 }
408 } else {
409 // this happens when the document is loaded and the address arrives from addressbook
410 replace = false;
411 }
412 } else if( currAddress == newAddress ) {
413 // both are equal, no action needed
414 replace = false;
415 }
416
417 if( replace ) {
418 mContactUid = contact.uid();
419
420 m_headerEdit->m_postAddressEdit->setText( newAddress );
421
422 // Generate the welcome
423 m_headerEdit->m_letterHead->clear();
424 QStringList li = generateLetterHead(adr.familyName(), adr.givenName());
425
426 m_headerEdit->m_letterHead->insertItems(-1, li );
427 m_headerEdit->m_letterHead->setCurrentIndex( KraftSettings::self()->salut() );
428 }
429 }
430
redrawDocPositions()431 void KraftView::redrawDocPositions( )
432 {
433 // If there is no position yet, come up with a help message.
434 KraftDoc *doc = getDocument();
435 if ( ! doc ) return;
436
437 DocPositionList list = doc->positions();
438 if ( list.count() == 0 ) {
439 // the doc has no positions yet. Let's show a help page
440 if ( ! mHelpLabel ) {
441 mHelpLabel = new QLabel(this);
442 mHelpLabel->setTextFormat(Qt::RichText);
443 // mHelpLabel->setMinimumHeight(400);
444 //TODO PORT QT5 mHelpLabel->setMargin( QDialog::marginHint() );
445 mHelpLabel->setText( i18n( "<qt><h2>The Document Items List is still empty, but Items "
446 "can be added now.</h2>"
447 "To add items to the document either "
448 "<ul>"
449 "<li>Press the 'Add item' button above.</li>"
450 "<li>Open the template catalog by clicking on the 'show Template' "
451 "button on the right and pick one of the available templates.</li>"
452 "</ul></qt>" ) );
453 mHelpLabel->setWordWrap(true);
454 mHelpLabel->setMinimumHeight(200);
455 m_positionScroll->addChild( mHelpLabel, 0);
456 }
457 return;
458
459 } else {
460 if ( mHelpLabel ) {
461 delete mHelpLabel;
462 mHelpLabel = nullptr;
463 }
464 }
465
466 // qDebug () << "starting to redraw " << list.count() << " positions!";
467 int cnt = 0;
468 DocPositionListIterator it( list );
469 while( it.hasNext() ) {
470 DocPositionBase *dp = it.next();
471 PositionViewWidget *w = mPositionWidgetList.widgetFromPosition( dp );
472 if( !w ) {
473 w = createPositionViewWidget( dp, cnt);
474 w->slotAllowIndividualTax( currentTaxSetting() == DocPositionBase::TaxIndividual );
475 }
476 cnt++;
477 // qDebug () << "now position " << dp->positionNumber() << endl;
478 }
479
480 // now go through the positionWidgetMap and check if it contains elements
481 // that are not any longer in the list of positions
482
483 QMutableListIterator<PositionViewWidget*> it2( mPositionWidgetList );
484 while( it2.hasNext() ) {
485 PositionViewWidget *w = it2.next();
486
487 if( w && (list.contains( w->position() ) == 0) ) {
488 // qDebug () << "Removing this one: " << w << endl;
489 m_positionScroll->removeChild( w );
490 it2.remove();
491 // mPositionWidgetList.erase( it2 );
492 break;
493 }
494 }
495 }
496
setMappingId(QWidget * widget,int pos)497 void KraftView::setMappingId( QWidget *widget, int pos )
498 {
499 mDeleteMapper->setMapping( widget, pos );
500 mMoveUpMapper->setMapping( widget, pos );
501 mMoveDownMapper->setMapping( widget, pos );
502 mLockPositionMapper->setMapping( widget, pos );
503 mUnlockPositionMapper->setMapping( widget, pos );
504 mModifiedMapper->setMapping( widget, pos );
505 }
506
507 //
508 // create a new position widget.
509 // The position parameter comes in as list counter, starting at 0
510
createPositionViewWidget(DocPositionBase * dp,int pos)511 PositionViewWidget *KraftView::createPositionViewWidget( DocPositionBase *dp, int pos )
512 {
513 PositionViewWidget *w = new PositionViewWidget( );
514
515 int cw = m_positionScroll->width();
516 if ( cw < 400 ) cw = 400;
517 w->resize( cw, w->height() );
518
519 connect( w, SIGNAL( deletePosition() ), mDeleteMapper, SLOT( map() ) );
520 connect( w, SIGNAL( moveUp() ), mMoveUpMapper, SLOT( map() ) );
521 connect( w, SIGNAL( moveDown() ), mMoveDownMapper, SLOT( map() ) );
522 connect( w, SIGNAL( lockPosition() ), mLockPositionMapper, SLOT( map() ) );
523 connect( w, SIGNAL( unlockPosition() ), mUnlockPositionMapper, SLOT( map() ) );
524 connect( w, SIGNAL( positionModified()), mModifiedMapper, SLOT( map() ) );
525
526 setMappingId( w, pos );
527
528 QStringList units = UnitManager::self()->allUnits();
529 units.sort();
530 w->m_cbUnit->addItems(units);
531
532 if( dp->dbId().toInt() < 0 ) {
533 w->slotSetState( PositionViewWidget::New );
534 }
535
536 /* do resizing and add the widget to the scrollview and move it to the final place */
537
538 if ( mHelpLabel ) {
539 mHelpLabel->hide();
540 }
541
542 mPositionWidgetList.insert( pos, w );
543 m_positionScroll->addChild( w, pos );
544
545 //Set the correct indexes when the widget is not appended
546 if(pos < mPositionWidgetList.count())
547 {
548 for(int i = pos+1; i < mPositionWidgetList.count(); ++i)
549 {
550 mPositionWidgetList.at(i)->setOrdNumber(i+1);
551 setMappingId(mPositionWidgetList.at(i), i);
552 }
553 }
554
555 w->setDocPosition(dp);
556 w->setOrdNumber( pos+1 );
557 w->slotSetTax( dp->taxType() );
558 return w;
559 }
560
currentTaxSetting()561 DocPositionBase::TaxType KraftView::currentTaxSetting()
562 {
563 // add 1 to the currentItem since that starts with zero.
564 int taxKind = 1+( m_footerEdit->ui()->mTaxCombo->currentIndex() );
565 DocPositionBase::TaxType tt = DocPositionBase::TaxInvalid;
566
567 if ( taxKind == 1 ) { // No Tax at all
568 tt = DocPositionBase::TaxNone;
569 } else if ( taxKind == 2 ) { // Reduced tax for all items
570 tt = DocPositionBase::TaxReduced;
571 } else if ( taxKind == 3 ) { // Full tax for all items
572 tt = DocPositionBase::TaxFull;
573 } else { // individual level
574 tt = DocPositionBase::TaxIndividual;
575 }
576 return tt;
577 }
578
refreshPostCard()579 void KraftView::refreshPostCard()
580 {
581 DocPositionList positions = currentPositionList();
582
583 if( !getDocument() ) return;
584
585 if ( mAssistant->postCard() ) {
586 QDate d = m_headerEdit->m_dateEdit->date();
587 const QString dStr = Format::toDateString( d, KraftSettings::self()->dateFormat() );
588
589 mAssistant->postCard()->setHeaderData( m_headerEdit->m_cbType->currentText(),
590 dStr, m_headerEdit->m_postAddressEdit->toPlainText(),
591 getDocument()->ident(),
592 m_headerEdit->m_teEntry->toPlainText() );
593
594
595 mAssistant->postCard()->setPositions( positions, currentTaxSetting(),
596 DocumentMan::self()->tax( d ),
597 DocumentMan::self()->reducedTax( d ) );
598
599 mAssistant->postCard()->setFooterData( m_footerEdit->ui()->m_teSummary->toPlainText(),
600 m_footerEdit->greeting() );
601
602 mAssistant->postCard()->renderDoc( mViewStack->currentIndex() ); // id( mViewStack->visibleWidget() ) );
603 }
604
605
606 DocPositionListIterator it( positions );
607 DocPositionBase *dp;
608 while( it.hasNext()) {
609 dp = it.next();
610
611 if ( dp->type() == DocPositionBase::ExtraDiscount ) {
612 PositionViewWidget *w = ( static_cast<DocPosition*>( dp ) )->associatedWidget();
613 if( w ) {
614 w->slotSetOverallPrice( ( static_cast<DocPosition*>( dp ) )->overallPrice() );
615 } else {
616 // qDebug () << "Warning: Position object has no associated widget!" << endl;
617 }
618 }
619 }
620 }
621
setupFooter()622 void KraftView::setupFooter()
623 {
624 m_footerEdit = new KraftDocFooterEdit(this);
625
626 mViewStack->addWidget( m_footerEdit ); // KraftDoc::Footer );
627
628 // ATTENTION: If you change the following inserts, make sure to check the code
629 // in method currentPositionList!
630 m_footerEdit->ui()->mTaxCombo->insertItem( NO_TAX, QIcon::fromTheme("kraft_notax"), i18n( "Display no tax at all" ));
631 m_footerEdit->ui()->mTaxCombo->insertItem( RED_TAX, QIcon::fromTheme("kraft_redtax"), i18n( "Calculate reduced tax for all items" ));
632 m_footerEdit->ui()->mTaxCombo->insertItem( FULL_TAX, QIcon::fromTheme("kraft_fulltax"), i18n( "Calculate full tax for all items" ));
633 m_footerEdit->ui()->mTaxCombo->insertItem( INDI_TAX, i18n( "Calculate individual tax for each item"));
634
635 // set the tax type combo correctly: If all items have the same tax type, take it.
636 // If items have different, its the individual thing.
637 DocPositionList list = m_doc->positions();
638
639 int tt = -1;
640 DocPositionBase *dp = nullptr;
641
642 DocPositionListIterator it( list );
643 int taxIndex = 0;
644
645 while( it.hasNext()) {
646 dp = it.next();
647 if ( tt == -1 )
648 tt = dp->taxTypeNumeric(); // store the first entry.
649 else {
650 if ( tt != dp->taxTypeNumeric() ) {
651 taxIndex = INDI_TAX;
652 } else {
653 // old and new taxtype are the same.
654 }
655 }
656 }
657 if ( tt == -1 ) {
658 // means that there is no item yet, the default tax type needs to be used.
659 int deflt = KraftSettings::self()->defaultTaxType();
660 if ( deflt > 0 ) {
661 deflt -= 1;
662 }
663 taxIndex = deflt;
664 } else {
665 if ( taxIndex == 0 ) {
666 taxIndex = tt-1;
667 }
668 }
669
670 connect( m_footerEdit->ui()->mTaxCombo,SIGNAL(currentIndexChanged(int)),this,SLOT(slotTaxComboChanged(int)));
671
672 m_footerEdit->ui()->mTaxCombo->setCurrentIndex( taxIndex );
673 slotTaxComboChanged( taxIndex );
674
675 mTaxBefore = taxIndex;
676
677 connect(m_footerEdit,SIGNAL(modified()),this,SLOT(slotModifiedFooter()));
678 }
679
slotTaxComboChanged(int newId)680 void KraftView::slotTaxComboChanged(int newId)
681 {
682 bool allowTaxSetting = false;
683
684 if( mTaxBefore == newId ) return;
685
686 if( mTaxBefore == INDI_TAX ) {
687 // we're changing away from individual settings. WARNING needed.
688 // qDebug () << "You switch away from item individual tax settings.";
689 if( QMessageBox::question( this,
690 i18n("Tax Settings Overwrite"),
691 i18n("Really overwrite all individual tax settings of the items?")
692 ) == QMessageBox::No ) {
693 m_footerEdit->ui()->mTaxCombo->setCurrentIndex( INDI_TAX );
694 return;
695 }
696 }
697 DocPositionBase::TaxType tax = DocPositionBase::TaxFull;
698
699 if( newId == INDI_TAX ) {
700 allowTaxSetting = true;
701 } else if( newId == RED_TAX ) {
702 tax = DocPositionBase::TaxReduced;
703 } else if( newId == NO_TAX ) {
704 tax = DocPositionBase::TaxNone;
705 }
706
707 PositionViewWidgetListIterator it( mPositionWidgetList );
708 while( it.hasNext() ) {
709 PositionViewWidget *w = it.next();
710 w->slotAllowIndividualTax( allowTaxSetting );
711 w->slotSetTax( tax );
712 }
713
714 mTaxBefore = newId;
715 slotModifiedFooter();
716 }
717
718 /* This is the flow in the move up method:
719 0 Bla1 0 Bla1 0 Bla1
720 1 Bla2 <- w2 1 Bla2 -> insert at pos-1 => 1 Bla3
721 pos -> 2 Bla3 <- w1 2 Bla4 2 Bla2
722 3 Bla4 3 Bla4
723 */
slotMovePositionUp(int pos)724 void KraftView::slotMovePositionUp( int pos )
725 {
726 PositionViewWidget *w1 = nullptr;
727 PositionViewWidget *w2 = nullptr;
728
729 // qDebug () << "Moving position up: " << pos << endl;
730 if( pos < 1 || pos > mPositionWidgetList.count() ) {
731 // qDebug () << "ERR: position out of range: " << pos << endl;
732 return;
733 }
734
735 mPositionWidgetList.swap( pos, pos-1 );
736 w1 = mPositionWidgetList.at( pos-1 );
737 w2 = mPositionWidgetList.at( pos ); // Porting ATTENTION: check assignment of w1, w1
738
739 // qDebug () << "Found at pos " << pos << " the widgets " << w1 << " and " << w2 << endl;
740
741 if( w1 && w2 ) {
742 // qDebug () << "Setting ord number: " << pos << endl;
743 w1->setOrdNumber( pos ); // note: ordnumbers start with 1, thus add one
744 w2->setOrdNumber( pos+1 );
745 setMappingId( w1, pos-1 );
746 setMappingId( w2, pos );
747
748 m_positionScroll->moveChild( w2, m_positionScroll->indexOf(w1) );
749 mModified = true;
750 QTimer::singleShot( 0, this, SLOT(refreshPostCard() ) );
751 } else {
752 // qDebug () << "ERR: Did not find the two corresponding widgets!" << endl;
753 }
754 }
755 /*
756 0 Bla1 0 Bla1 0 Bla1
757 pos -> 1 Bla2 <- w1 1 Bla3 1 Bla3
758 2 Bla3 <- w2 2 Bla4 -> insert at pos+1 => 2 Bla2
759 3 Bla4 3 Bla4
760 */
slotMovePositionDown(int pos)761 void KraftView::slotMovePositionDown( int pos )
762 {
763 PositionViewWidget *w1 = nullptr;
764 PositionViewWidget *w2 = nullptr;
765 // qDebug () << "Moving position down: " << pos << endl;
766
767 if( pos < 0 || pos >= mPositionWidgetList.count() -1 ) {
768 // qDebug () << "ERR: position out of range: " << pos << endl;
769 return;
770 }
771
772 mPositionWidgetList.swap( pos, pos+1);
773 w1 = mPositionWidgetList.at( pos+1 );
774 w2 = mPositionWidgetList.at( pos ); // Porting ATTENTION: check assignment of w1, w1
775
776 if( w1 && w2 ) {
777 w1->setOrdNumber( pos+2 );
778 w2->setOrdNumber( pos+1 );
779
780 setMappingId( w1, pos+1 );
781 setMappingId( w2, pos );
782
783 m_positionScroll->moveChild( w1, m_positionScroll->indexOf( w2 ) );
784
785 mModified = true;
786 QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) );
787 } else {
788 // qDebug () << "ERR: Did not find the two corresponding widgets!" << endl;
789 }
790 }
791
slotDeletePosition(int pos)792 void KraftView::slotDeletePosition( int pos )
793 {
794 PositionViewWidget *w1 = mPositionWidgetList.at( pos );
795 if( w1 ) {
796 w1->slotSetState( PositionViewWidget::Deleted );
797 w1->slotModified();
798 }
799 }
800
slotLockPosition(int pos)801 void KraftView::slotLockPosition( int pos )
802 {
803 // qDebug () << "Locking Position " << pos << endl;
804
805 PositionViewWidget *w1 = mPositionWidgetList.at( pos );
806 if( w1 ) {
807 w1->slotSetState( PositionViewWidget::Locked );
808 refreshPostCard();
809 }
810 }
811
slotUnlockPosition(int pos)812 void KraftView::slotUnlockPosition( int pos )
813 {
814 // qDebug () << "Unlocking Position " << pos << endl;
815
816 PositionViewWidget *w1 = mPositionWidgetList.at( pos );
817 if( w1 ) {
818 w1->slotSetState( PositionViewWidget::Active );
819 refreshPostCard();
820 }
821 }
822
slotPositionModified(int)823 void KraftView::slotPositionModified( int )
824 {
825 // qDebug () << "Modified Position " << pos << endl;
826 mModified = true;
827
828 QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) );
829 }
830
slotAddressFound(const QString & uid,const KContacts::Addressee & contact)831 void KraftView::slotAddressFound(const QString& uid, const KContacts::Addressee& contact)
832 {
833 const QString currAddress = m_headerEdit->m_postAddressEdit->toPlainText();
834 const QString newAddress = mAddressProvider->formattedAddress(contact);
835 bool replace = true;
836
837 if( currAddress.isEmpty() ) {
838 replace = true;
839 } else if(currAddress != newAddress) {
840 // non empty and current different from new address
841 // need to ask first if we overwrite
842 if( QMessageBox::question( this, i18n("Address Overwrite"),
843 i18n("The address label is not empty and different from the selected one.<br/>"
844 "Do you really want to replace it with the text shown below?<pre>%1</pre>",
845 newAddress)
846 ) == QMessageBox::No ) {
847 replace = false;
848 }
849 } else if( currAddress == newAddress ) {
850 // both are equal, no action needed
851 return;
852 }
853
854 if( replace ) {
855 mContactUid = uid;
856 m_headerEdit->m_labName->setText( contact.realName() );
857
858 m_headerEdit->m_postAddressEdit->setText( newAddress );
859
860 // Generate the welcome
861 m_headerEdit->m_letterHead->clear();
862 QStringList li = generateLetterHead( contact.familyName(), contact.givenName() );
863
864 m_headerEdit->m_letterHead->insertItems(-1, li );
865 KraftDoc *doc = getDocument();
866 if( doc->isNew() ) {
867 m_headerEdit->m_letterHead->setCurrentIndex( KraftSettings::self()->salut() );
868 } else {
869 if(!doc->salut().isEmpty()) {
870 m_headerEdit->m_letterHead->setCurrentText( doc->salut() );
871 }
872 }
873 }
874 }
875
slotDocTypeChanged(const QString & newType)876 void KraftView::slotDocTypeChanged( const QString& newType )
877 {
878 // qDebug () << "Doc Type changed to " << newType << endl;
879 mAssistant->slotSetDocType( newType );
880
881 DocType docType( newType );
882
883 PositionViewWidgetListIterator it( mPositionWidgetList );
884 while( it.hasNext() ) {
885 PositionViewWidget *w = it.next();
886 w->slotEnableKindMenu( docType.allowAlternative() );
887 w->slotShowPrice(docType.pricesVisible());
888 }
889
890 mAssistant->postCard()->slotShowPrices( docType.pricesVisible() );
891 m_footerEdit->ui()->_taxGroup->setVisible( docType.pricesVisible() );
892 if( mDocPosEditorIndx > -1 ) {
893 KraftDocPositionsEdit *w = dynamic_cast<KraftDocPositionsEdit*>(mViewStack->widget(mDocPosEditorIndx));
894 if(w) {
895 w->setDiscountButtonVisible(docType.pricesVisible());
896 }
897 }
898 }
899
slotLanguageSettings()900 void KraftView::slotLanguageSettings()
901 {
902 // qDebug () << "Language Settings" << endl;
903 // FIXME
904 }
905
slotNewHeaderText(const QString & str)906 void KraftView::slotNewHeaderText( const QString& str )
907 {
908 m_headerEdit->m_teEntry->setText( str );
909 slotModifiedHeader();
910 }
911
slotNewFooterText(const QString & str)912 void KraftView::slotNewFooterText( const QString& str )
913 {
914 m_footerEdit->ui()->m_teSummary->setText( str );
915 slotModifiedFooter();
916 }
917
918 // Add a new item. A katalog is required if user wants to store it in a
919 // catalog immediately. FIXME - now the current active catalog in the
920 // catalog selection is used.
slotAddNewItem()921 void KraftView::slotAddNewItem()
922 {
923 Katalog* kat = mAssistant->catalogSelection()->currentSelectedKat();
924 slotAddItem( kat, nullptr, QString() );
925 }
926
slotAddItems(Katalog * kat,CatalogTemplateList templates,const QString & selectedChapter)927 void KraftView::slotAddItems( Katalog *kat, CatalogTemplateList templates, const QString& selectedChapter)
928 {
929
930 if(templates.count() == 0) {
931 slotAddItem(kat, nullptr, selectedChapter);
932 } else {
933 for(CatalogTemplate *templ : templates ) {
934 slotAddItem( kat, templ, selectedChapter );
935 }
936 }
937 }
938
slotAddItem(Katalog * kat,CatalogTemplate * tmpl,const QString & selectedChapter)939 void KraftView::slotAddItem( Katalog *kat, CatalogTemplate *tmpl, const QString& selectedChapter )
940 {
941 // newpos is a list position, starts counting at zero!
942 int newpos = mPositionWidgetList.count();
943 // qDebug () << "Adding Position at list position " << newpos << endl;
944
945 QScopedPointer<TemplToPositionDialogBase> dia;
946
947 DocPosition *dp = new DocPosition();
948 dp->setPositionNumber( newpos +1 );
949
950 bool newTemplate = false;
951 if ( !tmpl ) {
952 newTemplate = true;
953 }
954
955 dia.reset(new InsertTemplDialog( this ));
956 dia->setCatalogChapters( kat->getKatalogChapters(), selectedChapter);
957
958 int tmplId = 0;
959
960 if ( !newTemplate ) {
961 // it's not a new template
962 dp->setText(tmpl->getText());
963 dp->setUnit(tmpl->unit());
964 dp->setUnitPrice(tmpl->unitPrice());
965 }
966
967 if ( mRememberAmount > 0 ) {
968 dp->setAmount( mRememberAmount );
969 }
970
971 KraftDoc *doc = getDocument();
972 if(doc) {
973 DocType docType = doc->docType();
974 dia->setDocPosition( dp, newTemplate, docType.pricesVisible() );
975 }
976 DocPositionList list = currentPositionList();
977 dia->setPositionList( list, newpos );
978
979 QSize s = KraftSettings::self()->templateToPosDialogSize();
980 dia->resize( s );
981
982 int execResult = dia->exec();
983
984 if ( execResult == QDialog::Accepted ) {
985 DocPosition diaPos = dia->docPosition();
986 *dp = diaPos;
987
988 // set the tax settings
989 if( currentTaxSetting() == DocPositionBase::TaxIndividual ) {
990 // FIXME: In case a new item is added, add the default tax type.
991 // otherwise add the tax of the template
992 dp->setTaxType( DocPositionBase::TaxFull );
993 } else {
994 dp->setTaxType( currentTaxSetting() );
995 }
996
997 // store the initial size of the template-to-doc-pos dialogs
998 s = dia->size();
999 KraftSettings::self()->setTemplateToPosDialogSize( s );
1000
1001 if ( kat->type() == TemplateCatalog ) {
1002
1003 // save the template if it is has a valid chapter.
1004 // the method chapter() considers the checkbox. If it is not checked to keep the template,
1005 // an empty chapter is returned.
1006
1007 const QString chapter = dia->chapter();
1008 if (!chapter.isEmpty()) {
1009 int chapterId = KatalogMan::self()->defaultTemplateCatalog()->chapterID(chapter).toInt();
1010
1011 FloskelTemplate *flos = new FloskelTemplate( -1, dp->text(),
1012 dp->unit().id(),
1013 chapterId,
1014 1 /* CalcKind = Manual */ );
1015 flos->setManualPrice( dp->unitPrice() );
1016 flos->save();
1017 tmplId = flos->getTemplID();
1018
1019 // reload the entire katalog
1020 Katalog *defaultKat = KatalogMan::self()->defaultTemplateCatalog();
1021 if( defaultKat ) {
1022 defaultKat->load();
1023 KatalogMan::self()->notifyKatalogChange( defaultKat , dbID() );
1024 }
1025 }
1026 }
1027 if (!newTemplate){
1028 tmplId = static_cast<FloskelTemplate*>(tmpl)->getTemplID();
1029 }
1030 } else if ( kat->type() == MaterialCatalog ) {
1031 if ( newTemplate ) {
1032 // FIXME
1033 }
1034 }
1035
1036 if (execResult == QDialog::Accepted) {
1037 newpos = dia->insertAfterPosition();
1038
1039 mRememberAmount = dp->amount();
1040
1041 if (tmplId > 0) {
1042 kat->recordUsage(tmplId);
1043 }
1044
1045 PositionViewWidget *widget = createPositionViewWidget( dp, newpos );
1046 widget->slotModified();
1047 widget->slotAllowIndividualTax( currentTaxSetting() == DocPositionBase::TaxIndividual );
1048
1049 // Check if the new widget is supposed to display prices, based on the doc type
1050 // FIXME: Shouldn't this be done by the positionViewWidget rather than here?
1051 const QString dt = getDocument()->docType();
1052 if( !dt.isEmpty() ) {
1053 DocType docType(dt);
1054 widget->slotShowPrice(docType.pricesVisible());
1055 }
1056 slotFocusItem( widget, newpos );
1057 refreshPostCard();
1058 }
1059 }
1060
slotImportItems()1061 void KraftView::slotImportItems()
1062 {
1063 ImportItemDialog dia( this );
1064 DocPositionList list = currentPositionList();
1065 int newpos = list.count();
1066 dia.setPositionList( list, newpos );
1067
1068 if ( dia.exec() ) {
1069 DocPositionList list = dia.positionList();
1070 if ( list.count() > 0 ) {
1071 // qDebug () << "Importlist amount of entries: " << list.count();
1072 int cnt = 0;
1073 int newpos = dia.getPositionCombo()->currentIndex();
1074 // qDebug () << "Newpos is " << newpos;
1075
1076 DocPositionListIterator posIt( list );
1077 while( posIt.hasNext() ) {
1078 DocPosition *dp_old = static_cast<DocPosition*>(posIt.next());
1079
1080 DocPosition *dp = new DocPosition( *(dp_old) );
1081 dp->setTaxType( currentTaxSetting() );
1082 PositionViewWidget *widget = createPositionViewWidget( dp, newpos + cnt++ );
1083 widget->slotSetTax( DocPositionBase::TaxFull ); // FIXME: Value from Import?
1084 widget->slotModified();
1085 }
1086 refreshPostCard();
1087 }
1088 }
1089 }
1090
slotAddExtraPosition()1091 void KraftView::slotAddExtraPosition()
1092 {
1093 // newpos is a list position, starts counting at 0
1094 int newpos = mPositionWidgetList.count();
1095 // qDebug () << "Adding EXTRA Position at position " << newpos << endl;
1096
1097 DocPosition *dp = new DocPosition( DocPosition::ExtraDiscount );
1098 dp->setPositionNumber( newpos+1 );
1099 dp->setText( i18n( "Discount" ) );
1100 Einheit e = UnitManager::self()->getPauschUnit();
1101 dp->setUnit(e);
1102 if( currentTaxSetting() == DocPositionBase::TaxIndividual ) {
1103 dp->setTaxType( DocPositionBase::TaxFull );
1104 } else {
1105 dp->setTaxType( currentTaxSetting() );
1106 }
1107
1108 // qDebug () << "New Extra position is " << dp << endl;
1109
1110 PositionViewWidget *widget = createPositionViewWidget( dp, newpos );
1111 // qDebug () << "PositionViewWiget doc position is: " << widget->position() << endl;
1112 widget->slotModified();
1113 slotFocusItem( widget, newpos );
1114 refreshPostCard();
1115
1116 }
1117
currentPositionList()1118 DocPositionList KraftView::currentPositionList()
1119 {
1120 DocPositionList list;
1121 PositionViewWidget *widget = nullptr;
1122 int cnt = 1;
1123
1124 PositionViewWidgetListIterator outerIt( mPositionWidgetList );
1125
1126 bool progress = true;
1127
1128 while ( progress && ( list.count() != mPositionWidgetList.count() ) ) {
1129 // the loop runs until all positions have a valid price.
1130
1131 int preListCnt = list.count();
1132 // qDebug() << "# Pre List Count: " << preListCnt << endl;
1133
1134 while ( outerIt.hasNext() ) {
1135 widget = outerIt.next();
1136 DocPositionBase *dpb = widget->position();
1137
1138 KraftDB::StringMap replaceMap;
1139
1140 if ( dpb ) {
1141 DocPosition *newDp = new DocPosition( dpb->type() );
1142 newDp->setPositionNumber( cnt++ );
1143 newDp->setAttributeMap( dpb->attributes() );
1144 newDp->setDbId( dpb->dbId().toInt() );
1145 newDp->setAssociatedWidget( widget );
1146
1147 bool calculatable = true;
1148
1149 if ( dpb->type() == DocPosition::ExtraDiscount ) {
1150 double discount = widget->mDiscountPercent->value();
1151
1152 /* set Attributes with the discount percentage */
1153 Attribute a( DocPosition::Discount );
1154 a.setPersistant( true );
1155 a.setValue( discount );
1156 newDp->setAttribute( a );
1157
1158 QString tagRequired = widget->extraDiscountTagRestriction();
1159
1160 if ( !tagRequired.isEmpty() ) {
1161 Attribute tr( DocPosition::ExtraDiscountTagRequired );
1162 tr.setValueRelation( "tagTemplates", "tagTmplID", "name" );
1163 tr.setPersistant( true );
1164 tr.setValue( QVariant( tagRequired ) );
1165 newDp->setAttribute( tr );
1166 }
1167
1168 /* Calculate the current sum over all widgets */
1169 PositionViewWidgetListIterator it( mPositionWidgetList );
1170 PositionViewWidget *w1;
1171 Geld sum;
1172 // qDebug () << "Starting to loop over the items " << endl;
1173 while ( calculatable && it.hasNext() ) {
1174 w1 = it.next();
1175
1176 if ( widget != w1 ) { // ATTENTION Porting: do not take the own value into account
1177 if ( tagRequired.isEmpty() // means that all positions are to calculate
1178 || w1->tagList().contains( tagRequired ) ) {
1179 if ( w1->priceValid() ) {
1180 sum += w1->currentPrice();
1181 // qDebug () << "Summing up pos with text " << w1->ordNumber() << " and price "
1182 // << w1->currentPrice().toLong() << endl;
1183 } else {
1184 calculatable = false; // give up, we continue in outerIt
1185 // qDebug () << "We skip pos " << w1->ordNumber() << endl;
1186 }
1187 }
1188 } else {
1189 // we can not calculate ourselves.
1190 // qDebug () << "Skipping pos " << w1->ordNumber() << " in summing up, thats me!" << endl;
1191 }
1192 }
1193 // qDebug () << "Finished loop over items with calculatable=" << calculatable << endl;
1194
1195 if ( calculatable ) {
1196 sum = sum.percent( discount );
1197 newDp->setUnitPrice( sum );
1198 newDp->setAmount( 1.0 );
1199 widget->setCurrentPrice( sum );
1200 }
1201
1202 // replace some tags in the text
1203
1204 replaceMap["%DISCOUNT"] = DefaultProvider().self()->locale()->toString( discount );
1205 replaceMap["%ABS_DISCOUNT"] = DefaultProvider().self()->locale()->toString( qAbs( discount ) );
1206
1207 } else {
1208 /* Type is ordinary position */
1209 newDp->setUnitPrice( widget->unitPrice() );
1210
1211 double v = widget->m_sbAmount->value();
1212 newDp->setAmount( v );
1213 widget->setCurrentPrice( newDp->overallPrice() );
1214 }
1215
1216 if ( calculatable ) {
1217 // copy information from the widget
1218 newDp->setToDelete( widget->deleted() );
1219
1220 QString t = widget->m_teFloskel->toPlainText();
1221 if ( !replaceMap.empty() ) {
1222 t = KraftDB::self()->replaceTagsInWord( t, replaceMap );
1223 }
1224 newDp->setText( t );
1225
1226 QString h = widget->m_cbUnit->currentText();
1227 int eId = UnitManager::self()->getUnitIDSingular( h );
1228 Einheit e = UnitManager::self()->getUnit( eId );
1229 newDp->setUnit( e );
1230
1231 PositionViewWidget::Kind k = widget->kind();
1232
1233 if ( k != PositionViewWidget::Normal ) {
1234 Attribute a( DocPosition::Kind );
1235 a.setPersistant( true );
1236 a.setValue( widget->kindString() );
1237 newDp->setAttribute( a );
1238 } else {
1239 newDp->removeAttribute( DocPosition::Kind );
1240 }
1241
1242 /* set Attribute with the tags */
1243 QStringList tagStrings = widget->tagList();
1244 if ( !tagStrings.isEmpty() ) {
1245 Attribute tags( DocPosition::Tags );
1246 tags.setValueRelation( "tagTemplates", "tagTmplID", "name" );
1247 tags.setPersistant( true );
1248 tags.setListValue( true );
1249 tags.setValue( QVariant( tagStrings ) );
1250 newDp->setAttribute( tags );
1251 // qDebug() << "============ " << tags.toString() << endl;
1252 } else {
1253 newDp->removeAttribute( DocPosition::Tags );
1254 }
1255
1256 // tax settings
1257 if( currentTaxSetting() == DocPositionBase::TaxIndividual ) {
1258 newDp->setTaxType( widget->taxType() );
1259 } else {
1260 newDp->setTaxType( currentTaxSetting() );
1261 }
1262 list.append( newDp );
1263 }
1264 } else {
1265 qCritical() << "Fatal: Widget without position found!" << endl;
1266 }
1267 }
1268 // qDebug() << " Post List Count: " << list.count() << endl;
1269
1270 if ( preListCnt == list.count() ) {
1271 qCritical() << "No progress in widget list processing - abort!" << endl;
1272 progress = false;
1273 }
1274 }
1275 return list;
1276 }
1277
slotShowCatalog(bool on)1278 void KraftView::slotShowCatalog( bool on )
1279 {
1280 if ( on ) {
1281 mAssistant->slotShowCatalog();
1282 } else {
1283 mAssistant->setFullPreview( true, KraftDoc::Positions );
1284 }
1285 }
1286
slotModifiedPositions()1287 void KraftView::slotModifiedPositions()
1288 {
1289 // As long as the modified mapper is blocked, ignore this.
1290 if( mModifiedMapper->signalsBlocked() ) {
1291 return;
1292 }
1293
1294 qDebug () << "Position Modified" << endl;
1295 mModified = true;
1296 }
1297
slotModifiedHeader()1298 void KraftView::slotModifiedHeader()
1299 {
1300 // qDebug () << "Modified the header!" << endl;
1301 // As long as the modified mapper is blocked, ignore this.
1302 if( mModifiedMapper->signalsBlocked() ) {
1303 return;
1304 }
1305
1306 mModified = true;
1307
1308 QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) );
1309 }
1310
slotModifiedFooter()1311 void KraftView::slotModifiedFooter()
1312 {
1313 // qDebug () << "Modified the footer!" << endl;
1314 // As long as the modified mapper is blocked, ignore this.
1315 if( mModifiedMapper->signalsBlocked() ) {
1316 return;
1317 }
1318
1319 mModified = true;
1320
1321 QTimer::singleShot( 0, this, SLOT( refreshPostCard() ) );
1322 }
1323
generateLetterHead(const QString & familyName,const QString & givenName)1324 QStringList KraftView::generateLetterHead( const QString& familyName, const QString& givenName )
1325 {
1326 QStringList s;
1327
1328 KraftDB::StringMap m;
1329 m[ "%NAME"] = familyName;
1330 m[ "%GIVEN_NAME"] = givenName;
1331
1332 return KraftDB::self()->wordList( "salut", m );
1333 }
1334
done(int r)1335 void KraftView::done( int r )
1336 {
1337 bool okToContinue = true;
1338
1339 //Closed using the cancel button .. Check if we can close
1340 if(r == 0) {
1341 if( mModified ) {
1342 okToContinue = documentModifiedMessageBox();
1343 if(!okToContinue) {
1344 return;
1345 }
1346 }
1347 }
1348 //Closed using the OK button .. it can be closed, but data needs saved
1349 if( mModified && r > 0 ) {
1350 saveChanges();
1351 emit viewClosed( r == 1, m_doc );
1352 }
1353 // remember the sizes of the docassistant splitter if visible.
1354 mAssistant->saveSplitterSizes();
1355 KraftSettings::self()->setDocViewSplitter(mCSplit->sizes());
1356 const QByteArray geo = saveGeometry().toBase64();
1357 KraftSettings::self()->setDocEditGeometry(geo);
1358
1359 QDialog::done( r );
1360 }
1361
saveChanges()1362 void KraftView::saveChanges()
1363 {
1364 // qDebug () << "Saving changes!" << endl;
1365
1366 KraftDoc *doc = getDocument();
1367
1368 if( !doc ) {
1369 // qDebug () << "ERR: No document available in view, return!" << endl;
1370 return;
1371 }
1372 // transfer all values to the document
1373 doc->setDate( m_headerEdit->m_dateEdit->date() );
1374 doc->setAddressUid( mContactUid );
1375 doc->setAddress( m_headerEdit->m_postAddressEdit->toPlainText() );
1376 doc->setDocType( m_headerEdit->m_cbType->currentText() );
1377 doc->setPreText( m_headerEdit->m_teEntry->toPlainText() );
1378 doc->setWhiteboard( m_headerEdit->m_whiteboardEdit->toPlainText() );
1379 doc->setProjectLabel( m_headerEdit->mProjectLabelEdit->text() );
1380 doc->setSalut( m_headerEdit->m_letterHead->currentText() );
1381 doc->setPostText( m_footerEdit->ui()->m_teSummary->toPlainText() );
1382 doc->setGoodbye( m_footerEdit->greeting() );
1383
1384 DocPositionList list = currentPositionList();
1385 doc->setPositionList( list );
1386
1387 doc->saveDocument( );
1388
1389 if ( doc->isNew() ) {
1390 // For new documents the user had to select a greeting and we make this
1391 // default for the future
1392 KraftSettings::self()->setGreeting( m_footerEdit->greeting() );
1393 KraftSettings::self()->setSalut( m_headerEdit->m_letterHead->currentIndex() );
1394 }
1395 }
1396
slotFocusItem(PositionViewWidget * posWidget,int pos)1397 void KraftView::slotFocusItem( PositionViewWidget *posWidget, int pos )
1398 {
1399 if( posWidget && pos > 0) {
1400 int y = (1+pos)*posWidget->height();
1401 m_positionScroll->ensureVisible(0, y);
1402 } else {
1403 m_positionScroll->ensureVisible( 0, 0 );
1404 }
1405 // setting Focus within the item.
1406 if( posWidget ) {
1407 if( posWidget->m_teFloskel->toPlainText().isEmpty() ) {
1408 posWidget->m_teFloskel->setFocus();
1409 } else {
1410 posWidget->m_sbAmount->setFocus();
1411 }
1412 }
1413 }
1414
documentModifiedMessageBox()1415 bool KraftView::documentModifiedMessageBox()
1416 {
1417 if ( mModified ) {
1418 QMessageBox msgBox;
1419 msgBox.setText(i18n("The document has been modified."));
1420 msgBox.setInformativeText(i18n("Do you want to save your changes?"));
1421 msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
1422 msgBox.setDefaultButton(QMessageBox::Save);
1423 int ret = msgBox.exec();
1424
1425 if( ret == QMessageBox::Cancel ) {
1426 return false;
1427 }
1428 }
1429 return true;
1430
1431 }
1432
discardChanges()1433 void KraftView::discardChanges()
1434 {
1435 // We need to reread the document
1436 KraftDoc *doc = getDocument();
1437 if( doc && doc->isModified() ) {
1438 // qDebug () << "Document refetch from database" << endl;
1439 doc->reloadDocument();
1440 }
1441 }
1442
1443