/*************************************************************************** * Copyright (C) 2005. 2007 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 "qalculateexpressionedit.h" #include "qalculate_tde_utils.h" #include "kqalculate.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include extern std::vector modes; extern KQalculate *mainWin; extern PrintOptions printops; extern EvaluationOptions evalops; extern bool rpn_mode, rpn_keypad_only; extern tree_struct function_cats, unit_cats, variable_cats; extern std::vector ia_units, ia_variables, ia_functions; class QalculateExpressionEditListBoxItem : public TQListBoxItem { public: QalculateExpressionEditListBoxItem(ExpressionItem *eitem); virtual ~QalculateExpressionEditListBoxItem(); int height(const TQListBox*) const; int width(const TQListBox*) const; bool reuse(ExpressionItem *newItem); ExpressionItem *item; protected: void paint(TQPainter*); private: TQString title; int italic_index; bool rich_text; }; QalculateExpressionEdit::QalculateExpressionEdit(bool connected_to_main_win, TQWidget *parent, const char *name) : KLineEdit(parent, name) { qalculateCompletionBox = new QalculateExpressionEditCompletionBox(this); qalculateCompletion = new TDECompletion(); setCompletionObject(qalculateCompletion); pos_before_completion = 0; b_main = connected_to_main_win; dont_change_index = false; expression_history_index = -1; setCompletionMode(TDEGlobalSettings::CompletionPopup); setKeyCompression(false); //check for position changes regularly prev_position = 0; pos_timer = startTimer(50); connect(qalculateCompletionBox, TQ_SIGNAL(highlighted(TQListBoxItem*)), this, TQ_SLOT(insertCompletion(TQListBoxItem*))); connect(qalculateCompletionBox, TQ_SIGNAL(userCancelled(const TQString&)), this, TQ_SLOT(cancelCompletion(const TQString&))); connect(this, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(onTextChanged(const TQString&))); } QalculateExpressionEdit::~QalculateExpressionEdit() {} void QalculateExpressionEdit::timerEvent(TQTimerEvent *event) { if(event->timerId() == pos_timer) { if(cursorPosition() != prev_position) { prev_position = cursorPosition(); emit cursorMoved(); } } else { KLineEdit::timerEvent(event); } } void QalculateExpressionEdit::onTextChanged(const TQString &str) { if(str.isEmpty()) { if(qalculateCompletionBox) { qalculateCompletionBox->hide(); qalculateCompletionBox->clear(); } return; } prev_position = cursorPosition(); } void QalculateExpressionEdit::cancelCompletion(const TQString &str) { int new_pos = pos_before_completion; setText(str); setCursorPosition(new_pos); } void QalculateExpressionEdit::enableCompletion() { setCompletionMode(TDEGlobalSettings::CompletionPopup); } void QalculateExpressionEdit::disableCompletion() { setCompletionMode(TDEGlobalSettings::CompletionNone); } bool QalculateExpressionEdit::completionEnabled() const { return completionMode() == TDEGlobalSettings::CompletionPopup; } TQPopupMenu *QalculateExpressionEdit::createPopupMenu() { setCompletionObject(NULL); TQPopupMenu *menu = KLineEdit::createPopupMenu(); setCompletionObject(qalculateCompletion); menu->insertSeparator(); if(completionMode() == TDEGlobalSettings::CompletionPopup) menu->insertItem(i18n("Disable Completion"), this, TQ_SLOT(disableCompletion())); else menu->insertItem(i18n("Enable Completion"), this, TQ_SLOT(enableCompletion())); if(b_main) { menu->insertSeparator(); mainWin->ActionReadPrecision->plug(menu); mainWin->ActionLimitImplicitMultiplication->plug(menu); mainWin->ActionRPNMode->plug(menu); TQPopupMenu *modes_menu = new TQPopupMenu(menu); TQObject::connect(modes_menu, TQ_SIGNAL(activated(int)), mainWin, TQ_SLOT(loadMode(int))); for(size_t i = 0; i < modes.size(); i++) { modes_menu->insertItem(modes[i].name, i, i); } modes_menu->insertSeparator(); mainWin->ActionSaveModeAs->plug(modes_menu); mainWin->ActionDeleteMode->plug(modes_menu); menu->insertItem(i18n("Meta Modes"), modes_menu); menu->insertSeparator(); mainWin->ActionInsertMatrix->plug(menu); mainWin->ActionInsertVector->plug(menu); } return menu; } #if TQT_VERSION >= 0x030200 #define GET_SELECTION int start = selectionStart(), end = -1; if(start >= 0) end = start + selectedText().length(); #else #define GET_SELECTION int start = -1, end = -1; getSelection(&start, &end); #endif #define RESTORE_SELECTION if(start > 0) setSelection(start, end - start); void QalculateExpressionEdit::addToHistory(const TQString &str) { for(TQStringList::Iterator it = expression_history.begin(); it != expression_history.end(); ++it) { if(*it == str) { expression_history.erase(it); break; } } if(expression_history.size() >= 25) { expression_history.pop_back(); } expression_history.insert(expression_history.begin(), str); expression_history_index = 0; } void QalculateExpressionEdit::setAfterCompletionPosition() { setCursorPosition(cpos_ac); } void QalculateExpressionEdit::insertCompletion(TQListBoxItem *li) { ExpressionItem *item = ((QalculateExpressionEditListBoxItem*) li)->item; setSelection(cstart, cend - cstart + 1); TQString str = completed_text; const ExpressionName *ename = NULL, *ename_r = NULL; ename_r = &item->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) this); for(size_t name_i = 0; name_i <= item->countNames() && !ename; name_i++) { if(name_i == 0) { ename = ename_r; } else { ename = &item->getName(name_i); if(!ename || ename == ename_r || ename->plural || (ename->unicode && (!printops.use_unicode_signs || !can_display_unicode_string_function(ename->name.c_str(), (void*) this)))) { ename = NULL; } } if(ename) { if(str.length() <= ename->name.length()) { for(size_t i = 0; i < str.length(); i++) { if(ename->name[i] != str[i]) { ename = NULL; break; } } } else { ename = NULL; } } } for(size_t name_i = 1; name_i <= item->countNames() && !ename; name_i++) { ename = &item->getName(name_i); if(!ename || ename == ename_r || (!ename->plural && !(ename->unicode && (!printops.use_unicode_signs || !can_display_unicode_string_function(ename->name.c_str(), (void*) this))))) { ename = NULL; } if(ename) { if(str.length() <= ename->name.length()) { for(size_t i = 0; i < str.length(); i++) { if(ename->name[i] != str[i]) { ename = NULL; break; } } } else { ename = NULL; } } } if(!ename) ename = ename_r; if(!ename) return; if(item->type() == TYPE_FUNCTION) { if(text()[cend + 1] == '(') { insert(ename->name.c_str()); cend = cstart + ename->name.length() - 1; cpos_ac = cend + 2; } else { str = ename->name.c_str(); str += "()"; insert(str); cend = cstart + str.length() - 1; cpos_ac = cend; } } else { insert(ename->name.c_str()); cend = cstart + ename->name.length() - 1; cpos_ac = cend + 1; } setCursorPosition(cpos_ac); } bool matchesExpressionItem(const TQString &str, ExpressionItem *item) { bool b_match = false; for(size_t name_i = 1; !b_match && name_i <= item->countNames(); name_i++) { const ExpressionName *ename = &item->getName(name_i); if(ename && str.length() <= ename->name.length()) { b_match = true; for(size_t i = 0; i < str.length(); i++) { if(ename->name[i] != str[i]) { b_match = false; break; } } } } return b_match; } void QalculateExpressionEdit::makeCompletion(const TQString &str) { if(cursorPosition() <= 0 || str.isEmpty()) { if(qalculateCompletionBox) { qalculateCompletionBox->hide(); qalculateCompletionBox->clear(); } return; } uint start = (uint) cursorPosition(); cend = (int) start - 1; TQString str2 = str; str2.truncate(start); const char *cstr = str2.ascii(); bool non_number_before = false; size_t cpos = strlen(cstr) - 1; start--; while(true) { while(cpos > 0 && (unsigned char) cstr[cpos] >= 0x80 && (unsigned char) cstr[cpos] <= 0xBF) { cpos--; } if(!CALCULATOR->utf8_pos_is_valid_in_name((char*) &cstr[cpos])) { start++; break; } else if(is_in(NUMBERS, cstr[cpos])) { if(non_number_before) { start++; break; } } else { non_number_before = true; } if(start == 0 || cpos == 0) break; start--; cpos--; } if(start >= (uint) cursorPosition()) { if(qalculateCompletionBox) { qalculateCompletionBox->hide(); qalculateCompletionBox->clear(); } return; } cstart = (int) start; str2.remove(0, start); completed_text = str2; pos_before_completion = cursorPosition(); qalculateCompletionBox->setCancelledText(text()); matched_items.clear(); if(evalops.parse_options.functions_enabled) { for(size_t i = 0; i < CALCULATOR->functions.size(); i++) { if(CALCULATOR->functions[i]->isActive()) { if(matchesExpressionItem(str2, CALCULATOR->functions[i])) { matched_items.push_back(CALCULATOR->functions[i]); } } } } if(evalops.parse_options.variables_enabled) { for(size_t i = 0; i < CALCULATOR->variables.size(); i++) { if(CALCULATOR->variables[i]->isActive()) { if(matchesExpressionItem(str2, CALCULATOR->variables[i])) { matched_items.push_back(CALCULATOR->variables[i]); } } } } if(evalops.parse_options.units_enabled) { for(size_t i = 0; i < CALCULATOR->units.size(); i++) { if(CALCULATOR->units[i]->isActive() && CALCULATOR->units[i]->subtype() != SUBTYPE_COMPOSITE_UNIT) { if(matchesExpressionItem(str2, CALCULATOR->units[i])) { matched_items.push_back(CALCULATOR->units[i]); } } } } if(matched_items.isEmpty()) { if(qalculateCompletionBox) { qalculateCompletionBox->hide(); qalculateCompletionBox->clear(); } } else { setCompletedItems(); } } void QalculateExpressionEdit::updateCompletion() { } void QalculateExpressionEdit::wrapSelection() { GET_SELECTION if(start >= 0) { deselect(); setCursorPosition(start); insert("("); setCursorPosition(end + 1); insert(")"); setSelection(start, end - start + 2); } } void QalculateExpressionEdit::keyPressEvent(TQKeyEvent *e) { if(e->key() == Key_Enter || e->key() == Key_Return) { if(b_main) { mainWin->execute(); e->accept(); return; } else { return KLineEdit::keyPressEvent(e); } } if(e->state() & ControlButton && e->key() == Key_Asterisk) { if(rpn_mode && b_main && (!rpn_keypad_only || e->state() & Keypad)) { mainWin->calculateRPN(OPERATION_RAISE); return; } insert("^"); e->accept(); return; } if(e->state() != 0 && e->state() != ShiftButton && e->state() != Keypad) { KLineEdit::keyPressEvent(e); return; } switch(e->key()) { case Key_Period: { if(e->state() == Keypad) { insert(CALCULATOR->getDecimalPoint().c_str()); e->accept(); return; } break; } case Key_Comma: { if(e->state() == Keypad) { insert(CALCULATOR->getDecimalPoint().c_str()); e->accept(); return; } break; } case Key_AsciiCircum: { if(rpn_mode && b_main && (!rpn_keypad_only || e->state() & Keypad)) { mainWin->calculateRPN(OPERATION_RAISE); return; } if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^"); e->accept(); return; } case Key_Slash: { if(rpn_mode && b_main && (!rpn_keypad_only || e->state() & Keypad)) { mainWin->calculateRPN(OPERATION_DIVIDE); return; } if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } if(printops.use_unicode_signs && printops.division_sign == DIVISION_SIGN_DIVISION && can_display_unicode_string_function(SIGN_DIVISION, (void*) this)) { insert(SIGN_DIVISION); e->accept(); return; } break; } case Key_Asterisk: { if(rpn_mode && b_main && (!rpn_keypad_only || e->state() & Keypad)) { mainWin->calculateRPN(OPERATION_MULTIPLY); return; } if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT && can_display_unicode_string_function(SIGN_MULTIDOT, (void*) this)) { insert(SIGN_MULTIDOT); } else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_DOT && can_display_unicode_string_function(SIGN_SMALLCIRCLE, (void*) this)) { insert(SIGN_SMALLCIRCLE); } else if(printops.use_unicode_signs && printops.multiplication_sign == MULTIPLICATION_SIGN_X && can_display_unicode_string_function(SIGN_MULTIPLICATION, (void*) this)) { insert(SIGN_MULTIPLICATION); } else { insert("*"); } e->accept(); return; } case Key_Plus: { if(rpn_mode && b_main && (!rpn_keypad_only || e->state() & Keypad)) { mainWin->calculateRPN(OPERATION_ADD); return; } if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } e->accept(); break; } case Key_Minus: { if(rpn_mode && b_main && (!rpn_keypad_only || e->state() & Keypad)) { mainWin->calculateRPN(OPERATION_SUBTRACT); return; } if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } if(printops.use_unicode_signs && can_display_unicode_string_function(SIGN_MINUS, (void*) this)) { insert(SIGN_MINUS); e->accept(); return; } break; } case Key_Up: {} case Key_PageUp: { if(expression_history_index + 1 < (int) expression_history.size()) { expression_history_index++; dont_change_index = true; setText(expression_history[expression_history_index]); dont_change_index = false; } e->accept(); return; } case Key_Down: {} case Key_PageDown: { if(expression_history_index > -1) { expression_history_index--; dont_change_index = true; if(expression_history_index < 0) { clear(); } else { setText(expression_history[expression_history_index]); } dont_change_index = false; } e->accept(); return; } case Key_BraceLeft: {} case Key_BraceRight: { return; } case 0xffff: { if(e->text().utf8() == "⁰") { insert("°"); e->accept(); return; } if(e->text().utf8() == "¹") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^1"); e->accept(); return; } if(e->text().utf8() == "²") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^2"); e->accept(); return; } if(e->text().utf8() == "³") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^3"); e->accept(); return; } if(e->text().utf8() == "⁴") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^4"); e->accept(); return; } if(e->text().utf8() == "⁵") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^5"); e->accept(); return; } if(e->text().utf8() == "⁶") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^6"); e->accept(); return; } if(e->text().utf8() == "⁷") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^7"); e->accept(); return; } if(e->text().utf8() == "⁸") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^8"); e->accept(); return; } if(e->text().utf8() == "⁹") { if(!evalops.parse_options.rpn) { wrapSelection(); deselect(); } insert("^9"); e->accept(); return; } break; } } KLineEdit::keyPressEvent(e); } bool QalculateExpressionEdit::eventFilter(TQObject *o, TQEvent *ev) { if(o == this && ev->type() == TQEvent::KeyPress) { TQKeyEvent *e = static_cast(ev); if((e->key() == TQt::Key_Return || e->key() == TQt::Key_Enter) && qalculateCompletionBox && qalculateCompletionBox->isVisible()) { if(qalculateCompletionBox->selectedItem()) { KCursor::autoHideEventFilter(this, ev); e->accept(); qalculateCompletionBox->hide(); deselect(); return true; } else { qalculateCompletionBox->hide(); return false; } } } return KLineEdit::eventFilter(o, ev); } void set_title(ExpressionItem *item, TQString &title) { if(item->type() != TYPE_VARIABLE || !item->title(false).empty()) { title = item->title().c_str(); } else { Variable *v = (Variable*) item; if(is_answer_variable(v)) { title = i18n("a previous result"); } else if(v->isKnown()) { if(((KnownVariable*) v)->isExpression()) { title = CALCULATOR->localizeExpression(((KnownVariable*) v)->expression()).c_str(); } else { if(((KnownVariable*) v)->get().isMatrix()) { title = i18n("matrix"); } else if(((KnownVariable*) v)->get().isVector()) { title = i18n("vector"); } else { title = CALCULATOR->printMathStructureTimeOut(((KnownVariable*) v)->get(), 30).c_str(); } } } else { if(((UnknownVariable*) v)->assumptions()) { switch(((UnknownVariable*) v)->assumptions()->sign()) { case ASSUMPTION_SIGN_POSITIVE: { title = i18n("positive"); break; } case ASSUMPTION_SIGN_NONPOSITIVE: { title = i18n("non-positive"); break; } case ASSUMPTION_SIGN_NEGATIVE: { title = i18n("negative"); break; } case ASSUMPTION_SIGN_NONNEGATIVE: { title = i18n("non-negative"); break; } case ASSUMPTION_SIGN_NONZERO: { title = i18n("non-zero"); break; } default: {} } if(!title.isEmpty() && !((UnknownVariable*) v)->assumptions()->type() == ASSUMPTION_TYPE_NONE) title += " "; switch(((UnknownVariable*) v)->assumptions()->type()) { case ASSUMPTION_TYPE_INTEGER: { title += i18n("integer"); break; } case ASSUMPTION_TYPE_RATIONAL: { title += i18n("rational"); break; } case ASSUMPTION_TYPE_REAL: { title += i18n("real"); break; } case ASSUMPTION_TYPE_COMPLEX: { title += i18n("complex"); break; } case ASSUMPTION_TYPE_NUMBER: { title += i18n("number"); break; } case ASSUMPTION_TYPE_NONMATRIX: { title += i18n("(not matrix)"); break; } default: {} } if(title.isEmpty()) title = i18n("unknown"); } else { title = i18n("default assumptions"); } } } } std::string sub_suffix(const ExpressionName *ename) { size_t i = ename->name.rfind('_'); bool b = i == std::string::npos || i == ename->name.length() - 1 || i == 0; size_t i2 = 1; std::string str; if(b) { if(is_in(NUMBERS, ename->name[ename->name.length() - 1])) { while(ename->name.length() > i2 + 1 && is_in(NUMBERS, ename->name[ename->name.length() - 1 - i2])) { i2++; } } str += ename->name.substr(0, ename->name.length() - i2); } else { str += ename->name.substr(0, i); } str += ""; if(b) str += ename->name.substr(ename->name.length() - i2, i2); else str += ename->name.substr(i + 1, ename->name.length() - (i + 1)); str += ""; return str; } TQString makeListName(ExpressionItem *item, TQWidget *w, int *italic_index, bool *rich_text) { std::string str; const ExpressionName *ename, *ename_r; *rich_text = false; bool b = false; ename_r = &item->preferredInputName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) w); if(ename_r->suffix && ename_r->name.length() > 1) { str = sub_suffix(ename_r); *rich_text = true; } else { str = ename_r->name; } if(item->type() == TYPE_FUNCTION) str += "()"; for(size_t name_i = 1; name_i <= item->countNames(); name_i++) { ename = &item->getName(name_i); if(ename && ename != ename_r && !ename->plural && (!ename->unicode || can_display_unicode_string_function(ename->name.c_str(), (void*) w))) { str += " "; if(!b) { *italic_index = str.length(); *rich_text = true; str += ""; b = true; } if(ename->suffix && ename->name.length() > 1) { str += sub_suffix(ename); } else { str += ename->name; } if(item->type() == TYPE_FUNCTION) str += "()"; } } if(b) str += ""; return str.c_str(); } QalculateExpressionEditListBoxItem::QalculateExpressionEditListBoxItem(ExpressionItem *eitem) : TQListBoxItem() { item = eitem; italic_index = -1; setText(makeListName(item, listBox(), &italic_index, &rich_text)); set_title(item, title); } QalculateExpressionEditListBoxItem::~QalculateExpressionEditListBoxItem() { } #if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2 TQString rPixelSqueeze(const TQString& name, const TQFontMetrics& fontMetrics, uint maxPixels) { uint nameWidth = fontMetrics.width(name); if (maxPixels < nameWidth) { TQString tmp = name; const uint em = fontMetrics.maxWidth(); maxPixels -= fontMetrics.width("..."); while (maxPixels < nameWidth && !tmp.isEmpty()) { int length = tmp.length(); int delta = em ? (nameWidth - maxPixels) / em : length; if(delta < 1) delta = 1; else if(length < delta) delta = length; tmp.remove(length - delta, delta); nameWidth = fontMetrics.width(tmp); } return (tmp + "..."); } return name; } #endif void QalculateExpressionEditListBoxItem::paint(TQPainter *painter) { int itemHeight = height(listBox()); int entryWidth = listBox()->width() - listBox()->style().pixelMetric(TQStyle::PM_ScrollBarExtent) - 2 * listBox()->style().pixelMetric(TQStyle::PM_DefaultFrameWidth); int titleWidth = (entryWidth / 2) - 1; int nameWidth = entryWidth - titleWidth - 2; if(!text().isEmpty()) { TQString squeezedText; if(rich_text) { TQSimpleRichText rt(text(), painter->font()); rt.setWidth(entryWidth); if(rt.widthUsed() > nameWidth - 1) { squeezedText = text(); if(italic_index > 0) squeezedText.truncate(italic_index); #if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2 squeezedText = rPixelSqueeze(squeezedText, listBox()->fontMetrics(), nameWidth); #else squeezedText = KStringHandler::rPixelSqueeze(squeezedText, listBox()->fontMetrics(), nameWidth); #endif painter->drawText(0, 0, nameWidth, itemHeight, TQt::AlignLeft | TQt::AlignVCenter, squeezedText); } else { TQColorGroup cg = listBox()->colorGroup(); cg.setColor(TQColorGroup::Text, painter->pen().color()); rt.draw(painter, 1, 0, TQRect(0, 0, nameWidth - 1, itemHeight), cg, &painter->brush()); } } else { #if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2 squeezedText = rPixelSqueeze(text(), listBox()->fontMetrics(), nameWidth); #else squeezedText = KStringHandler::rPixelSqueeze(text(), listBox()->fontMetrics(), nameWidth); #endif painter->drawText(0, 0, nameWidth, itemHeight, TQt::AlignLeft | TQt::AlignVCenter, squeezedText); } #if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2 squeezedText = rPixelSqueeze(title, listBox()->fontMetrics(), titleWidth); #else squeezedText = KStringHandler::rPixelSqueeze(title, listBox()->fontMetrics(), titleWidth); #endif TQFont font = painter->font(); font.setItalic(true); painter->setFont(font); painter->drawText(entryWidth - titleWidth, 0, titleWidth, itemHeight, TQt::AlignLeft | TQt::AlignVCenter, squeezedText); } } int QalculateExpressionEditListBoxItem::height(const TQListBox *lb) const { int h; h = lb->fontMetrics().lineSpacing() + 4; return TQMAX(h, TQApplication::globalStrut().height()); } int QalculateExpressionEditListBoxItem::width(const TQListBox *lb) const { return TQMAX(lb->fontMetrics().width(text()) + 6, TQApplication::globalStrut().width()); } bool QalculateExpressionEditListBoxItem::reuse(ExpressionItem *newItem) { if(item == newItem) return false; item = newItem; italic_index = -1; setText(makeListName(item, listBox(), &italic_index, &rich_text)); set_title(item, title); return true; } QalculateExpressionEditCompletionBox::QalculateExpressionEditCompletionBox(TQWidget *parent, const char *name) : TDECompletionBox(parent, name) { } QalculateExpressionEditCompletionBox::~QalculateExpressionEditCompletionBox() { } void QalculateExpressionEditCompletionBox::setItems(const TQValueVector& items) { bool block = signalsBlocked(); blockSignals(true); TQListBoxItem* item = firstItem(); if(!item) { insertItemList(items); } else { //Keep track of whether we need to change anything, //so we can avoid a repaint for identical updates, //to reduce flicker bool dirty = false; #if TQT_VERSION >= 0x030200 TQValueVector::ConstIterator it = items.constBegin(); const TQValueVector::ConstIterator itEnd = items.constEnd(); #else TQValueVector::ConstIterator it = items.begin(); const TQValueVector::ConstIterator itEnd = items.end(); #endif for (; it != itEnd; ++it) { if(item) { const bool changed = ((QalculateExpressionEditListBoxItem*) item)->reuse(*it); dirty = dirty || changed; item = item->next(); } else { dirty = true; //Inserting an item is a way of making this dirty insertItem(new QalculateExpressionEditListBoxItem(*it)); } } //If there is an unused item, mark as dirty -> less items now if(item) dirty = true; TQListBoxItem* tmp = item; while((item = tmp)) { tmp = item->next(); delete item; } if(dirty) triggerUpdate(false); } sort(); if(isVisible() && size().height() != sizeHint().height()) { #if TDE_VERSION_MAJOR < 4 && TDE_VERSION_MINOR < 2 hide(); popup(); #else sizeAndPosition(); #endif } blockSignals(block); // Trigger d->down_workaround = true within TDECompletionBox TQStringList dummy; TDECompletionBox::insertItems(dummy, 1); } void QalculateExpressionEditCompletionBox::insertItemList(const TQValueVector & list, int index) { if(index < 0) index = count(); for(TQValueVector::ConstIterator it = list.begin(); it != list.end(); ++it) { insertItem(new QalculateExpressionEditListBoxItem(*it), index++); } } void QalculateExpressionEdit::setCompletedItems() { TQString txt; if(qalculateCompletionBox && qalculateCompletionBox->isVisible()) { // The popup is visible already - do the matching on the initial string, // not on the currently selected one. txt = qalculateCompletionBox->cancelledText(); } else { txt = text(); } if(!matched_items.isEmpty() && !(matched_items.size() == 1 && matched_items[0]->hasName(txt.ascii()))) { if(qalculateCompletionBox->isVisible()) { bool wasSelected = qalculateCompletionBox->isSelected(qalculateCompletionBox->currentItem()); const TQString currentSelection = qalculateCompletionBox->currentText(); qalculateCompletionBox->setItems(matched_items); TQListBoxItem* item = qalculateCompletionBox->findItem(currentSelection, TQt::ExactMatch); // If no item is selected, that means the listbox hasn't been manipulated by the user yet, // because it's not possible otherwise to have no selected item. In such case make // always the first item current and unselected, so that the current item doesn't jump. if(!item || !wasSelected) { wasSelected = false; item = qalculateCompletionBox->item(0); } if(item) { qalculateCompletionBox->blockSignals(true); qalculateCompletionBox->setCurrentItem(item); qalculateCompletionBox->setSelected(item, wasSelected); qalculateCompletionBox->blockSignals(false); } } else { // completion box not visible yet -> show it if(!txt.isEmpty()) qalculateCompletionBox->setCancelledText(txt); ((QalculateExpressionEditCompletionBox*) qalculateCompletionBox)->setItems(matched_items); qalculateCompletionBox->popup(); } } else { if(qalculateCompletionBox && qalculateCompletionBox->isVisible()) { qalculateCompletionBox->hide(); } } } void QalculateExpressionEditCompletionBox::hideEvent(TQHideEvent*) { emit hidden(); } #include "qalculateexpressionedit.moc"