You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1021 lines
29 KiB
1021 lines
29 KiB
/***************************************************************************
|
|
* 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 <vector>
|
|
#include <string>
|
|
#include <tdeversion.h>
|
|
#include <kcursor.h>
|
|
#include <tqstyle.h>
|
|
#include <tqpainter.h>
|
|
#include <tqapplication.h>
|
|
#include <tqfontmetrics.h>
|
|
#include <kstringhandler.h>
|
|
#include <tdepopupmenu.h>
|
|
#include <kxmlguifactory.h>
|
|
#include <kxmlguiclient.h>
|
|
#include <tdeaction.h>
|
|
#include <tdelocale.h>
|
|
#include <tqsimplerichtext.h>
|
|
|
|
extern std::vector<mode_struct> 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<void*> 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, SIGNAL(highlighted(TQListBoxItem*)), this, SLOT(insertCompletion(TQListBoxItem*)));
|
|
connect(qalculateCompletionBox, SIGNAL(userCancelled(const TQString&)), this, SLOT(cancelCompletion(const TQString&)));
|
|
connect(this, SIGNAL(textChanged(const TQString&)), this, 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, SLOT(disableCompletion()));
|
|
else menu->insertItem(i18n("Enable Completion"), this, 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, SIGNAL(activated(int)), mainWin, 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<TQKeyEvent *>(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 += "<sub>";
|
|
if(b) str += ename->name.substr(ename->name.length() - i2, i2);
|
|
else str += ename->name.substr(i + 1, ename->name.length() - (i + 1));
|
|
str += "</sub>";
|
|
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 += "<i>";
|
|
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 += "</i>";
|
|
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<ExpressionItem*>& 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<ExpressionItem*>::ConstIterator it = items.constBegin();
|
|
const TQValueVector<ExpressionItem*>::ConstIterator itEnd = items.constEnd();
|
|
#else
|
|
TQValueVector<ExpressionItem*>::ConstIterator it = items.begin();
|
|
const TQValueVector<ExpressionItem*>::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<ExpressionItem*> & list, int index) {
|
|
if(index < 0) index = count();
|
|
for(TQValueVector<ExpressionItem*>::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"
|