Spreadsheet: add a few context menu options

This commit is contained in:
Zheng, Lei
2019-12-24 10:34:50 +08:00
committed by Chris Hennes
parent 2c6f621721
commit 127e8098e8
6 changed files with 214 additions and 30 deletions

View File

@@ -792,6 +792,12 @@ void Sheet::touchCells(Range range) {
}while(range.next());
}
void Sheet::recomputeCells(Range range) {
do {
recomputeCell(*range);
}while(range.next());
}
/**
* @brief Recompute cell at address \a p.
* @param p Address of cell.

View File

@@ -179,6 +179,8 @@ public:
void touchCells(App::Range range);
void recomputeCells(App::Range range);
// Signals
boost::signals2::signal<void (App::CellAddress)> cellUpdated;

View File

@@ -165,5 +165,20 @@
<UserDocu>Get given spreadsheet row height</UserDocu>
</Documentation>
</Methode>
<Methode Name="touchCells">
<Documentation>
<UserDocu>touchCells(from, to=None): touch cells in the given range</UserDocu>
</Documentation>
</Methode>
<Methode Name="recomputeCells">
<Documentation>
<UserDocu>
recomputeCells(from, to=None)
Manually recompute cells in the given range with the given order without
following depedency order.
</UserDocu>
</Documentation>
</Methode>
</PythonExport>
</GenerateModel>

View File

@@ -91,15 +91,41 @@ PyObject* SheetPy::set(PyObject *args)
PyObject* SheetPy::get(PyObject *args)
{
char *address;
const char *address;
const char *address2=0;
if (!PyArg_ParseTuple(args, "s:get", &address))
if (!PyArg_ParseTuple(args, "s|s:get", &address, &address2))
return 0;
PY_TRY {
if(address2) {
auto a1 = getSheetPtr()->getAddressFromAlias(address);
if(a1.empty())
a1 = address;
auto a2 = getSheetPtr()->getAddressFromAlias(address2);
if(a2.empty())
a2 = address2;
Range range(a1.c_str(),a2.c_str());
Py::Tuple tuple(range.size());
int i=0;
do {
App::Property *prop = getSheetPtr()->getPropertyByName(range.address().c_str());
if(!prop) {
PyErr_Format(PyExc_ValueError, "Invalid address '%s' in range %s:%s",
range.address().c_str(), address, address2);
return 0;
}
tuple.setItem(i++,Py::Object(prop->getPyObject(),true));
}while(range.next());
return Py::new_reference_to(tuple);
}
}PY_CATCH;
App::Property * prop = this->getSheetPtr()->getPropertyByName(address);
if (prop == 0) {
PyErr_SetString(PyExc_ValueError, "Invalid address or property.");
PyErr_Format(PyExc_ValueError,
"Invalid cell address or property: %s",address);
return 0;
}
return prop->getPyObject();
@@ -113,21 +139,29 @@ PyObject* SheetPy::getContents(PyObject *args)
if (!PyArg_ParseTuple(args, "s:getContents", &strAddress))
return 0;
try {
address = stringToAddress(strAddress);
}
catch (const Base::Exception & e) {
PyErr_SetString(PyExc_ValueError, e.what());
return 0;
}
PY_TRY {
try {
Sheet * sheet = getSheetPtr();
std::string addr = sheet->getAddressFromAlias(strAddress);
std::string contents;
const Cell * cell = this->getSheetPtr()->getCell(address);
if (addr.empty())
address = stringToAddress(strAddress);
else
address = stringToAddress(addr.c_str());
}
catch (const Base::Exception & e) {
PyErr_SetString(PyExc_ValueError, e.what());
return 0;
}
if (cell)
cell->getStringContent( contents );
std::string contents;
const Cell * cell = this->getSheetPtr()->getCell(address);
return Py::new_reference_to( Py::String( contents ) );
if (cell)
cell->getStringContent( contents );
return Py::new_reference_to( Py::String( contents ) );
} PY_CATCH
}
PyObject* SheetPy::clear(PyObject *args)
@@ -587,8 +621,10 @@ PyObject* SheetPy::setAlignment(PyObject *args)
std::string line = PyUnicode_AsUTF8(value);
tokenizer<escaped_list_separator<char> > tok(line, e);
for(tokenizer<escaped_list_separator<char> >::iterator i = tok.begin(); i != tok.end();++i)
alignment = Cell::decodeAlignment(*i, alignment);
for(tokenizer<escaped_list_separator<char> >::iterator i = tok.begin(); i != tok.end();++i) {
if(i->size())
alignment = Cell::decodeAlignment(*i, alignment);
}
}
else {
std::string error = std::string("style must be either set or string, not ") + value->ob_type->tp_name;
@@ -903,15 +939,61 @@ PyObject* SheetPy::getRowHeight(PyObject *args)
}
}
PyObject *SheetPy::touchCells(PyObject *args) {
const char *address;
const char *address2=0;
if (!PyArg_ParseTuple(args, "s|s:touchCells", &address, &address2))
return 0;
PY_TRY {
std::string a1 = getSheetPtr()->getAddressFromAlias(address);
if(a1.empty())
a1 = address;
std::string a2;
if(!address2) {
a2 = a1;
} else {
a2 = getSheetPtr()->getAddressFromAlias(address2);
if(a2.empty())
a2 = address2;
}
getSheetPtr()->touchCells(Range(a1.c_str(),a2.c_str()));
Py_Return;
}PY_CATCH;
}
PyObject *SheetPy::recomputeCells(PyObject *args) {
const char *address;
const char *address2=0;
if (!PyArg_ParseTuple(args, "s|s:touchCells", &address, &address2))
return 0;
PY_TRY {
std::string a1 = getSheetPtr()->getAddressFromAlias(address);
if(a1.empty())
a1 = address;
std::string a2;
if(!address2) {
a2 = a1;
} else {
a2 = getSheetPtr()->getAddressFromAlias(address2);
if(a2.empty())
a2 = address2;
}
getSheetPtr()->recomputeCells(Range(a1.c_str(),a2.c_str()));
Py_Return;
}PY_CATCH;
}
// +++ custom attributes implementer ++++++++++++++++++++++++++++++++++++++++
PyObject *SheetPy::getCustomAttributes(const char* attr) const
PyObject *SheetPy::getCustomAttributes(const char*) const
{
App::Property * prop = this->getSheetPtr()->getPropertyByName(attr);
if (prop == 0)
return 0;
return prop->getPyObject();
return 0;
}
int SheetPy::setCustomAttributes(const char* , PyObject* )

View File

@@ -24,6 +24,7 @@
#ifndef _PreComp_
# include <QKeyEvent>
# include <QAction>
# include <QMenu>
# include <QApplication>
# include <QClipboard>
# include <QMenu>
@@ -35,6 +36,7 @@
#include <App/AutoTransaction.h>
#include <App/Document.h>
#include <Gui/CommandT.h>
#include <Gui/Application.h>
#include <Gui/MainWindow.h>
#include <boost_bind_bind.hpp>
#include "../App/Utils.h"
@@ -108,9 +110,6 @@ SheetTableView::SheetTableView(QWidget *parent)
setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
horizontalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
verticalHeader()->setContextMenuPolicy(Qt::CustomContextMenu);
connect(verticalHeader(), &QWidget::customContextMenuRequested,
[this](const QPoint &point){
QMenu menu(this);
@@ -163,11 +162,46 @@ SheetTableView::SheetTableView(QWidget *parent)
auto cellProperties = new QAction(tr("Properties..."), this);
addAction(cellProperties);
horizontalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
verticalHeader()->setContextMenuPolicy(Qt::ActionsContextMenu);
setContextMenuPolicy(Qt::ActionsContextMenu);
setTabKeyNavigation(false);
contextMenu = new QMenu(this);
contextMenu->addAction(cellProperties);
connect(cellProperties, SIGNAL(triggered()), this, SLOT(cellProperties()));
contextMenu->addSeparator();
QAction *recompute = new QAction(tr("Recompute"),this);
connect(recompute, SIGNAL(triggered()), this, SLOT(onRecompute()));
contextMenu->addAction(recompute);
contextMenu->addSeparator();
actionMerge = contextMenu->addAction(tr("Merge cells"));
connect(actionMerge,SIGNAL(triggered()), this, SLOT(mergeCells()));
actionSplit = contextMenu->addAction(tr("Split cells"));
connect(actionSplit,SIGNAL(triggered()), this, SLOT(splitCell()));
contextMenu->addSeparator();
actionCut = contextMenu->addAction(tr("Cut"));
connect(actionCut,SIGNAL(triggered()), this, SLOT(cutSelection()));
actionCopy = contextMenu->addAction(tr("Copy"));
connect(actionCopy,SIGNAL(triggered()), this, SLOT(copySelection()));
actionPaste = contextMenu->addAction(tr("Paste"));
connect(actionPaste,SIGNAL(triggered()), this, SLOT(pasteClipboard()));
actionDel = contextMenu->addAction(tr("Delete"));
connect(actionDel,SIGNAL(triggered()), this, SLOT(deleteSelection()));
setTabKeyNavigation(false);
}
void SheetTableView::onRecompute() {
Gui::Command::openCommand("Recompute cells");
for(auto &range : selectedRanges()) {
Gui::cmdAppObjectArgs(sheet, "recomputeCells('%s', '%s')",
range.fromCellString(), range.toCellString());
}
Gui::Command::commitCommand();
}
void SheetTableView::cellProperties()
@@ -828,6 +862,14 @@ void SheetTableView::ModifyBlockSelection(int targetRow, int targetCol)
this->selectionModel()->setCurrentIndex(model()->index(targetRow, targetCol), QItemSelectionModel::Current);
}
void SheetTableView::mergeCells() {
Gui::Application::Instance->commandManager().runCommandByName("Spreadsheet_MergeCells");
}
void SheetTableView::splitCell() {
Gui::Application::Instance->commandManager().runCommandByName("Spreadsheet_SplitCell");
}
void SheetTableView::closeEditor(QWidget * editor, QAbstractItemDelegate::EndEditHint hint)
{
QTableView::closeEditor(editor, hint);
@@ -845,4 +887,25 @@ void SheetTableView::edit ( const QModelIndex & index )
QTableView::edit(index);
}
void SheetTableView::contextMenuEvent(QContextMenuEvent *) {
const QMimeData* mimeData = QApplication::clipboard()->mimeData();
if(!selectionModel()->hasSelection()) {
actionCut->setEnabled(false);
actionCopy->setEnabled(false);
actionDel->setEnabled(false);
actionPaste->setEnabled(false);
actionSplit->setEnabled(false);
actionMerge->setEnabled(false);
}else{
actionPaste->setEnabled(mimeData && (mimeData->hasText() || mimeData->hasText()));
actionCut->setEnabled(true);
actionCopy->setEnabled(true);
actionDel->setEnabled(true);
actionSplit->setEnabled(true);
actionMerge->setEnabled(true);
}
contextMenu->exec(QCursor::pos());
}
#include "moc_SheetTableView.cpp"

View File

@@ -58,12 +58,15 @@ public:
void edit(const QModelIndex &index);
void setSheet(Spreadsheet::Sheet *_sheet);
std::vector<App::Range> selectedRanges() const;
public Q_SLOTS:
void mergeCells();
void splitCell();
void deleteSelection();
void copySelection();
void cutSelection();
void pasteClipboard();
void finishEditWithMove(int keyPressed, Qt::KeyboardModifiers modifiers, bool handleTabMotion = false);
void finishEditWithMove(int keyPressed, Qt::KeyboardModifiers modifiers, bool handleTabMotion = false);
void ModifyBlockSelection(int targetRow, int targetColumn);
protected Q_SLOTS:
@@ -76,16 +79,29 @@ protected Q_SLOTS:
void insertColumnsAfter();
void removeColumns();
void cellProperties();
void onRecompute();
protected:
bool edit(const QModelIndex &index, EditTrigger trigger, QEvent *event);
bool event(QEvent *event);
void closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint);
void mousePressEvent(QMouseEvent* event);
void contextMenuEvent (QContextMenuEvent * e);
QModelIndex currentEditIndex;
Spreadsheet::Sheet * sheet;
int tabCounter;
QMenu *contextMenu;
QAction *actionMerge;
QAction *actionSplit;
QAction *actionCopy;
QAction *actionPaste;
QAction *actionCut;
QAction *actionDel;
boost::signals2::scoped_connection cellSpanChangedConnection;
};