Merge remote-tracking branch 'upstream/main'

This commit is contained in:
Damir Islamov 2021-09-14 14:15:26 +07:00
commit dd3fece131
6 changed files with 303 additions and 68 deletions

View File

@ -28,7 +28,12 @@ win32: {
CONFIG += c++17
} else {
CONFIG += link_pkgconfig
PKGCONFIG += libqalculate
macx: {
PKGCONFIG += libqalculate gmp mpfr
CONFIG += c++11
} else {
PKGCONFIG += libqalculate
}
}
CONFIG += qt
QT += widgets network

View File

@ -19,6 +19,12 @@
#include <QClipboard>
#include <QTextDocumentFragment>
#include <QScrollBar>
#include <QLineEdit>
#include <QLabel>
#include <QGridLayout>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QDialog>
#include <QDebug>
#include <libqalculate/qalculate.h>
@ -29,6 +35,7 @@
QString unhtmlize(QString str) {
int i = 0, i2;
str.remove("\n");
while(true) {
i = str.indexOf("<", i);
if(i < 0) break;
@ -69,9 +76,15 @@ QString unhtmlize(QString str) {
str.replace(i, i3 - i, name);
continue;
}
} else if(i2 - i == 3 && str.mid(i + 1, 2) == "<br>") {
} else if((i2 - i == 3 && str.mid(i + 1, 2) == "br") || (i2 - i == 4 && str.mid(i + 1, 3) == "/tr")) {
str.replace(i, i2 - i + 1, "\n");
continue;
} else if(i2 - i > 5 && str.mid(i + 1, 4) == "span" && i2 + 1 < str.length() && str[i2 + 1] == '#') {
int i3 = str.indexOf("</", i2 + 1);
if(i3 >= 0 && str.indexOf("</span></a>") == i3) {
str.remove(i, i3 - i);
continue;
}
} else if(i2 - i == 4) {
if(str.mid(i + 1, 3) == "sup") {
int i3 = str.indexOf("</sup>", i2 + 1);
@ -109,6 +122,7 @@ QString unhtmlize(QString str) {
str.replace("&amp;", "&");
str.replace("&gt;", ">");
str.replace("&lt;", "<");
str.replace("&quot;", "\"");
return str;
}
@ -125,8 +139,9 @@ HistoryView::~HistoryView() {}
void replace_colors(QString &s_text) {
if(settings->color == 2) {
s_text.replace("color: #800000", "color: #AAAAFF");
s_text.replace("color: #000080", "color: #FFAAAA");
s_text.replace("color: #585858", "color: #AAAAAA");
s_text.replace("color: #800000", "color: #FFAAAA");
s_text.replace("color: #000080", "color: #AAAAFF");
s_text.replace("color:#005858", "color:#AAFFFF");
s_text.replace("color:#585800", "color:#FFFFAA");
s_text.replace("color:#580058", "color:#FFAAFF");
@ -134,8 +149,9 @@ void replace_colors(QString &s_text) {
s_text.replace("color:#008000", "color:#BBFFBB");
s_text.replace(":/icons/actions", ":/icons/dark/actions");
} else {
s_text.replace("color: #AAAAFF", "color: #800000");
s_text.replace("color: #FFAAAA", "color: #000080");
s_text.replace("color: #AAAAAA", "color: #585858");
s_text.replace("color: #AAAAFF", "color: #000080");
s_text.replace("color: #FFAAAA", "color: #800000");
s_text.replace("color:#AAFFFF", "color:#005858");
s_text.replace("color:#FFFFAA", "color:#585800");
s_text.replace("color:#FFAAFF", "color:#580058");
@ -146,8 +162,6 @@ void replace_colors(QString &s_text) {
}
void replace_colors(std::string &str) {
if(settings->color == 2) {
gsub("color: #800000", "color: #AAAAFF", str);
gsub("color: #000080", "color: #FFAAAA", str);
gsub("color:#005858", "color:#AAFFFF", str);
gsub("color:#585800", "color:#FFFFAA", str);
gsub("color:#580058", "color:#FFAAFF", str);
@ -155,8 +169,6 @@ void replace_colors(std::string &str) {
gsub("color:#008000", "color:#BBFFBB", str);
gsub(":/icons/actions", ":/icons/dark/actions", str);
} else {
gsub("color: #AAAAFF", "color: #800000", str);
gsub("color: #FFAAAA", "color: #000080", str);
gsub("color:#AAFFFF", "color:#005858", str);
gsub("color:#FFFFAA", "color:#585800", str);
gsub("color:#FFAAFF", "color:#580058", str);
@ -166,13 +178,31 @@ void replace_colors(std::string &str) {
}
}
void replace_one(QString &str, const QString &origstr, const QString &newstr, bool b_last = false) {
int index = (b_last ? str.lastIndexOf(origstr) : str.indexOf(origstr));
if(index > 0) {
str.replace(index, origstr.length(), newstr);
}
}
void remove_top_border(QString &s_text) {
if(!s_text.isEmpty() && s_text.indexOf("border-top: 0px none") < 0) {
replace_one(s_text, "border-top: 1px dashed", "border-top: 0px none");
int index_a = s_text.indexOf("padding-top: ") + strlen("padding-top: ");
int index_b = s_text.indexOf("px", index_a);
if(index_b >= 0) {
s_text.replace(index_a, index_b - index_a, "0");
}
}
}
void HistoryView::loadInitial() {
if(!settings->v_expression.empty()) {
for(size_t i = 0; i < settings->v_expression.size(); i++) {
addResult(settings->v_result[i], settings->v_expression[i], true, false, QString(), NULL, true, i);
}
if(!s_text.isEmpty()) {
if((settings->color == 2 && s_text.contains("color:#00")) || (settings->color != 2 && s_text.contains("color:#FF"))) {
if((settings->color == 2 && (s_text.contains("color:#00") || s_text.contains("color:#58"))) || (settings->color != 2 && (s_text.contains("color:#FF") || s_text.contains("color:#AA")))) {
replace_colors(s_text);
for(size_t i = 0; i < settings->v_expression.size(); i++) {
replace_colors(settings->v_expression[i]);
@ -181,26 +211,30 @@ void HistoryView::loadInitial() {
}
}
}
setHtml("<body style=\"color: " + textColor().name() + "\">" + s_text + "</body>");
setHtml("<body color=\"" + textColor().name() + "\"><table width=\"100%\">" + s_text + "</table></body>");
}
}
}
#define PASTE_H QFontMetrics fm(font()); \
int paste_h = fm.ascent(); \
if(paste_h < 16) {paste_h = 12;} \
else if(paste_h < 24) {paste_h = 16;} \
else {paste_h = 24;} \
void HistoryView::addResult(std::vector<std::string> values, std::string expression, int exact, bool dual_approx, const QString &image, bool *implicit_warning, bool initial_load, size_t index) {
QFontMetrics fm(font());
int paste_h = fm.ascent();
if(paste_h < 16) paste_h = 12;
else if(paste_h < 24) paste_h = 16;
else paste_h = 24;
PASTE_H
QString str;
if(!expression.empty()) {
str += "<div style=\"text-align:left; line-height:120%\">";
str += QString("<tr><td colspan=\"2\" style=\"padding-bottom: %1 px; padding-top: 0px; border-top: 0px none %2; text-align:left\">").arg(paste_h / 4).arg(textColor().name());
if(settings->color == 2) str += QString("<a href=\"%1\"><img src=\":/icons/dark/actions/%2/edit-paste.svg\" height=\"%2\"/></a>").arg(initial_load ? (int) index : settings->v_expression.size()).arg(paste_h);
else str += QString("<a href=\"%1\"><img src=\":/icons/actions/%2/edit-paste.svg\" height=\"%2\"/></a>").arg(initial_load ? (int) index : settings->v_expression.size()).arg(paste_h);
str += THIN_SPACE;
str += QString::fromStdString(expression);
str += "</div>";
str += "</td></tr>";
if(!initial_load) {
settings->v_expression.push_back(expression);
settings->v_protected.push_back(false);
settings->v_delexpression.push_back(false);
settings->v_result.push_back(values);
settings->v_exact.push_back(std::vector<int>());
@ -222,9 +256,9 @@ void HistoryView::addResult(std::vector<std::string> values, std::string express
if(!settings->implicit_question_asked) *implicit_warning = true;
} else {
MessageType mtype = CALCULATOR->message()->type();
str += "<div style=\"text-align:left; font-size:normal";
str += "<tr><td colspan=\"2\" style=\"text-align:left; font-size:normal";
if(mtype == MESSAGE_ERROR || mtype == MESSAGE_WARNING) {
str += "; color:";
str += "; color: ";
if(mtype == MESSAGE_ERROR) {
if(settings->color == 2) str += "#FFAAAA";
else str += "#800000";
@ -243,7 +277,7 @@ void HistoryView::addResult(std::vector<std::string> values, std::string express
mstr.replace("!=", SIGN_NOT_EQUAL);
}
str += mstr.toHtmlEscaped();
str += "</div>";
str += "</td></tr>";
}
} while(CALCULATOR->nextMessage());
if(str.isEmpty() && values.empty() && expression.empty()) return;
@ -251,9 +285,26 @@ void HistoryView::addResult(std::vector<std::string> values, std::string express
str.replace("</i>", "<img src=\"data://img1px.png\" width=\"1\"/></i>");
if(!expression.empty()) i_pos = str.length();
for(size_t i = 0; i < values.size(); i++) {
size_t i_answer = -1;
if(!initial_load) i_answer = dual_approx && i == 0 ? settings->history_answer.size() - 1 : settings->history_answer.size();
QFontMetrics fm(font());
int w = fm.boundingRect(unhtmlize(QString::fromStdString(values[i]))).width();
str += "<div style=\"text-align:right";
int w = fm.boundingRect("#9999" + unhtmlize(QString::fromStdString(values[i]))).width();
str += "<tr><td valign=\"center\">";
if(!initial_load && (dual_approx || i == 0)) {
if(expression.empty() && last_ans == i_answer && !last_ref.isEmpty()) s_text.remove(last_ref);
QString sref;
if(settings->color == 2) {
sref = QString("<a href=\"#%1:%2:%3\" style=\"text-decoration: none; text-align:left; color: #AAAAAA\">#%1</a>").arg(i_answer).arg(settings->v_expression.size() - 1).arg(settings->v_result[settings->v_result.size() - 1].size() - i - 1);
} else {
sref = QString("<a href=\"#%1:%2:%3\" style=\"text-decoration: none; text-align:left; color: #585858\">#%1</a>").arg(i_answer).arg(settings->v_expression.size() - 1).arg(settings->v_result[settings->v_result.size() - 1].size() - i - 1);
}
str += sref;
if(!dual_approx || i == values.size()) {
last_ans = i_answer;
last_ref = sref;
}
}
str += "</td><td style=\"text-align:right";
if(initial_load || w > width() * 2) {
gsub("</i>", "<img src=\"data://img1px.png\" width=\"1\"/></i>", values[i]);
} else if(w * 2 > width()) {
@ -263,6 +314,7 @@ void HistoryView::addResult(std::vector<std::string> values, std::string express
str += "; font-size:x-large";
gsub("</i>", "<img src=\"data://img1px.png\" width=\"2\"/></i>", values[i]);
}
if(!expression.empty() && i == values.size() - 1) str += QString("; padding-bottom: %1 px").arg(paste_h / 2);
str += "\">";
int b_exact = 1;
if(initial_load) {
@ -281,10 +333,10 @@ void HistoryView::addResult(std::vector<std::string> values, std::string express
if(settings->color == 2) str += QString("<a href=\"%1:%3\"><img src=\":/icons/dark/actions/%2/edit-paste.svg\" height=\"%2\"/></a>").arg((int) index).arg(paste_h).arg((int) i);
else str += QString("<a href=\"%1:%3\"><img src=\":/icons/actions/%2/edit-paste.svg\" height=\"%2\"/></a>").arg((int) index).arg(paste_h).arg((int) i);
} else {
if(settings->color == 2) str += QString("<a href=\"#%1:%2:%3\"><img src=\":/icons/dark/actions/%4/edit-paste.svg\" height=\"%4\"/></a>").arg(dual_approx && i == 0 ? settings->history_answer.size() - 1 : settings->history_answer.size()).arg(settings->v_expression.size() - 1).arg(settings->v_result[settings->v_result.size() - 1].size() - i - 1).arg(paste_h);
else str += QString("<a href=\"#%1\"><img src=\":/icons/actions/%2/edit-paste.svg\" height=\"%2\"/></a>").arg(dual_approx && i == 0 ? settings->history_answer.size() - 1 : settings->history_answer.size()).arg(paste_h);
if(settings->color == 2) str += QString("<a href=\"%1:%2\"><img src=\":/icons/dark/actions/%3/edit-paste.svg\" height=\"%3\"/></a>").arg(settings->v_expression.size() - 1).arg(settings->v_result[settings->v_result.size() - 1].size() - i - 1).arg(paste_h);
else str += QString("<a href=\"%1:%2\"><img src=\":/icons/actions/%3/edit-paste.svg\" height=\"%3\"/></a>").arg(settings->v_expression.size() - 1).arg(settings->v_result[settings->v_result.size() - 1].size() - i - 1).arg(paste_h);
}
str += "</div>";
str += "</td></tr>";
}
str.replace("\n", "<br>");
int i = 0;
@ -330,10 +382,11 @@ void HistoryView::addResult(std::vector<std::string> values, std::string express
s_text.remove("; font-size:x-large");
s_text.remove("; font-size:large");
}
if(!s_text.isEmpty()) str += "<hr/>";
replace_one(s_text, "border-top: 0px none", "border-top: 1px dashed");
replace_one(s_text, "padding-top: 0px", "padding-top: " + QString::number(paste_h / 2) + "px");
s_text.insert(0, str);
}
if(!initial_load) setHtml("<body color=\"" + textColor().name() + "\">" + s_text + "</body>");
if(!initial_load) setHtml("<body color=\"" + textColor().name() + "\"><table width=\"100%\">" + s_text + "</table></body>");
}
void HistoryView::changeEvent(QEvent *e) {
if(e->type() == QEvent::PaletteChange || e->type() == QEvent::ApplicationPaletteChange) {
@ -346,7 +399,9 @@ void HistoryView::changeEvent(QEvent *e) {
}
if(!s_text.isEmpty()) {
replace_colors(s_text);
setHtml("<body style=\"color: " + textColor().name() + "\">" + s_text + "</body>");
s_text.replace("1px dashed " + prev_color.name(), "1px dashed " + textColor().name());
s_text.replace("0px none " + prev_color.name(), "0px none " + textColor().name());
setHtml("<body color=\"" + textColor().name() + "\"><table width=\"100%\">" + s_text + "</table></body>");
}
prev_color = textColor();
}
@ -398,37 +453,124 @@ void HistoryView::inputMethodEvent(QInputMethodEvent *e) {
}
}
void HistoryView::editClear() {
clear();
s_text.clear();
settings->v_expression.clear();
settings->v_result.clear();
for(size_t i1 = 0; i1 < settings->v_protected.size(); i1++) {
if(!settings->v_protected[i1]) {
if(i1 == 0) settings->current_result = NULL;
settings->v_delexpression[i1] = true;
int index = s_text.indexOf("<a href=\"" + QString::number(i1) + "\"");
if(index >= 0) {
int index2 = s_text.indexOf("<tr><td colspan=\"2\"", index);
int index1 = s_text.lastIndexOf("<tr><td colspan=\"2\"", index);
QString new_text;
if(index1 > 0) new_text = s_text.left(index1);
if(index2 >= 0) new_text += s_text.mid(index2);
s_text = new_text;
}
}
}
remove_top_border(s_text);
setHtml("<body color=\"" + textColor().name() + "\"><table width=\"100%\">" + s_text + "</table></body>");
}
void HistoryView::editMoveToTop() {
int i1 = -1, i2 = -1;
indexAtPos(context_pos, &i1, &i2, NULL);
if(i1 < 0 || i1 >= (int) settings->v_delexpression.size()) return;
settings->v_delexpression[i1] = true;
settings->v_expression.push_back(settings->v_expression[i1]);
settings->v_protected.push_back(settings->v_protected[i1]);
settings->v_delexpression.push_back(false);
settings->v_result.push_back(settings->v_result[i1]);
settings->v_exact.push_back(settings->v_exact[i1]);
settings->v_delresult.push_back(settings->v_delresult[i1]);
int index = s_text.indexOf("<a href=\"" + QString::number(i1) + "\"");
if(index >= 0) {
int index2 = s_text.indexOf("<tr><td colspan=\"2\"", index);
int index1 = s_text.lastIndexOf("<tr><td colspan=\"2\"", index);
QString new_text = s_text.mid(index1, index2 - index1);
int index_a = new_text.indexOf("<a href=\"");
bool b_expr = true;
while(index_a >= 0 && index_a + 9 < new_text.length() - 1) {
index_a += 9;
int index_b = -1;
if(b_expr) {
index_b = new_text.indexOf("\"", index_a);
} else {
index_b = new_text.indexOf(":", index_a);
if(new_text[index_a] == '#') {
if(index_b < 0) break;
index_a = index_b + 1;
index_b = new_text.indexOf(":", index_b + 1);
}
}
if(index_b < 0) break;
new_text.replace(index_a, index_b - index_a, QString::number(settings->v_expression.size() - 1));
index_a = new_text.indexOf("<a href=\"", index_b + 1);
b_expr = false;
}
replace_one(s_text, "border-top: 0px none", "border-top: 1px dashed");
PASTE_H
replace_one(s_text, "padding-top: 0px", "padding-top: " + QString::number(paste_h / 2) + "px");
if(index1 > 0) new_text += s_text.left(index1);
if(index2 >= 0) new_text += s_text.mid(index2);
s_text = new_text;
remove_top_border(s_text);
}
settings->current_result = NULL;
setHtml("<body color=\"" + textColor().name() + "\"><table width=\"100%\">" + s_text + "</table></body>");
}
void HistoryView::editRemove() {
int i1 = -1, i2 = -1;
QString sref;
indexAtPos(context_pos, &i1, &i2, &sref);
if(i1 < 0 || i1 >= (int) settings->v_delexpression.size()) return;
if(i2 >= 0 && settings->v_result[i1].size() <= 1) i2 = -1;
if(i2 >= 0 && i2 < (int) settings->v_delresult[i1].size()) {
settings->v_delresult[i1][i2] = true;
bool b = true;
for(size_t i = 0; i < settings->v_delresult[i1].size(); i++) {
if(!settings->v_delresult[i1][i]) {b = false; break;}
}
if(b) i2 = -1;
}
if(i2 < 0) {
sref = QString::number(i1);
settings->v_delexpression[i1] = true;
} else if(i2 < (int) settings->v_delresult[i1].size()) {
settings->v_delresult[i1][i2] = true;
}
int index = s_text.indexOf("<a href=\"" + sref + "\"");
if(index >= 0) {
int index2 = s_text.indexOf(i2 < 0 ? "<hr/>" : "</a></div>", index);
if(index2 >= 0) index2 += (i2 < 0 ? 5 : 10);
int index1 = s_text.lastIndexOf("<div", index);
int index2 = s_text.indexOf(i2 < 0 ? "<tr><td colspan=\"2\"" : "</a></td></tr>", index);
if(index2 >= 0) index2 += (i2 < 0 ? 0 : 14);
int index1 = s_text.lastIndexOf(i2 < 0 ? "<tr><td colspan=\"2\"" : "<tr", index);
QString new_text;
if(index1 > 0) new_text = s_text.left(index1);
if(i2 >= 0) {
bool b = true;
for(size_t i = i2; i < settings->v_delresult[i1].size(); i++) {
if(!settings->v_delresult[i1][i]) {b = false; break;}
}
if(b) {
PASTE_H
int index_a = new_text.lastIndexOf("<td style=\"text-align:right") + strlen("<td style=\"text-align:right");
index_a = new_text.indexOf("\"", index_a);
if(index_a >= 0) new_text.insert(index_a, "; padding-bottom: " + QString::number(paste_h / 2) + "px");
}
}
if(index2 >= 0) new_text += s_text.mid(index2);
s_text = new_text;
if(i2 < 0) {
remove_top_border(s_text);
}
}
if(i1 == 0) settings->current_result = NULL;
int vpos = verticalScrollBar()->value();
setHtml("<body color=\"" + textColor().name() + "\">" + s_text + "</body>");
setHtml("<body color=\"" + textColor().name() + "\"><table width=\"100%\">" + s_text + "</table></body>");
verticalScrollBar()->setValue(vpos);
}
void HistoryView::editProtect() {
int i1 = -1, i2 = -1;
indexAtPos(context_pos, &i1, &i2);
if(i1 < 0 || i1 >= (int) settings->v_protected.size()) return;
settings->v_protected[i1] = protectAction->isChecked();
}
void HistoryView::indexAtPos(const QPoint &pos, int *expression_index, int *result_index, QString *anchorstr) {
*expression_index = -1;
*result_index = -1;
@ -447,10 +589,8 @@ void HistoryView::indexAtPos(const QPoint &pos, int *expression_index, int *resu
sref = str.mid(i, i2 - i);
if(sref.isEmpty()) return;
break;
} else if(str.lastIndexOf("text-align:left") > 0) {
} else if(str.indexOf("text-align:left") < 0) {
if(!cur.movePosition(QTextCursor::NextBlock, QTextCursor::MoveAnchor)) return;
} else {
if(!cur.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor)) return;
}
}
}
@ -485,19 +625,73 @@ void HistoryView::contextMenuEvent(QContextMenuEvent *e) {
selectAllAction = cmenu->addAction(tr("Select All"), this, SLOT(selectAll()));
selectAllAction->setShortcut(QKeySequence::SelectAll);
selectAllAction->setShortcutContext(Qt::WidgetShortcut);
findAction = cmenu->addAction(tr("Find…"), this, SLOT(editFind()));
findAction->setShortcut(QKeySequence::Find);
findAction->setShortcutContext(Qt::WidgetShortcut);
cmenu->addSeparator();
protectAction = cmenu->addAction(tr("Protect"), this, SLOT(editProtect()));
protectAction->setCheckable(true);
movetotopAction = cmenu->addAction(tr("Move to Top"), this, SLOT(editMoveToTop()));
cmenu->addSeparator();
delAction = cmenu->addAction(tr("Remove"), this, SLOT(editRemove()));
clearAction = cmenu->addAction(tr("Clear"), this, SLOT(editClear()));
}
int i1 = -1, i2 = -1;
context_pos = e->pos();
indexAtPos(context_pos, &i1, &i2);
copyAction->setEnabled(textCursor().hasSelection() || (i1 >= 0 && e->reason() == QContextMenuEvent::Mouse));
copyFormattedAction->setEnabled(textCursor().hasSelection() || (i1 >= 0 && e->reason() == QContextMenuEvent::Mouse));
selectAllAction->setEnabled(!s_text.isEmpty());
delAction->setEnabled(i1 >= 0 && e->reason() == QContextMenuEvent::Mouse && !textCursor().hasSelection());
protectAction->setChecked(i1 >= 0 && i1 < (int) settings->v_protected.size() && settings->v_protected[i1]);
if(i1 >= 0 && e->reason() == QContextMenuEvent::Mouse && !textCursor().hasSelection()) {
copyAction->setEnabled(true);
copyFormattedAction->setEnabled(true);
delAction->setEnabled(true);
protectAction->setEnabled(true);
bool b = false;
for(size_t i = i1; i < settings->v_delexpression.size(); i++) {
if(!settings->v_delexpression[i]) {
b = true;
break;
}
}
movetotopAction->setEnabled(b);
} else {
copyAction->setEnabled(textCursor().hasSelection());
copyFormattedAction->setEnabled(textCursor().hasSelection());
delAction->setEnabled(false);
protectAction->setEnabled(false);
movetotopAction->setEnabled(false);
}
clearAction->setEnabled(!s_text.isEmpty());
cmenu->popup(e->globalPos());
}
void HistoryView::doFind() {
if(!find(searchEdit->text())) {
QTextCursor c = textCursor();
QTextCursor cbak = c;
c.movePosition(QTextCursor::Start);
setTextCursor(c);
if(!find(searchEdit->text())) {
setTextCursor(cbak);
}
}
}
void HistoryView::editFind() {
QDialog *dialog = new QDialog(this);
QVBoxLayout *box = new QVBoxLayout(dialog);
if(settings->always_on_top) dialog->setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
dialog->setWindowTitle(tr("Find"));
QGridLayout *grid = new QGridLayout();
grid->addWidget(new QLabel(tr("Text:"), this), 0, 0);
searchEdit = new QLineEdit(this);
grid->addWidget(searchEdit, 0, 1);
box->addLayout(grid);
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close, Qt::Horizontal, dialog);
connect(buttonBox->addButton(tr("Search"), QDialogButtonBox::AcceptRole), SIGNAL(clicked()), this, SLOT(doFind()));
connect(buttonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), dialog, SLOT(reject()));
box->addWidget(buttonBox);
dialog->exec();
dialog->deleteLater();
}
void HistoryView::editCopyFormatted() {
if(textCursor().hasSelection()) {
copy();
@ -516,10 +710,21 @@ void HistoryView::editCopy() {
if(textCursor().hasSelection()) {
QString str = textCursor().selection().toHtml();
int i = str.indexOf("<!--StartFragment-->");
int i2 = str.indexOf("<!--EndFragment-->", i + 20);
if(i >= 0 && i2 >= 0) str = str.mid(i + 20, i2 - i - 20).trimmed();
else str = textCursor().selectedText();
QApplication::clipboard()->setText(unhtmlize(str));
if(i >= 0) {
int i2 = str.indexOf("<!--EndFragment-->", i + 20);
if(i2 >= 0) str = str.mid(i + 20, i2 - i - 20).trimmed();
str = unhtmlize(str);
} else if(str.startsWith("<!DOCTYPE")) {
i = str.indexOf("<body>");
int i2 = str.indexOf("</body>", i + 6);
if(i2 >= 0) str = str.mid(i + 6, i2 - i - 6).trimmed();
str = unhtmlize(str).trimmed();
str.replace("\n\n", "\n");
str.replace("\n ", "\n");
} else {
str = unhtmlize(textCursor().selectedText());
}
QApplication::clipboard()->setText(str);
} else {
int i1 = -1, i2 = -1;
indexAtPos(context_pos, &i1, &i2);

View File

@ -19,6 +19,7 @@ class QMenu;
class QAction;
class ExpressionEdit;
class QColor;
class QLineEdit;
class HistoryView : public QTextBrowser {
@ -42,9 +43,12 @@ class HistoryView : public QTextBrowser {
int i_pos;
QImage *paste_image;
QMenu *cmenu;
QAction *copyAction, *copyFormattedAction, *selectAllAction, *delAction, *clearAction;
QAction *copyAction, *copyFormattedAction, *selectAllAction, *delAction, *clearAction, *findAction, *protectAction, *movetotopAction;
QColor prev_color;
QPoint context_pos;
QLineEdit *searchEdit;
size_t last_ans;
QString last_ref;
void mouseReleaseEvent(QMouseEvent *e) override;
void contextMenuEvent(QContextMenuEvent *e) override;
@ -52,12 +56,19 @@ class HistoryView : public QTextBrowser {
void inputMethodEvent(QInputMethodEvent*) override;
void changeEvent(QEvent*) override;
protected slots:
void doFind();
public slots:
void editCopy();
void editCopyFormatted();
void editClear();
void editRemove();
void editProtect();
void editFind();
void editMoveToTop();
signals:

View File

@ -293,18 +293,19 @@ void QalculateQtSettings::loadPreferences() {
svalue = stmp.substr(i + 1);
remove_blank_ends(svalue);
v = s2i(svalue);
if(svar == "history_expression") {
if(svar == "history_expression" || svar == "history_expression*") {
v_expression.push_back(svalue);
v_delexpression.push_back(false);
v_protected.push_back(svar[svar.length() - 1] == '*');
v_result.push_back(std::vector<std::string>());
v_exact.push_back(std::vector<int>());
v_delresult.push_back(std::vector<bool>());
} else if(svar == "history_result") {
} else if(svar == "history_result" || svar == "history_result_approximate") {
if(!v_result.empty()) {
v_result[settings->v_result.size() - 1].push_back(svalue);
v_delresult[settings->v_result.size() - 1].push_back(false);
if(v_exact[settings->v_exact.size() - 1].size() < v_result[settings->v_result.size() - 1].size()) {
v_exact[settings->v_exact.size() - 1].push_back(false);
v_exact[settings->v_exact.size() - 1].push_back(svar.length() > 20);
}
}
} else if(svar == "history_exact") {
@ -941,25 +942,28 @@ void QalculateQtSettings::savePreferences(bool) {
if(n >= 300 || i == 0) break;
i--;
}
for(; i < v_expression.size(); i++) {
if(!v_delexpression[i]) {
fprintf(file, "history_expression=%s\n", v_expression[i].c_str());
size_t i_first = i;
for(i = 0; i < v_expression.size(); i++) {
if((i >= i_first || v_protected[i]) && !v_delexpression[i]) {
if(v_protected[i]) fprintf(file, "history_expression*=%s\n", v_expression[i].c_str());
else fprintf(file, "history_expression=%s\n", v_expression[i].c_str());
n++;
for(size_t i2 = 0; i2 < settings->v_result[i].size(); i2++) {
if(!v_delresult[i][i2]) {
fprintf(file, "history_exact=%i\n", v_exact[i][i2]);
if(v_result[i][i2].length() > 6000) {
if(v_exact[i][i2]) fprintf(file, "history_result");
else fprintf(file, "history_result_approximate");
if(v_result[i][i2].length() > 6000 && !v_protected[i]) {
std::string str = unhtmlize(v_result[i][i2]);
if(str.length() > 5000) {
int index = 50;
while(index >= 0 && str[index] < 0 && (unsigned char) str[index + 1] < 0xC0) index--;
gsub("\n", "<br>", str);
fprintf(file, "history_result=%s …\n", str.substr(0, index + 1).c_str());
fprintf(file, "=%s …\n", str.substr(0, index + 1).c_str());
} else {
fprintf(file, "history_result=%s\n", v_result[i][i2].c_str());
fprintf(file, "=%s\n", v_result[i][i2].c_str());
}
} else {
fprintf(file, "history_result=%s\n", v_result[i][i2].c_str());
fprintf(file, "=%s\n", v_result[i][i2].c_str());
}
}
}

View File

@ -118,6 +118,7 @@ class QalculateQtSettings : QObject {
std::string last_found_version;
std::vector<std::string> v_expression;
std::vector<bool> v_protected;
std::vector<bool> v_delexpression;
std::vector<std::vector<std::string> > v_result;
std::vector<std::vector<bool> > v_delresult;

View File

@ -152,7 +152,7 @@ std::string unhtmlize(std::string str) {
if(i == std::string::npos) break;
i2 = str.find(">", i + 1);
if(i2 == std::string::npos) break;
if(i2 - i == 3 && str.substr(i + 1, 2) == "<br>") {
if((i2 - i == 3 && str.substr(i + 1, 2) == "br") || (i2 - i == 4 && str.substr(i + 1, 3) == "/tr")) {
str.replace(i, i2 - i + 1, "\n");
continue;
} else if(i2 - i == 4) {
@ -193,6 +193,7 @@ std::string unhtmlize(std::string str) {
gsub("&amp;", "&", str);
gsub("&gt;", ">", str);
gsub("&lt;", "<", str);
gsub("&quot;", "\"", str);
gsub("&hairsp;", "", str);
gsub("&thinsp;", THIN_SPACE, str);
return str;
@ -689,7 +690,7 @@ QalculateWindow::QalculateWindow() : QMainWindow() {
connect(server, SIGNAL(newConnection()), this, SLOT(serverNewConnection()));
mstruct = new MathStructure();
settings->current_result = mstruct;
settings->current_result = NULL;
mstruct_exact.setUndefined();
prepend_mstruct.setUndefined();
parsed_mstruct = new MathStructure();
@ -2697,6 +2698,10 @@ void QalculateWindow::calculateExpression(bool force, bool do_mathoperation, Mat
if(last_is_space) to_str += " ";
CALCULATOR->separateToExpression(to_str, str_left, settings->evalops, true, false);
remove_blank_ends(to_str);
} else if(!settings->current_result) {
b_busy--;
if(current_expr) setPreviousExpression();
return;
}
size_t ispace = to_str.find_first_of(SPACES);
if(ispace != std::string::npos) {
@ -3233,6 +3238,7 @@ void QalculateWindow::calculateExpression(bool force, bool do_mathoperation, Mat
mstruct = CALCULATOR->getRPNRegister(1);
if(!mstruct) mstruct = new MathStructure();
else mstruct->ref();
settings->current_result = NULL;
}
if(do_stack) {
@ -3888,7 +3894,9 @@ void QalculateWindow::setResult(Prefix *prefix, bool update_history, bool update
if(settings->rpn_mode && CALCULATOR->RPNStackSize() == 0) return;
if(settings->history_answer.empty() && !register_moved && !update_parse && update_history) {
if(!settings->rpn_mode) {stack_index = 0; do_stack = false;}
if(!do_stack && (settings->history_answer.empty() || !settings->current_result) && !register_moved && !update_parse && update_history) {
return;
}
@ -3901,7 +3909,6 @@ void QalculateWindow::setResult(Prefix *prefix, bool update_history, bool update
parsed_text = "aborted";
}
if(!settings->rpn_mode) {stack_index = 0; do_stack = false;}
if(do_stack) {
update_history = true;
update_parse = false;
@ -4161,6 +4168,8 @@ void QalculateWindow::setResult(Prefix *prefix, bool update_history, bool update
}
settings->printops.prefix = NULL;
settings->current_result = mstruct;
b_busy--;
if(implicit_warning && askImplicit()) {
@ -4439,7 +4448,7 @@ void QalculateWindow::closeEvent(QCloseEvent *e) {
void QalculateWindow::onToActivated() {
QTextCursor cur = expressionEdit->textCursor();
QPoint pos = tb->mapToGlobal(tb->widgetForAction(toAction)->geometry().topRight());
if(!expressionEdit->expressionHasChanged()) {
if(!expressionEdit->expressionHasChanged() && settings->current_result) {
if(expressionEdit->complete(mstruct, pos)) return;
}
expressionEdit->blockCompletion();