Commit e73ab99b authored by Alexander Semke's avatar Alexander Semke
Browse files

Squash commit of multiple fixes that will go into 22.08.

When saving the results, use the file extension and not the mime-type in the QFileDialog to show the relevant files only.

Open URLs in the "Select Backend"-dialog in the external browser.

BUG: 456650
FIXED-IN: 22.08

Enable highdpi pixmaps

Fixes icon rendering on highdpi screens

[maxima] remove the obsolete quotes in string variable values and properly handle quoted sub-strings in string variables.

Moved the worksheet specific actions from the menu "Settings" to the menu "Worksheet" to make it more explicit these actions are affecting the current worksheet only and don't change the global default settings.

Updated ChangeLog.
parent b97355d0
Pipeline #212013 passed with stage
in 10 minutes and 28 seconds
# Changelog
## 22.08
### New features
* Added zooming related actions (zoom in, zoom out, zoom original) to the context menu of the worksheet
* Smooth zoom in the worksheet view with the mouse wheel
* Show the information about the available internal help system in Maxima and in R in the help panel
### Bug fixes:
* Enable highdpi pixmaps, fixes icon rendering on highdpi screens
* Open URLs in the "Select Backend"-dialog in the external browser, BUG: 456650
* When saving the results, use the file extension and not the mime-type in the QFileDialog to show the relevant files only
* [maxima] properly embedd the results of the commands from the draw package (draw, draw2d and draw3d)
* [maxima] properly parse plot and draw commands with line breaks
* [maxima] remove the obsolete quotes in string variable values and properly handle quoted sub-strings in string variables
* [R] Remove backspaces in the help output in R
## The information for the releases 20.12 - 22.04 was not maintained.
## 20.08
### New features
......
......@@ -110,9 +110,8 @@ void AnimationResultItem::updateSize(QSize size)
void AnimationResultItem::saveResult()
{
Cantor::Result* res = result();
const QString& filename=QFileDialog::getSaveFileName(worksheet()->worksheetView(), i18n("Save result"), QString(), res->mimeType());
res->save(filename);
const QString& filename = QFileDialog::getSaveFileName(worksheet()->worksheetView(), i18n("Save animation result"), QString(), i18n("Animations (*.gif)"));
result()->save(filename);
}
void AnimationResultItem::stopMovie()
......
/*
SPDX-License-Identifier: GPL-2.0-or-later
SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
SPDX-FileCopyrightText: 2019 Alexander Semke <alexander.semke@web.de>
SPDX-FileCopyrightText: 2019-2022 Alexander Semke <alexander.semke@web.de>
*/
#include "backendchoosedialog.h"
......@@ -13,6 +13,7 @@
#include <KSharedConfig>
#include <KWindowConfig>
#include <QDesktopServices>
#include <QIcon>
#include <QPushButton>
#include <QWindow>
......@@ -59,6 +60,7 @@ BackendChooseDialog::BackendChooseDialog(QWidget* parent) : QDialog(parent)
int height = m_ui.backendList->iconSize().height() * m_ui.backendList->count();
m_ui.backendList->setMinimumSize(0, height);
setWindowTitle(i18n("Select the Backend"));
setWindowIcon(QIcon::fromTheme(QLatin1String("run-build")));
......@@ -66,14 +68,21 @@ BackendChooseDialog::BackendChooseDialog(QWidget* parent) : QDialog(parent)
connect(m_ui.buttonBox, &QDialogButtonBox::rejected, this, &BackendChooseDialog::close);
connect(this, &BackendChooseDialog::accepted, this, &BackendChooseDialog::onAccept);
//restore saved settings if available
create(); // ensure there's a window created
KConfigGroup conf(KSharedConfig::openConfig(), "BackendChooseDialog");
if (conf.exists()) {
KWindowConfig::restoreWindowSize(windowHandle(), conf);
resize(windowHandle()->size()); // workaround for QTBUG-40584
} else
resize(QSize(500, 200).expandedTo(minimumSize()));
// open URLs in the external browser
m_ui.descriptionView->setOpenLinks(false);
connect(m_ui.descriptionView, &QTextBrowser::anchorClicked, this, [=](const QUrl &link)
{
QDesktopServices::openUrl(QUrl(link));
});
//restore saved settings if available
create(); // ensure there's a window created
KConfigGroup conf(KSharedConfig::openConfig(), "BackendChooseDialog");
if (conf.exists()) {
KWindowConfig::restoreWindowSize(windowHandle(), conf);
resize(windowHandle()->size()); // workaround for QTBUG-40584
} else
resize(QSize(500, 200).expandedTo(minimumSize()));
}
BackendChooseDialog::~BackendChooseDialog() {
......
......@@ -455,6 +455,16 @@ void MaximaExpression::parseResult(const QString& resultContent)
else
{
//no latex output is available, the actual result is part of the textContent string
// text output is quoted by Maxima, remove the quotes. No need to do it for internal
// commands to fetch the list of current variables, the proper parsing is done in MaximaVariableModel::parse().
if (!isInternal() && textContent.startsWith(QLatin1String("\"")))
{
textContent.remove(0, 1);
textContent.chop(1);
textContent.replace(QLatin1String("\\\""), QLatin1String("\""));
}
result = new Cantor::TextResult(textContent);
}
......
......@@ -117,6 +117,14 @@ QList<Cantor::DefaultVariableModel::Variable> parse(MaximaExpression* expr)
{
var.value=variableValues.at(i).trimmed();
var.value=var.value.remove(QLatin1String("\n")); //lists with many elements have line breaks, remove them
// text output is quoted by Maxima, remove the quotes
if (var.value.startsWith(QLatin1String("\"")))
{
var.value.remove(0, 1);
var.value.chop(1);
var.value.replace(QLatin1String("\\\""), QLatin1String("\""));
}
}
else
var.value=QLatin1String("unknown");
......
......@@ -342,22 +342,49 @@ void TestMaxima::testHelpRequest()
QVERIFY(e->results().size() == 2); //two results, the warning and the actual result of the calculation
}
void TestMaxima::testTextQuotes()
{
// check simple sting
auto* e1 = evalExp(QLatin1String("t1: \"test string\""));
QVERIFY(e1 != nullptr);
if(session()->status()==Cantor::Session::Running)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
QVERIFY(e1->result() != nullptr);
QCOMPARE(e1->result()->type(), (int)Cantor::TextResult::Type );
QCOMPARE(e1->result()->data().toString(), QLatin1String("test string"));
// check string with quotes inside
auto* e2 = evalExp(QLatin1String("t2: \"this is a \\\"quoted string\\\"\""));
QVERIFY(e2 != nullptr);
if(session()->status()==Cantor::Session::Running)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
QVERIFY(e2->result() != nullptr);
QCOMPARE(e2->result()->type(), (int)Cantor::TextResult::Type );
QCOMPARE(e2->result()->data().toString(), QLatin1String("this is a \"quoted string\""));
}
void TestMaxima::testVariableModel()
{
QAbstractItemModel* model = session()->variableModel();
QVERIFY(model != nullptr);
auto* e1=evalExp(QLatin1String("a: 15"));
auto* e2=evalExp(QLatin1String("a: 15; b: \"Hello, world!\""));
auto* e3=evalExp(QLatin1String("l: [1,2,3]"));
QVERIFY(e1!=nullptr);
QVERIFY(e2!=nullptr);
QVERIFY(e3!=nullptr);
auto* e1 = evalExp(QLatin1String("a: 15"));
auto* e2 = evalExp(QLatin1String("a: 15; b: \"Hello, world!\""));
auto* e3 = evalExp(QLatin1String("l: [1,2,3]"));
auto* e4 = evalExp(QLatin1String("t: \"this is a \\\"quoted string\\\"\""));
QVERIFY(e1 != nullptr);
QVERIFY(e2 != nullptr);
QVERIFY(e3 != nullptr);
QVERIFY(e4 != nullptr);
if(session()->status()==Cantor::Session::Running)
waitForSignal(session(), SIGNAL(statusChanged(Cantor::Session::Status)));
QCOMPARE(3, model->rowCount());
QCOMPARE(4, model->rowCount());
QVariant name = model->index(0,0).data();
QCOMPARE(name.toString(),QLatin1String("a"));
......@@ -369,13 +396,19 @@ void TestMaxima::testVariableModel()
QCOMPARE(name1.toString(),QLatin1String("b"));
QVariant value1 = model->index(1,1).data();
QCOMPARE(value1.toString(),QLatin1String("\"Hello, world!\""));
QCOMPARE(value1.toString(),QLatin1String("Hello, world!"));
QVariant name2 = model->index(2,0).data();
QCOMPARE(name2.toString(),QLatin1String("l"));
QVariant value2 = model->index(2,1).data();
QCOMPARE(value2.toString(),QLatin1String("[1,2,3]"));
QVariant name3 = model->index(3,0).data();
QCOMPARE(name3.toString(),QLatin1String("t"));
QVariant value3 = model->index(3,1).data();
QCOMPARE(value3.toString(),QLatin1String("this is a \"quoted string\""));
}
void TestMaxima::testLispMode01()
......
......@@ -58,6 +58,8 @@ private Q_SLOTS:
void testLispMode01();
void testTextQuotes();
void testLoginLogout();
void testRestartWhileRunning();
......
......@@ -46,14 +46,16 @@
<Action name="all_entries_remove_all_results"/>
<Separator/>
<Action name="remove_current"/>
</Menu>
<Menu name="settings">
<Action name="enable_typesetting"/>
<Action name="enable_highlighting"/>
<Action name="enable_completion"/>
<Action name="enable_expression_numbers"/>
<Action name="enable_animations"/>
<Action name="enable_embedded_math"/>
<Separator/>
<Menu name="settings"><text>Settings</text>
<Action name="enable_expression_numbers"/>
<Action name="enable_highlighting"/>
<Action name="enable_completion"/>
<Action name="enable_animations"/>
<Separator/>
<Action name="enable_typesetting"/>
<Action name="enable_embedded_math"/>
</Menu>
</Menu>
<Menu name="help">
<Action name="backend_help"/>
......
......@@ -13,6 +13,7 @@
#include <KLocalizedString>
#include <QFileDialog>
#include <QImageReader>
ImageResultItem::ImageResultItem(QGraphicsObject* parent, Cantor::Result* result)
: WorksheetImageItem(parent), ResultItem(result)
......@@ -84,9 +85,20 @@ double ImageResultItem::height() const
void ImageResultItem::saveResult()
{
Cantor::Result* res = result();
const QString& filename = QFileDialog::getSaveFileName(worksheet()->worksheetView(), i18n("Save result"), QString(), res->mimeType());
res->save(filename);
QString formats;
for (const auto& format : QImageReader::supportedImageFormats()) {
QString f = QLatin1String("*.") + QLatin1String(format.constData());
if (f == QLatin1String("*.svg")) // TODO: add SVG after we've switched internally to PDF/SVG for backend's output
continue;
formats += f + QLatin1Char(' ');
}
const auto& fileName = QFileDialog::getSaveFileName(worksheet()->worksheetView(),
i18n("Save image result"),
/*dir*/ QString(),
i18n("Images (%1)", formats));
if (!fileName.isEmpty())
result()->save(fileName);
}
void ImageResultItem::deleteLater()
......
......@@ -159,11 +159,9 @@ void ImageResult::saveAdditionalData(KZip* archive)
void ImageResult::save(const QString& filename)
{
//load into memory and let Qt save it, instead of just copying d->url
//to give possibility to convert file format
QImage img=data().value<QImage>();
img.save(filename);
bool rc = d->img.save(filename);
if (!rc)
qDebug()<<"saving to " << filename << " failed.";
}
QSize Cantor::ImageResult::displaySize()
......
......@@ -28,6 +28,7 @@ int main(int argc, char **argv)
QWebEngineUrlScheme::registerScheme(qthelp);
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication app(argc, argv);
// Add our custom plugins path, where we install our plugins, if it isn't default path
......
......@@ -40,7 +40,7 @@ TextResultItem::TextResultItem(WorksheetEntry* parent, Cantor::Result* result)
// We do it here, because we need it one
if (document()->characterCount() && document()->characterAt(0) == QChar::ParagraphSeparator)
{
Cantor::HtmlResult* hr = static_cast<Cantor::HtmlResult*>(m_result);
auto* hr = static_cast<Cantor::HtmlResult*>(m_result);
hr->setFormat(Cantor::HtmlResult::PlainAlternative);
setHtml(hr->toHtml());
}
......@@ -60,7 +60,7 @@ void TextResultItem::populateMenu(QMenu* menu, QPointF pos)
menu->addAction(copy);
ResultItem::addCommonActions(this, menu);
Cantor::Result* res = result();
auto* res = result();
if (res->type() == Cantor::LatexResult::Type) {
QAction* showCodeAction = nullptr;
Cantor::LatexResult* lres = static_cast<Cantor::LatexResult*>(res);
......@@ -149,7 +149,7 @@ void TextResultItem::setLatex(Cantor::LatexResult* result)
else
{
QString uuid = Cantor::LatexRenderer::genUuid();
Cantor::Renderer* renderer = qobject_cast<Worksheet*>(scene())->renderer();;
auto* renderer = qobject_cast<Worksheet*>(scene())->renderer();;
format = renderer->render(cursor.document(), Cantor::Renderer::EPS, result->url(), uuid);
format.setProperty(Cantor::Renderer::CantorFormula,
Cantor::Renderer::LatexFormula);
......@@ -178,7 +178,7 @@ double TextResultItem::height() const
void TextResultItem::toggleLatexCode()
{
Cantor::LatexResult* lr = static_cast<Cantor::LatexResult*>(result());
auto* lr = static_cast<Cantor::LatexResult*>(result());
if(lr->isCodeShown())
lr->showRendered();
else
......@@ -189,34 +189,30 @@ void TextResultItem::toggleLatexCode()
void TextResultItem::showHtml()
{
Cantor::HtmlResult* hr = static_cast<Cantor::HtmlResult*>(result());
auto* hr = static_cast<Cantor::HtmlResult*>(result());
hr->setFormat(Cantor::HtmlResult::Html);
parentEntry()->updateEntry();
}
void TextResultItem::showHtmlSource()
{
Cantor::HtmlResult* hr = static_cast<Cantor::HtmlResult*>(result());
auto* hr = static_cast<Cantor::HtmlResult*>(result());
hr->setFormat(Cantor::HtmlResult::HtmlSource);
parentEntry()->updateEntry();
}
void TextResultItem::showPlain()
{
Cantor::HtmlResult* hr = static_cast<Cantor::HtmlResult*>(result());
auto* hr = static_cast<Cantor::HtmlResult*>(result());
hr->setFormat(Cantor::HtmlResult::PlainAlternative);
parentEntry()->updateEntry();
}
void TextResultItem::saveResult()
{
auto* res = result();
const QString& filename = QFileDialog::getSaveFileName(worksheet()->worksheetView(), i18n("Save result"), QString(), res->mimeType());
if (!filename.isEmpty())
{
qDebug() << "saving result to " << filename;
res->save(filename);
}
const auto& fileName = QFileDialog::getSaveFileName(worksheet()->worksheetView(), i18n("Save text result"), QString(), i18n("Text Files (*.txt)"));
if (!fileName.isEmpty())
result()->save(fileName);
}
void TextResultItem::deleteLater()
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment