/*************************************************************************** * Copyright (C) 2005 by Niklas Knutsson * * nq@altern.org * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * ***************************************************************************/ #include "qalculateunitsdialog.h" #include "qalculate_tde_utils.h" #include "qalculateeditunitdialog.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern tree_struct unit_cats; extern std::vector ia_units; extern PrintOptions printops; extern EvaluationOptions evalops; QalculateUnitsDialog::QalculateUnitsDialog(TQWidget *parent, const char *name) : KDialog(parent, name, false) { unit_edit_dialog = NULL; selected_category = ""; selected_unit = NULL; selected_to_unit = NULL; block_unit_convert = true; TQHBoxLayout *layout = new TQHBoxLayout(this, marginHint(), spacingHint()); setCaption(i18n("Units")); TQVBoxLayout *leftLayout = new TQVBoxLayout(layout, spacingHint()); TQSplitter *splitter = new TQSplitter(TQt::Horizontal, this); splitter->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Expanding); leftLayout->addWidget(splitter); categoryView = new TDEListView(splitter); categoryView->addColumn(i18n("Category")); categoryView->setRootIsDecorated(false); unitView = new TDEListView(splitter); unitView->addColumn(i18n("Unit")); unitView->addColumn(i18n("Names")); unitView->addColumn(i18n("Base")); unitView->setRootIsDecorated(false); convertGroup = new TQGroupBox(3, TQt::Horizontal, i18n("Conversion"), this); convertGroup->setSizePolicy(TQSizePolicy::Expanding, TQSizePolicy::Minimum); convertGroup->setInsideSpacing(spacingHint()); convertGroup->setInsideMargin(spacingHint()); convertButton = new KPushButton(TQIconSet(SmallIcon("reload")), "", convertGroup); fromEdit = new KLineEdit("1", convertGroup); fromEdit->setAlignment(TQt::AlignRight); fromEdit->setMinimumWidth(100); fromLabel = new TQLabel(convertGroup); equalsLabel = new TQLabel("=", convertGroup); equalsLabel->setAlignment(TQt::AlignRight); toEdit = new KLineEdit("1", convertGroup); toEdit->setAlignment(TQt::AlignRight); toEdit->setMinimumWidth(100); toCombo = new KComboBox(convertGroup); leftLayout->addWidget(convertGroup); TQVBoxLayout *buttonLayout = new TQVBoxLayout(layout, spacingHint()); newButton = new TQPushButton(i18n("New"), this); buttonLayout->addWidget(newButton); editButton = new TQPushButton(i18n("Edit"), this); editButton->setEnabled(false); buttonLayout->addWidget(editButton); deleteButton = new TQPushButton(i18n("Delete"), this); deleteButton->setEnabled(false); buttonLayout->addWidget(deleteButton); deactivateButton = new TQPushButton(i18n("Deactivate"), this); deactivateButton->setEnabled(false); buttonLayout->addWidget(deactivateButton); insertButton = new TQPushButton(i18n("Insert"), this); insertButton->setEnabled(false); buttonLayout->addWidget(insertButton); convertResultButton = new TQPushButton(i18n("Convert Result"), this); convertResultButton->setEnabled(false); buttonLayout->addWidget(convertResultButton); buttonLayout->addItem(new TQSpacerItem(0, 0, TQSizePolicy::Minimum, TQSizePolicy::Expanding)); helpButton = new KPushButton(KStdGuiItem::help(), this); buttonLayout->addWidget(helpButton); buttonClose = new KPushButton(KStdGuiItem::close(), this); buttonLayout->addWidget(buttonClose); fromEdit->setFocus(); resize(TQSize(675, 425).expandedTo(size())); connect(buttonClose, TQ_SIGNAL(clicked()), this, TQ_SLOT(close())); connect(newButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(newUnit())); connect(editButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(editUnit())); connect(deleteButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(deleteUnit())); connect(deactivateButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(deactivateUnit())); connect(insertButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(insertUnit())); connect(convertResultButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(convertResult())); connect(unitView, TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(unitSelected())); connect(unitView, TQ_SIGNAL(doubleClicked(TQListViewItem*)), this, TQ_SLOT(unitDoubleClicked(TQListViewItem*))); connect(categoryView, TQ_SIGNAL(selectionChanged()), this, TQ_SLOT(categorySelected())); connect(toCombo, TQ_SIGNAL(activated(int)), this, TQ_SLOT(toUnitSelected(int))); connect(convertButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(convertClicked())); connect(fromEdit, TQ_SIGNAL(returnPressed()), this, TQ_SLOT(convert())); connect(toEdit, TQ_SIGNAL(returnPressed()), this, TQ_SLOT(convertReversed())); connect(fromEdit, TQ_SIGNAL(lostFocus()), this, TQ_SLOT(convert())); connect(toEdit, TQ_SIGNAL(lostFocus()), this, TQ_SLOT(convertReversed())); connect(helpButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(slotHelp())); } QalculateUnitsDialog::~QalculateUnitsDialog() { } void QalculateUnitsDialog::slotHelp() { TDEApplication::kApplication()->invokeHelp("qalculate-managers"); } void QalculateUnitsDialog::updateUnitTree() { unitItems.clear(); comboItems.clear(); categoryItems.clear(); categoryView->clear(); TQListViewItem *i = new TDEListViewItem(categoryView, i18n("All")), *i2; categoryItems[i] = i18n("All"); i->setOpen(true); TQString str; tree_struct *item, *item2; unit_cats.it = unit_cats.items.begin(); if(unit_cats.it != unit_cats.items.end()) { item = &*unit_cats.it; ++unit_cats.it; item->it = item->items.begin(); } else { item = NULL; } str = ""; i2 = i; while(item) { str += "/"; str += item->item.c_str(); i = new TDEListViewItem(i2, item->item.c_str()); i->setOpen(false); categoryItems[i] = str; if(str == selected_category) { categoryView->ensureItemVisible(i); categoryView->setSelected(i, true); } while(item && item->it == item->items.end()) { int str_i = str.findRev("/"); if(str_i < 0) { str = ""; } else { str.truncate(str_i); } item = item->parent; i = i->parent(); i2 = i; } if(item) { item2 = &*item->it; if(item->it == item->items.begin()) i2 = i; ++item->it; item = item2; item->it = item->items.begin(); } } if(!unit_cats.objects.empty()) { //add "Uncategorized" category if there are units without category i = new TDEListViewItem(categoryView, i18n("Uncategorized")); categoryItems[i] = i18n("Uncategorized"); if(selected_category == i18n("Uncategorized")) { categoryView->ensureItemVisible(i); categoryView->setSelected(i, true); } } if(!ia_units.empty()) { //add "Inactive" category if there are inactive units i = new TDEListViewItem(categoryView, i18n("Inactive")); categoryItems[i] = i18n("Inactive"); if(selected_category == i18n("Inactive")) { categoryView->ensureItemVisible(i); categoryView->setSelected(i, true); } } if(!categoryView->selectedItem()) { //if no category has been selected (previously selected has been renamed/deleted), select "All" selected_category = i18n("All"); TQListViewItemIterator it(categoryView); if(it.current()) categoryView->setSelected(it.current(), true); } } #define UPDATE_SELECTED_UNIT TQListViewItem *i = unitView->selectedItem(); if(!i) return; selected_unit = unitItems[i]; if(!selected_unit) return; #define CHECK_IF_UNIT_STILL_THERE if(!CALCULATOR->stillHasUnit(selected_unit)) {KMessageBox::error(this, i18n("Unit does not exist anymore.")); emit unitsChanged(); return;} void QalculateUnitsDialog::insertUnit() { UPDATE_SELECTED_UNIT CHECK_IF_UNIT_STILL_THERE emit insertRequest(selected_unit); } void QalculateUnitsDialog::convertResult() { UPDATE_SELECTED_UNIT CHECK_IF_UNIT_STILL_THERE emit convertRequest(selected_unit); } void QalculateUnitsDialog::deactivateUnit() { UPDATE_SELECTED_UNIT CHECK_IF_UNIT_STILL_THERE selected_unit->setActive(!selected_unit->isActive()); emit unitsChanged(); } void QalculateUnitsDialog::deleteUnit() { UPDATE_SELECTED_UNIT CHECK_IF_UNIT_STILL_THERE if(selected_unit->isLocal()) { if(selected_unit->isUsedByOtherUnits()) { //do not delete units that are used by other units KMessageBox::error(this, i18n("Cannot delete unit as it is needed by other units.")); return; } //ensure that all references are removed in Calculator selected_unit->destroy(); //update menus and trees emit unitsChanged(); } } void QalculateUnitsDialog::editUnit() { UPDATE_SELECTED_UNIT CHECK_IF_UNIT_STILL_THERE if(!unit_edit_dialog) { unit_edit_dialog = new QalculateEditUnitDialog(this); } Unit *u = unit_edit_dialog->editUnit(TQString::null, selected_unit); if(u) { selected_unit = u; if(!u->isActive()) { selected_category = i18n("Inactive"); } else if(u->category().empty()) { selected_category = i18n("Uncategorized"); } else { selected_category = "/"; selected_category += u->category().c_str(); } emit unitsChanged(); } } void QalculateUnitsDialog::newUnit() { if(!unit_edit_dialog) { unit_edit_dialog = new QalculateEditUnitDialog(this); } Unit *u = NULL; if(selected_category.isEmpty() || selected_category[0] != '/') { u = unit_edit_dialog->editUnit(); } else { TQString str = selected_category; str.remove(0, 1); u = unit_edit_dialog->editUnit(str); } if(u) { selected_unit = u; if(!u->isActive()) { selected_category = i18n("Inactive"); } else if(u->category().empty()) { selected_category = i18n("Uncategorized"); } else { selected_category = "/"; selected_category += u->category().c_str(); } emit unitsChanged(); } } void QalculateUnitsDialog::unitDoubleClicked(TQListViewItem*i) { selected_unit = unitItems[i]; if(!selected_unit) return; CHECK_IF_UNIT_STILL_THERE if(!unit_edit_dialog) { unit_edit_dialog = new QalculateEditUnitDialog(this); } Unit *u = unit_edit_dialog->editUnit(TQString::null, selected_unit); if(u) { selected_unit = u; if(!u->isActive()) { selected_category = i18n("Inactive"); } else if(u->category().empty()) { selected_category = i18n("Uncategorized"); } else { selected_category = "/"; selected_category += u->category().c_str(); } emit unitsChanged(); } } void QalculateUnitsDialog::unitSelected() { TQListViewItem *selected = unitView->selectedItem(); if(selected) { Unit *u = unitItems[selected]; if(!CALCULATOR->stillHasUnit(u)) { KMessageBox::error(this, i18n("Unit does not exist anymore.")); selected_unit = NULL; emit unitsChanged(); return; } //remember selection selected_unit = u; editButton->setEnabled(true); insertButton->setEnabled(u->isActive()); convertResultButton->setEnabled(true); deleteButton->setEnabled(u->isLocal()); deactivateButton->setEnabled(true); convertGroup->setEnabled(true); fromLabel->setText(u->print(true, printops.abbreviate_names, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) fromLabel).c_str()); if(u->isActive()) deactivateButton->setText(i18n("Deactivate")); else deactivateButton->setText(i18n("Activate")); } else { editButton->setEnabled(false); insertButton->setEnabled(false); deleteButton->setEnabled(false); deactivateButton->setEnabled(false); convertResultButton->setEnabled(false); convertGroup->setEnabled(false); selected_unit = NULL; } if(!block_unit_convert) convert(); } void QalculateUnitsDialog::addUnitTreeItem(Unit *u) { TQString snames, sbase; //display name, plural name and short name in the second column AliasUnit *au; for(size_t i = 1; i <= u->countNames(); i++) { if(i > 1) snames += " / "; snames += u->getName(i).name.c_str(); } //depending on unit type display relation to base unit(s) switch(u->subtype()) { case SUBTYPE_COMPOSITE_UNIT: { snames = ""; sbase = ((CompositeUnit*) u)->print(false, true, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) unitView).c_str(); break; } case SUBTYPE_ALIAS_UNIT: { au = (AliasUnit*) u; sbase = au->firstBaseUnit()->preferredDisplayName(printops.abbreviate_names, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) unitView).name.c_str(); if(au->firstBaseExponent() != 1) { sbase += POWER; sbase += TQString::number(au->firstBaseExponent()); } break; } case SUBTYPE_BASE_UNIT: { sbase = ""; break; } } TQListViewItem *i = new TDEListViewItem(unitView, u->title(true).c_str(), snames, sbase); unitItems[i] = u; if(u == selected_unit) { unitView->setSelected(i, true); } } void QalculateUnitsDialog::categorySelected() { block_unit_convert = true; TQListViewItem *selected = categoryView->selectedItem(); bool no_cat = false, b_all = false, b_inactive = false; unitView->clear(); unitItems.clear(); if(!selected) { selected_category = ""; unitSelected(); return; } selected_category = categoryItems[selected]; if(selected_category == i18n("All")) { b_all = true; } else if(selected_category == i18n("Uncategorized")) { no_cat = true; } else if(selected_category == i18n("Inactive")) { b_inactive = true; } if(!b_all && !no_cat && !b_inactive && selected_category[0] == '/') { std::string str = selected_category.ascii(); str.erase(str.begin()); for(size_t i = 0; i < CALCULATOR->units.size(); i++) { if(CALCULATOR->units[i]->isActive() && CALCULATOR->units[i]->category().substr(0, selected_category.length() - 1) == str) { addUnitTreeItem(CALCULATOR->units[i]); } } } else { std::string str = selected_category.ascii(); for(size_t i = 0; i < CALCULATOR->units.size(); i++) { if((b_inactive && !CALCULATOR->units[i]->isActive()) || (CALCULATOR->units[i]->isActive() && (b_all || (no_cat && CALCULATOR->units[i]->category().empty()) || (!b_inactive && CALCULATOR->units[i]->category() == str)))) { addUnitTreeItem(CALCULATOR->units[i]); } } } if(!selected_unit || !unitView->selectedItem()) { TQListViewItemIterator it(unitView); if(it.current()) unitView->setSelected(it.current(), true); } //generate convert to menu toCombo->blockSignals(true); toCombo->clear(); comboItems.clear(); int i = 0, h = -1; //add all units in units tree to menu TQListViewItemIterator it(unitView); Unit *u; while(it.current()) { u = unitItems[it.current()]; if(!selected_to_unit) { selected_to_unit = u; } if(u) { toCombo->insertItem(it.current()->text(0)); comboItems.push_back(u); if(selected_to_unit == u) h = i; } i++; ++it; } //if no items were added to the menu, reset selected unit if(i == 0) { selected_to_unit = NULL; } else { //if no menu item was selected, select the first if(h < 0) { h = 0; TQListViewItemIterator it2(unitView); if(it2.current()) { selected_to_unit = unitItems[it2.current()]; } else { selected_to_unit = NULL; } } toCombo->setCurrentItem(h); } toCombo->blockSignals(false); block_unit_convert = false; //update conversion display convert(); } void QalculateUnitsDialog::toUnitSelected(int index) { if(index < (int) comboItems.size()) { selected_to_unit = comboItems[index]; convert(); } } void QalculateUnitsDialog::convertClicked() { if(toEdit->hasFocus()) { convertReversed(); } else { convert(); } } void QalculateUnitsDialog::convert() { if(selected_unit && selected_to_unit) { //determine conversion direction bool b = false; if(selected_unit == selected_to_unit) { toEdit->setText(fromEdit->text()); } else { EvaluationOptions eo; eo.approximation = APPROXIMATION_APPROXIMATE; eo.parse_options.angle_unit = evalops.parse_options.angle_unit; PrintOptions po; po.is_approximate = &b; po.number_fraction_format = FRACTION_DECIMAL; MathStructure v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(fromEdit->text().ascii(), evalops.parse_options), selected_unit, selected_to_unit, eo); toEdit->setText(v_mstruct.print(po).c_str()); b = b || v_mstruct.isApproximate(); } if(b && printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) equalsLabel)) { equalsLabel->setText(SIGN_ALMOST_EQUAL); } else { equalsLabel->setText("="); } } } void QalculateUnitsDialog::convertReversed() { if(selected_unit && selected_to_unit) { bool b = false; if(selected_unit == selected_to_unit) { fromEdit->setText(toEdit->text()); } else { EvaluationOptions eo; eo.approximation = APPROXIMATION_APPROXIMATE; eo.parse_options.angle_unit = evalops.parse_options.angle_unit; PrintOptions po; po.is_approximate = &b; po.number_fraction_format = FRACTION_DECIMAL; MathStructure v_mstruct = CALCULATOR->convert(CALCULATOR->unlocalizeExpression(toEdit->text().ascii(), evalops.parse_options), selected_to_unit, selected_unit, eo); fromEdit->setText(v_mstruct.print(po).c_str()); b = b || v_mstruct.isApproximate(); } if(b && printops.use_unicode_signs && can_display_unicode_string_function(SIGN_ALMOST_EQUAL, (void*) equalsLabel)) { equalsLabel->setText(SIGN_ALMOST_EQUAL); } else { equalsLabel->setText("="); } } } void QalculateUnitsDialog::keyPressEvent(TQKeyEvent *e) { if(e->key() == Key_Return) { convertClicked(); e->accept(); return; } KDialog::keyPressEvent(e); } #include "qalculateunitsdialog.moc"