File indexing completed on 2024-05-12 16:35:16

0001 /* This file is part of the KDE project
0002    Copyright (C) 2002-2003 Norbert Andres <nandres@web.de>
0003              (C) 2002-2003 Philipp Mueller <philipp.mueller@gmx.de>
0004              (C) 2002 John Dailey <dailey@vt.edu>
0005              (C) 1999-2001 Laurent Montel <montel@kde.org>
0006 
0007    This library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Library General Public
0009    License as published by the Free Software Foundation; either
0010    version 2 of the License, or (at your option) any later version.
0011 
0012    This library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Library General Public License for more details.
0016 
0017    You should have received a copy of the GNU Library General Public License
0018    along with this library; see the file COPYING.LIB.  If not, write to
0019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020    Boston, MA 02110-1301, USA.
0021 */
0022 
0023 
0024 #include "ConditionalDialog.h"
0025 #include "Condition.h"
0026 
0027 #include "Cell.h"
0028 #include "Map.h"
0029 #include "ui/Selection.h"
0030 #include "Sheet.h"
0031 #include "StyleManager.h"
0032 #include "ValueConverter.h"
0033 #include "ValueParser.h"
0034 #include "SheetsDebug.h"
0035 
0036 // commands
0037 #include "commands/ConditionCommand.h"
0038 
0039 #include <kcombobox.h>
0040 #include <klineedit.h>
0041 #include <KLocalizedString>
0042 #include <kmessagebox.h>
0043 
0044 #include <QGroupBox>
0045 #include <QLabel>
0046 #include <QGridLayout>
0047 
0048 using namespace Calligra::Sheets;
0049 
0050 ConditionalWidget::ConditionalWidget(QWidget* parent, const char* /*name*/, Qt::WindowFlags fl)
0051         : QWidget(parent, fl)
0052 {
0053     QGridLayout * Form1Layout = new QGridLayout(this);
0054 
0055     QGroupBox * groupBox1_3 = new QGroupBox(this);
0056     QGridLayout * groupBox1_3Layout = new QGridLayout(groupBox1_3);
0057     groupBox1_3Layout->setAlignment(Qt::AlignTop);
0058 
0059     QLabel * textLabel1_3 = new QLabel(groupBox1_3);
0060     groupBox1_3Layout->addWidget(textLabel1_3, 0, 0);
0061 
0062     m_condition_3 = new KComboBox(groupBox1_3);
0063     groupBox1_3Layout->addWidget(m_condition_3, 0, 1);
0064 
0065     m_firstValue_3 = new KLineEdit(groupBox1_3);
0066     m_firstValue_3->setEnabled(false);
0067     groupBox1_3Layout->addWidget(m_firstValue_3, 0, 2);
0068 
0069     m_secondValue_3 = new KLineEdit(groupBox1_3);
0070     m_secondValue_3->setEnabled(false);
0071     groupBox1_3Layout->addWidget(m_secondValue_3, 0, 3);
0072 
0073     m_style_3 = new KComboBox(groupBox1_3);
0074     m_style_3->setEnabled(false);
0075     groupBox1_3Layout->addWidget(m_style_3, 1, 1);
0076 
0077     QLabel * textLabel2_3 = new QLabel(groupBox1_3);
0078     groupBox1_3Layout->addWidget(textLabel2_3, 1, 0);
0079 
0080     QSpacerItem * spacer = new QSpacerItem(41, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0081     groupBox1_3Layout->addItem(spacer, 1, 2);
0082     QSpacerItem * spacer_2 = new QSpacerItem(61, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0083     groupBox1_3Layout->addItem(spacer_2, 1, 3);
0084 
0085     Form1Layout->addWidget(groupBox1_3, 2, 0);
0086 
0087     QGroupBox * groupBox1_2 = new QGroupBox(this);
0088 
0089     QGridLayout * groupBox1_2Layout = new QGridLayout(groupBox1_2);
0090     groupBox1_2Layout->setAlignment(Qt::AlignTop);
0091 
0092     QLabel * textLabel1_2 = new QLabel(groupBox1_2);
0093     groupBox1_2Layout->addWidget(textLabel1_2, 0, 0);
0094 
0095     QLabel * textLabel2_2 = new QLabel(groupBox1_2);
0096     groupBox1_2Layout->addWidget(textLabel2_2, 1, 0);
0097 
0098     m_condition_2 = new KComboBox(groupBox1_2);
0099     groupBox1_2Layout->addWidget(m_condition_2, 0, 1);
0100 
0101     m_style_2 = new KComboBox(groupBox1_2);
0102     m_style_2->setEnabled(false);
0103     groupBox1_2Layout->addWidget(m_style_2, 1, 1);
0104 
0105     m_firstValue_2 = new KLineEdit(groupBox1_2);
0106 
0107     m_firstValue_2->setEnabled(false);
0108     groupBox1_2Layout->addWidget(m_firstValue_2, 0, 2);
0109 
0110     m_secondValue_2 = new KLineEdit(groupBox1_2);
0111     m_secondValue_2->setEnabled(false);
0112 
0113     groupBox1_2Layout->addWidget(m_secondValue_2, 0, 3);
0114 
0115     QSpacerItem * spacer_3 = new QSpacerItem(41, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0116     groupBox1_2Layout->addItem(spacer_3, 1, 2);
0117     QSpacerItem * spacer_4 = new QSpacerItem(61, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0118     groupBox1_2Layout->addItem(spacer_4, 1, 3);
0119     Form1Layout->addWidget(groupBox1_2, 1, 0);
0120 
0121     QGroupBox * groupBox1_1 = new QGroupBox(this);
0122 
0123     QGridLayout * groupBox1_1Layout = new QGridLayout(groupBox1_1);
0124     groupBox1_1Layout->setAlignment(Qt::AlignTop);
0125 
0126     QLabel * textLabel1_1 = new QLabel(groupBox1_1);
0127     groupBox1_1Layout->addWidget(textLabel1_1, 0, 0);
0128 
0129     QLabel * textLabel2_1 = new QLabel(groupBox1_1);
0130     groupBox1_1Layout->addWidget(textLabel2_1, 1, 0);
0131 
0132     m_condition_1 = new KComboBox(groupBox1_1);
0133     groupBox1_1Layout->addWidget(m_condition_1, 0, 1);
0134 
0135     m_style_1 = new KComboBox(groupBox1_1);
0136     m_style_1->setEnabled(false);
0137     groupBox1_1Layout->addWidget(m_style_1, 1, 1);
0138 
0139     m_firstValue_1 = new KLineEdit(groupBox1_1);
0140     m_firstValue_1->setEnabled(false);
0141     groupBox1_1Layout->addWidget(m_firstValue_1, 0, 2);
0142 
0143     m_secondValue_1 = new KLineEdit(groupBox1_1);
0144     m_secondValue_1->setEnabled(false);
0145     groupBox1_1Layout->addWidget(m_secondValue_1, 0, 3);
0146 
0147     QSpacerItem * spacer_5 = new QSpacerItem(41, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0148     groupBox1_1Layout->addItem(spacer_5, 1, 2);
0149     QSpacerItem * spacer_6 = new QSpacerItem(61, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
0150     groupBox1_1Layout->addItem(spacer_6, 1, 3);
0151 
0152     Form1Layout->addWidget(groupBox1_1, 0, 0);
0153     resize(QSize(702, 380).expandedTo(minimumSizeHint()));
0154 
0155     QStringList list;
0156     list += i18n("<none>");   // krazy:exclude=i18ncheckarg
0157     list += i18n("equal to");
0158     list += i18n("greater than");
0159     list += i18n("less than");
0160     list += i18n("equal to or greater than");
0161     list += i18n("equal to or less than");
0162     list += i18n("between");
0163     list += i18n("outside range");
0164     list += i18n("different to");
0165 
0166     m_condition_1->clear();
0167     m_condition_2->clear();
0168     m_condition_3->clear();
0169     m_condition_1->insertItems(0, list);
0170     m_condition_2->insertItems(0, list);
0171     m_condition_3->insertItems(0, list);
0172 
0173     groupBox1_1->setTitle(i18n("First Condition"));
0174     groupBox1_2->setTitle(i18n("Second Condition"));
0175     groupBox1_3->setTitle(i18n("Third Condition"));
0176     textLabel1_1->setText(i18n("Cell is"));
0177     textLabel1_2->setText(i18n("Cell is"));
0178     textLabel1_3->setText(i18n("Cell is"));
0179     textLabel2_1->setText(i18n("Cell style"));
0180     textLabel2_2->setText(i18n("Cell style"));
0181     textLabel2_3->setText(i18n("Cell style"));
0182 
0183     connect(m_condition_1, SIGNAL(highlighted(QString)), this, SLOT(slotTextChanged1(QString)));
0184     connect(m_condition_2, SIGNAL(highlighted(QString)), this, SLOT(slotTextChanged2(QString)));
0185     connect(m_condition_3, SIGNAL(highlighted(QString)), this, SLOT(slotTextChanged3(QString)));
0186 }
0187 
0188 ConditionalWidget::~ConditionalWidget()
0189 {
0190 }
0191 
0192 void ConditionalWidget::slotTextChanged1(const QString & text)
0193 {
0194     if (text == i18n("<none>")) {   // krazy:exclude=i18ncheckarg
0195         m_firstValue_1->setEnabled(false);
0196         m_secondValue_1->setEnabled(false);
0197         m_style_1->setEnabled(false);
0198     } else {
0199         m_condition_2->setEnabled(true);
0200         m_style_1->setEnabled(true);
0201         if ((text == i18n("between")) || (text == i18n("different from"))) {
0202             m_firstValue_1->setEnabled(true);
0203             m_secondValue_1->setEnabled(true);
0204         } else {
0205             m_firstValue_1->setEnabled(true);
0206             m_secondValue_1->setEnabled(false);
0207         }
0208     }
0209 }
0210 
0211 void ConditionalWidget::slotTextChanged2(const QString & text)
0212 {
0213     if (text == i18n("<none>")) {   // krazy:exclude=i18ncheckarg
0214         m_firstValue_2->setEnabled(false);
0215         m_secondValue_2->setEnabled(false);
0216         m_style_2->setEnabled(false);
0217     } else {
0218         m_condition_3->setEnabled(true);
0219         m_style_2->setEnabled(true);
0220         if ((text == i18n("between")) || (text == i18n("different from"))) {
0221             m_firstValue_2->setEnabled(true);
0222             m_secondValue_2->setEnabled(true);
0223         } else {
0224             m_firstValue_2->setEnabled(true);
0225             m_secondValue_2->setEnabled(false);
0226         }
0227     }
0228 }
0229 
0230 void ConditionalWidget::slotTextChanged3(const QString & text)
0231 {
0232     if (text == i18n("<none>")) {   // krazy:exclude=i18ncheckarg
0233         m_firstValue_3->setEnabled(false);
0234         m_secondValue_3->setEnabled(false);
0235         m_style_3->setEnabled(false);
0236     } else {
0237         m_style_3->setEnabled(true);
0238         if ((text == i18n("between")) || (text == i18n("different from"))) {
0239             m_firstValue_3->setEnabled(true);
0240             m_secondValue_3->setEnabled(true);
0241         } else {
0242             m_firstValue_3->setEnabled(true);
0243             m_secondValue_3->setEnabled(false);
0244         }
0245     }
0246 }
0247 
0248 /**
0249  * ConditionalDialog
0250  * Sets conditional cell formattings.
0251  */
0252 ConditionalDialog::ConditionalDialog(QWidget* parent, Selection* selection)
0253         : KoDialog(parent),
0254         m_selection(selection),
0255         m_dlg(new ConditionalWidget(this))
0256 {
0257     setButtons(KoDialog::Ok | KoDialog::Cancel);
0258     setCaption(i18n("Conditional Styles"));
0259 
0260     QStringList list(m_selection->activeSheet()->map()->styleManager()->styleNames());
0261 
0262     m_dlg->m_style_1->insertItems(0, list);
0263     m_dlg->m_style_2->insertItems(0, list);
0264     m_dlg->m_style_3->insertItems(0, list);
0265 
0266     setMainWidget(m_dlg);
0267 
0268     connect(this, SIGNAL(okClicked()), this, SLOT(slotOk()));
0269 
0270     init();
0271 }
0272 
0273 void ConditionalDialog::init()
0274 {
0275     QLinkedList<Conditional> conditionList;
0276     QLinkedList<Conditional> otherList;
0277     bool found;
0278     int numCondition;
0279 
0280     QLinkedList<Conditional>::iterator it1;
0281     QLinkedList<Conditional>::iterator it2;
0282 
0283     Sheet* sheet = m_selection->activeSheet();
0284 
0285     conditionList = Cell(sheet, m_selection->marker()).conditions().conditionList();
0286     /* this is the list, but only display the conditions common to all selected
0287        cells*/
0288 
0289     for (int x = m_selection->lastRange().left(); x <= m_selection->lastRange().right(); x++) {
0290         for (int y = m_selection->lastRange().top(); y <= m_selection->lastRange().bottom(); y++) {
0291             otherList = Cell(sheet, x, y).conditions().conditionList();
0292 
0293             it1 = conditionList.begin();
0294             while (it1 != conditionList.end()) {
0295                 debugSheets << "Here";
0296                 found = false;
0297                 for (it2 = otherList.begin(); !found && it2 != otherList.end(); ++it2) {
0298                     debugSheets << "Found:" << found;
0299                     found = ((*it1).value1 == (*it2).value1 &&
0300                              (*it1).value2 == (*it2).value2 &&
0301                              (*it1).cond == (*it2).cond);
0302 
0303                     if (!found)
0304                         continue;
0305 
0306                     if ((*it1).styleName != (*it2).styleName)
0307                         found = false;
0308                 }
0309 
0310                 if (!found) {  /* if it's not here, don't display this condition */
0311                     it1 = conditionList.erase(it1);
0312                 } else {
0313                     ++it1;
0314                 }
0315             }
0316         }
0317     }
0318 
0319     debugSheets << "Conditions:" << conditionList.size();
0320 
0321     m_dlg->m_condition_2->setEnabled(false);
0322     m_dlg->m_condition_3->setEnabled(false);
0323 
0324     m_dlg->m_style_1->setEnabled(false);
0325     m_dlg->m_style_2->setEnabled(false);
0326     m_dlg->m_style_3->setEnabled(false);
0327 
0328     numCondition = 0;
0329     for (it1 = conditionList.begin(); numCondition < 3 && it1 != conditionList.end(); ++it1) {
0330         init(*it1, numCondition);
0331 
0332         ++numCondition;
0333     }
0334 }
0335 
0336 void ConditionalDialog::init(Conditional const & tmp, int numCondition)
0337 {
0338     debugSheets << "Adding" << numCondition;
0339     KComboBox * cb  = 0;
0340     KComboBox * sb  = 0;
0341     KLineEdit * kl1 = 0;
0342     KLineEdit * kl2 = 0;
0343     QString value;
0344     Map *const map = m_selection->activeSheet()->map();
0345     ValueConverter *const converter = map->converter();
0346 
0347     switch (numCondition) {
0348     case 0:
0349         cb  = m_dlg->m_condition_1;
0350         sb  = m_dlg->m_style_1;
0351         kl1 = m_dlg->m_firstValue_1;
0352         kl2 = m_dlg->m_secondValue_1;
0353         break;
0354     case 1:
0355         cb  = m_dlg->m_condition_2;
0356         sb  = m_dlg->m_style_2;
0357         kl1 = m_dlg->m_firstValue_2;
0358         kl2 = m_dlg->m_secondValue_2;
0359         break;
0360     case 2:
0361         cb  = m_dlg->m_condition_3;
0362         sb  = m_dlg->m_style_3;
0363         kl1 = m_dlg->m_firstValue_3;
0364         kl2 = m_dlg->m_secondValue_3;
0365         break;
0366     default:
0367         return;
0368     }
0369 
0370     if (!tmp.styleName.isEmpty()) {
0371         sb->setCurrentIndex(sb->findText(tmp.styleName));
0372         sb->setEnabled(true);
0373     }
0374 
0375     switch (tmp.cond) {
0376     case Conditional::None :
0377     case Conditional::IsTrueFormula: // was unhandled
0378         break;
0379 
0380     case Conditional::Equal :
0381         cb->setCurrentIndex(1);
0382         break;
0383 
0384     case Conditional::Superior :
0385         cb->setCurrentIndex(2);
0386         break;
0387 
0388     case Conditional::Inferior :
0389         cb->setCurrentIndex(3);
0390         break;
0391 
0392     case Conditional::SuperiorEqual :
0393         cb->setCurrentIndex(4);
0394         break;
0395 
0396     case Conditional::InferiorEqual :
0397         cb->setCurrentIndex(5);
0398         break;
0399 
0400     case Conditional::Between :
0401         cb->setCurrentIndex(6);
0402         kl2->setText(converter->asString(tmp.value2).asString());
0403         break;
0404 
0405     case Conditional::Different :
0406         cb->setCurrentIndex(7);
0407         kl2->setText(converter->asString(tmp.value2).asString());
0408         break;
0409     case Conditional::DifferentTo :
0410         cb->setCurrentIndex(8);
0411         break;
0412     }
0413 
0414     if (tmp.cond != Conditional::None) {
0415         kl1->setEnabled(true);
0416         kl1->setText(converter->asString(tmp.value1).asString());
0417     }
0418 }
0419 
0420 Conditional::Type ConditionalDialog::typeOfCondition(KComboBox const * const cb) const
0421 {
0422     Conditional::Type result = Conditional::None;
0423     switch (cb->currentIndex()) {
0424     case 0 :
0425         result = Conditional::None;
0426         break;
0427     case 1 :
0428         result = Conditional::Equal;
0429         break;
0430     case 2 :
0431         result = Conditional::Superior;
0432         break;
0433     case 3 :
0434         result = Conditional::Inferior;
0435         break;
0436     case 4 :
0437         result = Conditional::SuperiorEqual;
0438         break;
0439     case 5 :
0440         result = Conditional::InferiorEqual;
0441         break;
0442     case 6 :
0443         result = Conditional::Between;
0444         break;
0445     case 7 :
0446         result = Conditional::Different;
0447         break;
0448     case 8 :
0449         result = Conditional::DifferentTo;
0450         break;
0451     default:
0452         debugSheets << "Error in list";
0453         break;
0454     }
0455 
0456     return result;
0457 }
0458 
0459 bool ConditionalDialog::checkInputData(KLineEdit const * const edit1,
0460                                        KLineEdit const * const edit2)
0461 {
0462     bool b1 = false;
0463     bool b2 = false;
0464 
0465     if (!edit2->isEnabled())
0466         return true;
0467 
0468     edit1->text().toDouble(&b1);
0469     edit2->text().toDouble(&b2);
0470 
0471     if (b1 != b2) {
0472         if (b1)
0473             KMessageBox::sorry(0, i18n("If the first value is a number, the second value also has to be a number."));
0474         else
0475             KMessageBox::sorry(0, i18n("If the first value is a string, the second value also has to be a string."));
0476         return false;
0477     }
0478 
0479     return true;
0480 }
0481 
0482 bool ConditionalDialog::checkInputData()
0483 {
0484     if (m_dlg->m_firstValue_1->isEnabled() && !checkInputData(m_dlg->m_firstValue_1, m_dlg->m_secondValue_1))
0485         return false;
0486     if (m_dlg->m_firstValue_2->isEnabled() && !checkInputData(m_dlg->m_firstValue_2, m_dlg->m_secondValue_2))
0487         return false;
0488     if (m_dlg->m_firstValue_3->isEnabled() && !checkInputData(m_dlg->m_firstValue_3, m_dlg->m_secondValue_3))
0489         return false;
0490 
0491     return true;
0492 }
0493 
0494 bool ConditionalDialog::getCondition(Conditional & newCondition, const KComboBox * cb,
0495                                      const KLineEdit * edit1, const KLineEdit * edit2,
0496                                      const KComboBox * sb)
0497 {
0498     if (!cb->isEnabled())
0499         return false;
0500 
0501     newCondition.cond = typeOfCondition(cb);
0502     if (newCondition.cond == Conditional::None)
0503         return false;
0504 
0505     Map *const map = m_selection->activeSheet()->map();
0506     ValueParser *const parser = map->parser();
0507 
0508     newCondition.value1 = parser->parse(edit1->text());
0509     newCondition.value2 = parser->parse(edit2->text());
0510     newCondition.styleName = sb->currentText();
0511 
0512     return true;
0513 }
0514 
0515 void ConditionalDialog::slotOk()
0516 {
0517     debugSheets << "slotOk";
0518 
0519     if (!checkInputData())
0520         return;
0521 
0522     debugSheets << "Input data is valid";
0523 
0524     QLinkedList<Conditional> newList;
0525 
0526     Conditional newCondition;
0527 
0528     if (getCondition(newCondition, m_dlg->m_condition_1, m_dlg->m_firstValue_1,
0529                      m_dlg->m_secondValue_1, m_dlg->m_style_1))
0530         newList.append(newCondition);
0531 
0532     if (getCondition(newCondition, m_dlg->m_condition_2, m_dlg->m_firstValue_2,
0533                      m_dlg->m_secondValue_2, m_dlg->m_style_2))
0534         newList.append(newCondition);
0535 
0536     if (getCondition(newCondition, m_dlg->m_condition_3, m_dlg->m_firstValue_3,
0537                      m_dlg->m_secondValue_3, m_dlg->m_style_3))
0538         newList.append(newCondition);
0539 
0540     debugSheets << "Setting conditional list";
0541     ConditionCommand* manipulator = new ConditionCommand();
0542     manipulator->setSheet(m_selection->activeSheet());
0543     manipulator->setConditionList(newList);
0544     manipulator->add(*m_selection);
0545     manipulator->execute(m_selection->canvas());
0546 
0547     accept();
0548 }