| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| #include <QMessageBox> |
| #include <boost/algorithm/string.hpp> |
|
|
| #include <App/Application.h> |
| #include <App/Document.h> |
| #include <App/ExpressionParser.h> |
| #include <App/Range.h> |
| #include <Gui/CommandT.h> |
|
|
| #include "DlgBindSheet.h" |
| #include "ui_DlgBindSheet.h" |
|
|
|
|
| using namespace App; |
| using namespace Spreadsheet; |
| using namespace SpreadsheetGui; |
|
|
| DlgBindSheet::DlgBindSheet(Sheet* sheet, const std::vector<Range>& ranges, QWidget* parent) |
| : QDialog(parent) |
| , sheet(sheet) |
| , range(ranges.front()) |
| , ui(new Ui::DlgBindSheet) |
| { |
| ui->setupUi(this); |
| |
| setWindowFlag(Qt::WindowContextHelpButtonHint, false); |
|
|
| std::string toStart, toEnd; |
| ExpressionPtr pStart, pEnd; |
| App::ObjectIdentifier bindingTarget; |
| PropertySheet::BindingType type = sheet->getCellBinding(range, &pStart, &pEnd, &bindingTarget); |
| if (type == PropertySheet::BindingNone) { |
| if (ranges.size() > 1) { |
| toStart = ranges.back().from().toString(); |
| toEnd = ranges.back().to().toString(); |
| } |
| else { |
| CellAddress target(range.to().row() ? 0 : range.to().row() + 1, range.from().col()); |
| toStart = target.toString(); |
| target.setRow(target.row() + range.to().row() - range.from().row()); |
| target.setCol(target.col() + range.to().col() - range.from().col()); |
| toEnd = target.toString(); |
| } |
| ui->btnDiscard->setDisabled(true); |
| } |
| else { |
| ui->lineEditFromStart->setReadOnly(true); |
| ui->lineEditFromEnd->setReadOnly(true); |
| ui->checkBoxHREF->setChecked(type == PropertySheet::BindingHiddenRef); |
| assert(pStart && pEnd); |
| if (!pStart->hasComponent() && pStart->isDerivedFrom<StringExpression>()) { |
| toStart = static_cast<StringExpression*>(pStart.get())->getText(); |
| } |
| else { |
| toStart = "="; |
| toStart += pStart->toString(); |
| } |
| if (!pEnd->hasComponent() && pEnd->isDerivedFrom<StringExpression>()) { |
| toEnd = static_cast<StringExpression*>(pEnd.get())->getText(); |
| } |
| else { |
| toEnd = "="; |
| toEnd += pEnd->toString(); |
| } |
| } |
|
|
| ui->lineEditFromStart->setText(QString::fromLatin1(range.from().toString().c_str())); |
| ui->lineEditFromEnd->setText(QString::fromLatin1(range.to().toString().c_str())); |
|
|
| ui->lineEditToStart->setDocumentObject(sheet, false); |
| ui->lineEditToStart->setPrefix('='); |
| ui->lineEditToEnd->setDocumentObject(sheet, false); |
| ui->lineEditToEnd->setPrefix('='); |
|
|
| ui->lineEditToStart->setText(QLatin1String(toStart.c_str())); |
| ui->lineEditToEnd->setText(QLatin1String(toEnd.c_str())); |
|
|
| ui->comboBox->addItem( |
| QStringLiteral(". (%1)").arg(QString::fromUtf8(sheet->Label.getValue())), |
| QByteArray("") |
| ); |
|
|
| App::DocumentObject* target = bindingTarget.getDocumentObject(); |
| for (auto obj : sheet->getDocument()->getObjectsOfType<Sheet>()) { |
| if (obj == sheet) { |
| continue; |
| } |
| QString label; |
| if (obj->Label.getStrValue() != obj->getNameInDocument()) { |
| label = QStringLiteral("%1 (%2)").arg( |
| QString::fromLatin1(obj->getNameInDocument()), |
| QString::fromUtf8(obj->Label.getValue()) |
| ); |
| } |
| else { |
| label = QLatin1String(obj->getNameInDocument()); |
| } |
| ui->comboBox->addItem(label, QByteArray(obj->getNameInDocument())); |
| if (obj == target) { |
| ui->comboBox->setCurrentIndex(ui->comboBox->count() - 1); |
| } |
| } |
| for (auto doc : GetApplication().getDocuments()) { |
| if (doc == sheet->getDocument()) { |
| continue; |
| } |
| for (auto obj : sheet->getDocument()->getObjectsOfType<Sheet>()) { |
| if (obj == sheet) { |
| continue; |
| } |
| std::string fullname = obj->getFullName(); |
| QString label; |
| if (obj->Label.getStrValue() != obj->getNameInDocument()) { |
| label = QStringLiteral("%1 (%2)").arg( |
| QString::fromLatin1(fullname.c_str()), |
| QString::fromUtf8(obj->Label.getValue()) |
| ); |
| } |
| else { |
| label = QLatin1String(fullname.c_str()); |
| } |
| ui->comboBox->addItem(label, QByteArray(fullname.c_str())); |
| if (obj == target) { |
| ui->comboBox->setCurrentIndex(ui->comboBox->count() - 1); |
| } |
| } |
| } |
|
|
| connect(ui->btnDiscard, &QPushButton::clicked, this, &DlgBindSheet::onDiscard); |
| } |
|
|
| DlgBindSheet::~DlgBindSheet() |
| { |
| delete ui; |
| } |
|
|
| void DlgBindSheet::accept() |
| { |
| bool commandActive = false; |
| try { |
| const char* ref = ui->comboBox->itemData(ui->comboBox->currentIndex()) |
| .toByteArray() |
| .constData(); |
| auto obj = sheet; |
| if (ref[0]) { |
| const char* sep = strchr(ref, '#'); |
| if (sep) { |
| std::string docname(ref, sep); |
| auto doc = GetApplication().getDocument(docname.c_str()); |
| if (!doc) { |
| FC_THROWM(Base::RuntimeError, "Cannot find document " << docname); |
| } |
| obj = freecad_cast<Sheet*>(doc->getObject(sep + 1)); |
| } |
| else { |
| obj = freecad_cast<Sheet*>(sheet->getDocument()->getObject(ref)); |
| } |
| if (!obj) { |
| FC_THROWM(Base::RuntimeError, "Cannot find Spreadsheet '" << ref << "'"); |
| } |
| } |
|
|
| auto checkAddress = [](std::string& addr, CellAddress& cell, bool quote) { |
| std::string copy(addr); |
| boost::to_upper(copy); |
| cell = App::stringToAddress(copy.c_str(), true); |
| if (!cell.isValid()) { |
| std::string msg("Invalid cell: "); |
| msg += addr; |
| throw Base::ValueError(msg.c_str()); |
| } |
| if (quote) { |
| addr = std::string("<<") + copy + ">>"; |
| } |
| else { |
| addr = std::move(copy); |
| } |
| }; |
|
|
| CellAddress fromCellStart, fromCellEnd, toCellStart, toCellEnd; |
| std::string fromStart(ui->lineEditFromStart->text().trimmed().toLatin1().constData()); |
| std::string fromEnd(ui->lineEditFromEnd->text().trimmed().toLatin1().constData()); |
| checkAddress(fromStart, fromCellStart, false); |
| checkAddress(fromEnd, fromCellEnd, false); |
|
|
| std::string toStart(ui->lineEditToStart->text().trimmed().toLatin1().constData()); |
| if (boost::starts_with(toStart, "=")) { |
| toStart.erase(toStart.begin()); |
| } |
| else { |
| checkAddress(toStart, toCellStart, true); |
| } |
|
|
| std::string toEnd(ui->lineEditToEnd->text().trimmed().toLatin1().constData()); |
| if (boost::starts_with(toEnd, "=")) { |
| toEnd.erase(toEnd.begin()); |
| } |
| else { |
| checkAddress(toEnd, toCellEnd, true); |
| if (toCellStart.isValid()) { |
| App::Range fromRange(fromCellStart, fromCellEnd, true); |
| App::Range toRange(toCellStart, toCellEnd, true); |
| if (fromRange.size() != toRange.size()) { |
| auto res = QMessageBox::warning( |
| this, |
| tr("Bind Cells"), |
| tr("Source and target cell count mismatch. " |
| "Partial binding may still work.\n\n" |
| "Continue?"), |
| QMessageBox::Yes | QMessageBox::No |
| ); |
| if (res == QMessageBox::No) { |
| return; |
| } |
| } |
| } |
| } |
|
|
| Gui::Command::openCommand("Bind cells"); |
| commandActive = true; |
|
|
| if (ui->checkBoxHREF->isChecked()) { |
| Gui::cmdAppObjectArgs(sheet, "setExpression('.cells.Bind.%s.%s', None)", fromStart, fromEnd); |
| Gui::cmdAppObjectArgs( |
| sheet, |
| "setExpression('.cells.BindHiddenRef.%s.%s', 'hiddenref(tuple(%s.cells, %s, %s))')", |
| fromStart, |
| fromEnd, |
| ref, |
| toStart, |
| toEnd |
| ); |
| } |
| else { |
| Gui::cmdAppObjectArgs( |
| sheet, |
| "setExpression('.cells.BindHiddenRef.%s.%s', None)", |
| fromStart, |
| fromEnd |
| ); |
| Gui::cmdAppObjectArgs( |
| sheet, |
| "setExpression('.cells.Bind.%s.%s', 'tuple(%s.cells, %s, %s)')", |
| fromStart, |
| fromEnd, |
| ref, |
| toStart, |
| toEnd |
| ); |
| } |
| Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); |
| Gui::Command::commitCommand(); |
| QDialog::accept(); |
| } |
| catch (Base::Exception& e) { |
| e.reportException(); |
| QMessageBox::critical( |
| this, |
| tr("Bind Spreadsheet Cells"), |
| tr("Error:\n") + QString::fromUtf8(e.what()) |
| ); |
| if (commandActive) { |
| Gui::Command::abortCommand(); |
| } |
| } |
| } |
|
|
| void DlgBindSheet::onDiscard() |
| { |
| try { |
| std::string fromStart(ui->lineEditFromStart->text().trimmed().toLatin1().constData()); |
| std::string fromEnd(ui->lineEditFromEnd->text().trimmed().toLatin1().constData()); |
| Gui::Command::openCommand("Unbind cells"); |
| Gui::cmdAppObjectArgs(sheet, "setExpression('.cells.Bind.%s.%s', None)", fromStart, fromEnd); |
| Gui::cmdAppObjectArgs( |
| sheet, |
| "setExpression('.cells.BindHiddenRef.%s.%s', None)", |
| fromStart, |
| fromEnd |
| ); |
| Gui::Command::doCommand(Gui::Command::Doc, "App.ActiveDocument.recompute()"); |
| Gui::Command::commitCommand(); |
| reject(); |
| } |
| catch (Base::Exception& e) { |
| e.reportException(); |
| QMessageBox::critical(this, tr("Unbind Cells"), QString::fromUtf8(e.what())); |
| Gui::Command::abortCommand(); |
| } |
| } |
|
|
| #include "moc_DlgBindSheet.cpp" |
|
|