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.
496 lines
16 KiB
496 lines
16 KiB
/***************************************************************************
|
|
* 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 "qalculateresultdisplay.h"
|
|
|
|
#include "qalculate_kde_utils.h"
|
|
#include "kqalculate.h"
|
|
#include <kpopupmenu.h>
|
|
#include <kxmlguifactory.h>
|
|
#include <kxmlguiclient.h>
|
|
#include <kaction.h>
|
|
#include <kmessagebox.h>
|
|
#include <qwhatsthis.h>
|
|
#include <qtooltip.h>
|
|
#include <klocale.h>
|
|
#include <kapplication.h>
|
|
#include <qsimplerichtext.h>
|
|
|
|
extern vector<mode_struct> modes;
|
|
|
|
extern QString parsed_text;
|
|
extern KQalculate *mainWin;
|
|
extern MathStructure *mstruct;
|
|
extern PrintOptions printops;
|
|
extern EvaluationOptions evalops;
|
|
|
|
QString linkInfo(const MathStructure *m, QWidget *w, bool full_length = false) {
|
|
QString str;
|
|
if(m) {
|
|
if(m->isSymbolic()) {
|
|
str = "\"";
|
|
str += m->symbol().c_str();
|
|
str += "\"";
|
|
} else if(m->isVector()) {
|
|
if(m->isMatrix()) {
|
|
str = i18n("a matrix");
|
|
} else {
|
|
str = i18n("a vector");
|
|
}
|
|
str += "\n";
|
|
str += i18n("double-click to view/edit");
|
|
} else if(m->isVariable()) {
|
|
if(m->variable()->subtype() == SUBTYPE_UNKNOWN_VARIABLE) {
|
|
str = i18n("Unknown variable");
|
|
} else {
|
|
str = i18n("Variable");
|
|
}
|
|
str += ": ";
|
|
str += m->variable()->title(true).c_str();
|
|
} else if(m->isUnit()) {
|
|
str = i18n("Unit");
|
|
str += ": ";
|
|
str += m->unit()->title(true).c_str();
|
|
if(m->prefix() && m->prefix() != CALCULATOR->decimal_null_prefix && m->prefix() != CALCULATOR->binary_null_prefix) {
|
|
str += "\n";
|
|
str += i18n("Prefix");
|
|
str += ": ";
|
|
QString pstr;
|
|
switch(m->prefix()->type()) {
|
|
case PREFIX_DECIMAL: {
|
|
QTextOStream(&pstr) << m->prefix()->name(false, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) w).c_str() << " (10e" << ((DecimalPrefix*) m->prefix())->exponent() << ")";
|
|
break;
|
|
}
|
|
case PREFIX_BINARY: {
|
|
QTextOStream(&pstr) << m->prefix()->name(false, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) w).c_str() << " (2e" << ((BinaryPrefix*) m->prefix())->exponent() << ")";
|
|
break;
|
|
}
|
|
case PREFIX_NUMBER: {
|
|
QTextOStream(&pstr) << m->prefix()->name(false, printops.use_unicode_signs, &can_display_unicode_string_function, (void*) w).c_str();
|
|
break;
|
|
}
|
|
}
|
|
str += pstr;
|
|
}
|
|
} else if(m->isFunction()) {
|
|
str = i18n("Function");
|
|
str += ": ";
|
|
str += m->function()->title(true).c_str();
|
|
Argument default_arg;
|
|
MathFunction *f = m->function();
|
|
str += "<br>";
|
|
const ExpressionName *ename = &f->preferredName(false, printops.use_unicode_signs, false, false, &can_display_unicode_string_function, (void*) w);
|
|
str += "<i><b>";
|
|
str += ename->name.c_str();
|
|
str += "</b>";
|
|
int iargs = f->maxargs();
|
|
if(iargs < 0) {
|
|
iargs = f->minargs() + 1;
|
|
}
|
|
str += "(";
|
|
if(iargs != 0) {
|
|
for(int i2 = 1; i2 <= iargs; i2++) {
|
|
if(i2 > f->minargs()) {
|
|
str += "[";
|
|
}
|
|
if(i2 > 1) {
|
|
str += CALCULATOR->getComma().c_str();
|
|
str += " ";
|
|
}
|
|
Argument *arg = f->getArgumentDefinition(i2);
|
|
if(arg && !arg->name().empty()) {
|
|
str += arg->name().c_str();
|
|
} else {
|
|
str += i18n("argument");
|
|
str += " ";
|
|
str += QString::number(i2);
|
|
}
|
|
if(i2 > f->minargs()) {
|
|
str += "]";
|
|
}
|
|
}
|
|
if(f->maxargs() < 0) {
|
|
str += CALCULATOR->getComma().c_str();
|
|
str += " ...";
|
|
}
|
|
}
|
|
str += ")";
|
|
str += "</i>";
|
|
if(full_length) {
|
|
str += "<i>";
|
|
for(size_t i2 = 1; i2 <= f->countNames(); i2++) {
|
|
if(&f->getName(i2) != ename) {
|
|
str += "<br>";
|
|
str += f->getName(i2).name.c_str();
|
|
}
|
|
}
|
|
str += "</i>";
|
|
if(f->subtype() == SUBTYPE_DATA_SET) {
|
|
str += "<br>";
|
|
str += "<br>";
|
|
QString str2;
|
|
str2.sprintf(i18n("Retrieves data from the %s data set for a given object and property. If \"info\" is typed as property, a dialog window will pop up with all properties of the object."), f->title().c_str());
|
|
str2.replace("<", "<");
|
|
str2.replace(">", ">");
|
|
str += str2;
|
|
}
|
|
if(!f->description().empty()) {
|
|
str += "<br>";
|
|
str += "<br>";
|
|
QString str2 = f->description().c_str();
|
|
str2.replace("<", "<");
|
|
str2.replace(">", ">");
|
|
str += str2;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return str;
|
|
}
|
|
|
|
|
|
QString linkInfo(const QString &link, QWidget *w, bool full_length = false) {
|
|
if(!link.isEmpty() && link[0] == '+') {
|
|
QString str = link;
|
|
str.remove(0, 1);
|
|
return str;
|
|
} else {
|
|
return linkInfo(mainWin->getResultPart(link.toInt()), w, full_length);
|
|
}
|
|
}
|
|
|
|
class QalculateExpressionToolTip : public QToolTip {
|
|
|
|
public:
|
|
|
|
QalculateResultDisplay *qrd;
|
|
|
|
QalculateExpressionToolTip(QalculateResultDisplay *parent, QToolTipGroup *group = 0) : QToolTip(parent->viewport(), group) {
|
|
qrd = parent;
|
|
}
|
|
virtual ~QalculateExpressionToolTip() {}
|
|
|
|
protected:
|
|
|
|
void maybeTip(const QPoint &p) {
|
|
int cx = qrd->contentsX();
|
|
int cy = qrd->contentsY();
|
|
QString str = qrd->anchorAt(qrd->viewportToContents(p), Qt::AnchorName);
|
|
if(str.isEmpty()) return;
|
|
int w = 5;
|
|
while(p.x() + w < qrd->visibleWidth() && qrd->anchorAt(QPoint(p.x() + cx + w, p.y() + cy), Qt::AnchorName) == str) {
|
|
w += 5;
|
|
}
|
|
int x = p.x() - 5;
|
|
w += 5;
|
|
while(x > 0 && qrd->anchorAt(QPoint(x + cx, p.y() + cy), Qt::AnchorName) == str) {
|
|
x -= 5;
|
|
w += 5;
|
|
}
|
|
if(x < 0) x = 0;
|
|
if(w + x > qrd->visibleWidth()) w = qrd->visibleWidth() - x;
|
|
int h = 5;
|
|
while(p.y() + h < qrd->visibleHeight() && qrd->anchorAt(QPoint(p.x() + cx, p.y() + cy + h), Qt::AnchorName) == str) {
|
|
h += 5;
|
|
}
|
|
int y = p.y() - 5;
|
|
h += 5;
|
|
while(y > 0 && qrd->anchorAt(QPoint(p.x() + cx, y + cy), Qt::AnchorName) == str) {
|
|
y -= 5;
|
|
h += 5;
|
|
}
|
|
if(y < 0) y = 0;
|
|
if(h + y > qrd->visibleHeight()) h = qrd->visibleHeight() - y;
|
|
tip(QRect(x, y, w, h), linkInfo(str, qrd, true));
|
|
}
|
|
|
|
};
|
|
|
|
QalculateResultDisplay::QalculateResultDisplay(QWidget *parent, const char *name): QTextBrowser(parent, name) {
|
|
|
|
setResizePolicy(AutoOneFit);
|
|
setVScrollBarMode(Auto);
|
|
setHScrollBarMode(Auto);
|
|
setTextFormat(Qt::RichText);
|
|
setFrameStyle(QFrame::NoFrame);
|
|
//setFocusPolicy(QWidget::TabFocus);
|
|
paletteChanged();
|
|
m_under_pointer = NULL;
|
|
|
|
QToolTipGroup *tgroup = new QToolTipGroup(viewport());
|
|
tooltip = new QalculateExpressionToolTip(this, tgroup);
|
|
|
|
//connect(this, SIGNAL(anchorClicked(const QString&, const QString&)), this, SLOT(onAnchorClicked(const QString&, const QString&)));
|
|
connect(this, SIGNAL(doubleClicked(int, int)), this, SLOT(onDoubleClicked(int, int)));
|
|
if(kapp) {
|
|
connect(kapp, SIGNAL(kdisplayPaletteChanged()), this, SLOT(paletteChanged()));
|
|
}
|
|
|
|
}
|
|
|
|
QalculateResultDisplay::~QalculateResultDisplay() {}
|
|
|
|
void QalculateResultDisplay::setRightMargin(int i_margin) {
|
|
setMargins(0, 0, i_margin, 0);
|
|
}
|
|
|
|
void QalculateResultDisplay::onAnchorClicked(const QString&, const QString&) {
|
|
/*if(name.isEmpty()) return;
|
|
QWhatsThis::display(linkInfo(name, this, true));*/
|
|
}
|
|
|
|
QPopupMenu *QalculateResultDisplay::createPopupMenu(const QPoint &pos) {
|
|
|
|
m_under_pointer = NULL;
|
|
|
|
QPopupMenu *menu = QTextBrowser::createPopupMenu(pos);
|
|
menu->insertSeparator();
|
|
mainWin->ActionStoreResult->plug(menu);
|
|
mainWin->ActionSaveAsImage->plug(menu);
|
|
menu->insertSeparator();
|
|
if(mstruct && mstruct->containsType(STRUCT_ADDITION)) {
|
|
if(evalops.structuring != STRUCTURING_FACTORIZE) {
|
|
mainWin->ActionFactorize->plug(menu);
|
|
}
|
|
if(evalops.structuring != STRUCTURING_SIMPLIFY) {
|
|
mainWin->ActionSimplify->plug(menu);
|
|
}
|
|
} else if(mstruct && mstruct->isNumber() && mstruct->number().isInteger() && !mstruct->number().isZero()) {
|
|
mainWin->ActionFactorize->plug(menu);
|
|
menu->insertSeparator();
|
|
}
|
|
if(mstruct && mstruct->containsUnknowns()) {
|
|
mainWin->ActionSetUnknowns->plug(menu);
|
|
}
|
|
if(mstruct && (mstruct->containsType(STRUCT_ADDITION) || mstruct->containsUnknowns())) {
|
|
menu->insertSeparator();
|
|
}
|
|
if(mstruct && mstruct->containsDivision()) {
|
|
mainWin->ActionNonZeroDenominators->plug(menu);
|
|
menu->insertSeparator();
|
|
}
|
|
int id = menu->insertItem(i18n("Normal"));
|
|
if(printops.min_exp == EXP_PRECISION) menu->setItemChecked(id, true);
|
|
else menu->connectItem(id, this, SLOT(displayNormal()));
|
|
id = menu->insertItem(i18n("Engineering"));
|
|
if(printops.min_exp == EXP_BASE_3) menu->setItemChecked(id, true);
|
|
else menu->connectItem(id, this, SLOT(displayEngineering()));
|
|
id = menu->insertItem(i18n("Scientific"));
|
|
if(printops.min_exp == EXP_SCIENTIFIC) menu->setItemChecked(id, true);
|
|
else menu->connectItem(id, this, SLOT(displayScientific()));
|
|
/*mainWin->ActionNumericalDisplayNormal->plug(menu);
|
|
mainWin->ActionNumericalDisplayEngineering->plug(menu);
|
|
mainWin->ActionNumericalDisplayScientific->plug(menu);*/
|
|
if(!mstruct || !mstruct->containsType(STRUCT_UNIT)) {
|
|
menu->insertSeparator();
|
|
mainWin->ActionNumberBaseBinary->plug(menu);
|
|
mainWin->ActionNumberBaseOctal->plug(menu);
|
|
mainWin->ActionNumberBaseDecimal->plug(menu);
|
|
mainWin->ActionNumberBaseHexadecimal->plug(menu);
|
|
menu->insertSeparator();
|
|
mainWin->ActionFractionalDisplayDecimal->plug(menu);
|
|
mainWin->ActionFractionalDisplayDecimalTryExact->plug(menu);
|
|
mainWin->ActionFractionalDisplayFraction->plug(menu);
|
|
mainWin->ActionFractionalDisplayCombined->plug(menu);
|
|
}
|
|
menu->insertSeparator();
|
|
mainWin->ActionAbbreviateNames->plug(menu);
|
|
if(mstruct && mstruct->containsType(STRUCT_UNIT)) {
|
|
menu->insertSeparator();
|
|
mainWin->ActionConvertToUnitExpression->plug(menu);
|
|
mainWin->ActionConvertToBaseUnits->plug(menu);
|
|
mainWin->ActionConvertToBestUnit->plug(menu);
|
|
menu->insertSeparator();
|
|
mainWin->ActionEnablePrefixes->plug(menu);
|
|
mainWin->ActionEnableUseOfAllPrefixes->plug(menu);
|
|
mainWin->ActionEnableDenominatorPrefixes->plug(menu);
|
|
}
|
|
menu->insertSeparator();
|
|
QPopupMenu *modes_menu = new QPopupMenu(menu);
|
|
QObject::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);
|
|
if(parsed_text.isEmpty()) return menu;
|
|
menu->insertSeparator();
|
|
menu->insertItem(i18n("Show Parsed Expression"), this, SLOT(showParsedExpression()));
|
|
QString str = anchorAt(pos, Qt::AnchorName);
|
|
if(!str.isEmpty()) {
|
|
if(str[0] == '+') {
|
|
name_under_pointer = str;
|
|
name_under_pointer.remove(0, 1);
|
|
menu->insertItem(i18n("Show Object Info"), this, SLOT(showInfo()));
|
|
} else {
|
|
m_under_pointer = mainWin->getResultPart(str.toInt());
|
|
if(m_under_pointer) {
|
|
if(m_under_pointer->isVector()) {
|
|
if(m_under_pointer->isMatrix()) {
|
|
menu->insertItem(i18n("View/Edit Matrix"), this, SLOT(editMatrix()));
|
|
} else {
|
|
menu->insertItem(i18n("View/Edit Vector"), this, SLOT(editVector()));
|
|
}
|
|
} else {
|
|
menu->insertItem(i18n("Show Object Info"), this, SLOT(showInfo()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
curpos = viewport()->mapToGlobal(pos);
|
|
return menu;
|
|
|
|
}
|
|
|
|
void QalculateResultDisplay::displayNormal() {
|
|
printops.negative_exponents = false;
|
|
printops.sort_options.minus_last = true;
|
|
mainWin->ActionNumericalDisplayNormal->activate();
|
|
mainWin->ActionNegativeExponents->setChecked(false);
|
|
mainWin->ActionSortMinusLast->setChecked(true);
|
|
}
|
|
void QalculateResultDisplay::displayEngineering() {
|
|
mainWin->ActionNumericalDisplayEngineering->activate();
|
|
}
|
|
void QalculateResultDisplay::displayScientific() {
|
|
printops.negative_exponents = true;
|
|
printops.sort_options.minus_last = false;
|
|
mainWin->ActionNumericalDisplayScientific->activate();
|
|
mainWin->ActionNegativeExponents->setChecked(true);
|
|
mainWin->ActionSortMinusLast->setChecked(false);
|
|
}
|
|
|
|
void QalculateResultDisplay::showParsedExpression() {
|
|
QString str = i18n("Parsed expression:");
|
|
str += "\n";
|
|
str += parsed_text;
|
|
QWhatsThis::display(str, curpos);
|
|
}
|
|
void QalculateResultDisplay::showInfo() {
|
|
if(m_under_pointer) {
|
|
QWhatsThis::display(linkInfo(m_under_pointer, this, true), curpos);
|
|
} else {
|
|
QWhatsThis::display(linkInfo(name_under_pointer, this, true), curpos);
|
|
}
|
|
}
|
|
void QalculateResultDisplay::editVector() {
|
|
mainWin->insertMatrixVector(m_under_pointer, true, false, true);
|
|
}
|
|
void QalculateResultDisplay::editMatrix() {
|
|
mainWin->insertMatrixVector(m_under_pointer, false, false, true);
|
|
}
|
|
|
|
void QalculateResultDisplay::paletteChanged() {
|
|
QPalette p = kapp ? kapp->palette() : palette();
|
|
p.setBrush(QColorGroup::Base, p.brush(QPalette::Normal, QColorGroup::Background));
|
|
p.setColor(QColorGroup::Text, p.color(QPalette::Normal, QColorGroup::Foreground));
|
|
setPalette(p);
|
|
}
|
|
|
|
void QalculateResultDisplay::virtual_hook(int, void*) {
|
|
}
|
|
|
|
void QalculateResultDisplay::focusInEvent(QFocusEvent* fe) {
|
|
QTextBrowser::focusInEvent(fe);
|
|
if(fe->reason() == QFocusEvent::Tab || fe->reason() == QFocusEvent::Backtab)
|
|
selectAll(true);
|
|
}
|
|
|
|
void QalculateResultDisplay::focusOutEvent(QFocusEvent* fe) {
|
|
QTextBrowser::focusOutEvent(fe);
|
|
if(fe->reason() == QFocusEvent::Tab || fe->reason() == QFocusEvent::Backtab)
|
|
selectAll(false);
|
|
}
|
|
|
|
void QalculateResultDisplay::onDoubleClicked(int, int) {
|
|
curpos = QCursor::pos();
|
|
QString str = anchorAt(viewportToContents(viewport()->mapFromGlobal(curpos)), Qt::AnchorName);
|
|
if(!str.isEmpty()) {
|
|
if(str[0] == '+') {
|
|
selectAll(false);
|
|
name_under_pointer = str;
|
|
name_under_pointer.remove(0, 1);
|
|
showInfo();
|
|
} else {
|
|
m_under_pointer = mainWin->getResultPart(str.toInt());
|
|
if(m_under_pointer) {
|
|
selectAll(false);
|
|
if(m_under_pointer->isVector()) {
|
|
if(m_under_pointer->isMatrix()) {
|
|
editMatrix();
|
|
} else {
|
|
editVector();
|
|
}
|
|
} else {
|
|
showInfo();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void QalculateResultDisplay::keyPressEvent(QKeyEvent *e) {
|
|
|
|
switch (e->key()) {
|
|
case Key_Down:
|
|
case Key_Up:
|
|
case Key_Left:
|
|
case Key_Right:
|
|
// jump over QTextEdit's key navigation breakage.
|
|
// we're not interested in keyboard navigation within the text
|
|
QWidget::keyPressEvent(e);
|
|
break;
|
|
default:
|
|
QTextBrowser::keyPressEvent(e);
|
|
}
|
|
|
|
}
|
|
|
|
QSize QalculateResultDisplay::minimumSizeHint() const {
|
|
|
|
QSize ms = minimumSize();
|
|
if((ms.width() > 0) && (ms.height() > 0))
|
|
return ms;
|
|
|
|
int w = 100;
|
|
if(ms.width() > 0)
|
|
w = ms.width();
|
|
|
|
QSimpleRichText rt("<font size=6>X</font>", font());
|
|
rt.setWidth(100);
|
|
QSimpleRichText rt2("<font size=2>X</font>", font());
|
|
rt2.setWidth(100);
|
|
int h2 = (int) (rt2.height() / 1.5);
|
|
h2 += h2 % 2;
|
|
int h = rt.height() * 2 + h2 + 2 * frameWidth();
|
|
if(h < ms.height())
|
|
h = ms.height();
|
|
|
|
return QSize(w, h);
|
|
}
|
|
|
|
QSize QalculateResultDisplay::sizeHint() const {
|
|
return minimumSizeHint();
|
|
}
|
|
|
|
|
|
#include "qalculateresultdisplay.moc"
|