GUI: introduce an additional AbstractStdTable layer to prepare for the new symbol view
This commit is contained in:
parent
83005bdcda
commit
7c30c5993b
|
@ -0,0 +1,715 @@
|
|||
#include "AbstractStdTable.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
AbstractStdTable::AbstractStdTable(QWidget* parent) : AbstractTableView(parent)
|
||||
{
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(Bridge::getBridge(), SIGNAL(repaintTableView()), this, SLOT(reloadData()));
|
||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequestedSlot(QPoint)));
|
||||
connect(this, SIGNAL(headerButtonPressed(int)), this, SLOT(headerButtonPressedSlot(int)));
|
||||
}
|
||||
|
||||
QString AbstractStdTable::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h)
|
||||
{
|
||||
if(isSelected(rowBase, rowOffset))
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(selectionColor));
|
||||
return getCellContent(rowBase + rowOffset, col);
|
||||
}
|
||||
|
||||
void AbstractStdTable::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
bool wAccept = true;
|
||||
int y = transY(event->y());
|
||||
|
||||
if(mGuiState == AbstractStdTable::MultiRowsSelectionState)
|
||||
{
|
||||
//qDebug() << "State = MultiRowsSelectionState";
|
||||
|
||||
if(y >= 0 && y <= this->getTableHeight())
|
||||
{
|
||||
int wRowIndex = getTableOffset() + getIndexOffsetFromY(y);
|
||||
|
||||
if(wRowIndex < getRowCount())
|
||||
{
|
||||
if(mIsMultiSelectionAllowed)
|
||||
expandSelectionUpTo(wRowIndex);
|
||||
else
|
||||
setSingleSelection(wRowIndex);
|
||||
|
||||
updateViewport();
|
||||
|
||||
wAccept = false;
|
||||
}
|
||||
}
|
||||
else if(y < 0)
|
||||
{
|
||||
verticalScrollBar()->triggerAction(QAbstractSlider::SliderSingleStepSub);
|
||||
}
|
||||
else if(y > getTableHeight())
|
||||
{
|
||||
verticalScrollBar()->triggerAction(QAbstractSlider::SliderSingleStepAdd);
|
||||
}
|
||||
}
|
||||
|
||||
if(wAccept)
|
||||
AbstractTableView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void AbstractStdTable::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
bool wAccept = false;
|
||||
|
||||
if(((event->buttons() & Qt::LeftButton) != 0) && ((event->buttons() & Qt::RightButton) == 0))
|
||||
{
|
||||
if(getGuiState() == AbstractTableView::NoState)
|
||||
{
|
||||
if(event->y() > getHeaderHeight())
|
||||
{
|
||||
int wRowIndex = getTableOffset() + getIndexOffsetFromY(transY(event->y()));
|
||||
|
||||
if(wRowIndex < getRowCount())
|
||||
{
|
||||
if(mIsMultiSelectionAllowed && (event->modifiers() & Qt::ShiftModifier))
|
||||
expandSelectionUpTo(wRowIndex);
|
||||
else
|
||||
setSingleSelection(wRowIndex);
|
||||
|
||||
mGuiState = AbstractStdTable::MultiRowsSelectionState;
|
||||
|
||||
updateViewport();
|
||||
|
||||
wAccept = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!wAccept)
|
||||
AbstractTableView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void AbstractStdTable::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
if(event->y() > getHeaderHeight() && event->button() == Qt::LeftButton)
|
||||
emit doubleClickedSignal();
|
||||
AbstractTableView::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void AbstractStdTable::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
bool wAccept = true;
|
||||
|
||||
if((event->buttons() & Qt::LeftButton) == 0)
|
||||
{
|
||||
if(mGuiState == AbstractStdTable::MultiRowsSelectionState)
|
||||
{
|
||||
mGuiState = AbstractStdTable::NoState;
|
||||
|
||||
updateViewport();
|
||||
|
||||
wAccept = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(wAccept)
|
||||
AbstractTableView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void AbstractStdTable::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
emit keyPressedSignal(event);
|
||||
int key = event->key();
|
||||
Qt::KeyboardModifiers modifiers = event->modifiers();
|
||||
|
||||
if(key == Qt::Key_Up ||
|
||||
key == Qt::Key_Down ||
|
||||
key == Qt::Key_Home ||
|
||||
key == Qt::Key_End ||
|
||||
key == Qt::Key_A)
|
||||
{
|
||||
dsint wBotIndex = getTableOffset();
|
||||
dsint wTopIndex = wBotIndex + getNbrOfLineToPrint() - 1;
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+Up -> expand selection upwards
|
||||
{
|
||||
expandUp();
|
||||
}
|
||||
else //Up -> select previous
|
||||
{
|
||||
selectPrevious();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+Down -> expand selection downwards
|
||||
{
|
||||
expandDown();
|
||||
}
|
||||
else //Down -> select next
|
||||
{
|
||||
selectNext();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Home:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+Home -> expand selection to top
|
||||
{
|
||||
expandTop();
|
||||
}
|
||||
else if(modifiers == Qt::NoModifier) //Home -> select first line
|
||||
{
|
||||
selectStart();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_End:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+End -> expand selection to bottom
|
||||
{
|
||||
expandBottom();
|
||||
}
|
||||
else if(modifiers == Qt::NoModifier) //End -> select last line
|
||||
{
|
||||
selectEnd();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_A:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ControlModifier) //Ctrl+A -> select all
|
||||
{
|
||||
selectAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(getInitialSelection() < wBotIndex)
|
||||
{
|
||||
setTableOffset(getInitialSelection());
|
||||
}
|
||||
else if(getInitialSelection() >= wTopIndex)
|
||||
{
|
||||
setTableOffset(getInitialSelection() - getNbrOfLineToPrint() + 2);
|
||||
}
|
||||
|
||||
updateViewport();
|
||||
}
|
||||
else
|
||||
{
|
||||
AbstractTableView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::enableMultiSelection(bool enabled)
|
||||
{
|
||||
mIsMultiSelectionAllowed = enabled;
|
||||
}
|
||||
|
||||
void AbstractStdTable::enableColumnSorting(bool enabled)
|
||||
{
|
||||
mIsColumnSortingAllowed = enabled;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Selection Management
|
||||
************************************************************************************/
|
||||
void AbstractStdTable::expandSelectionUpTo(int to)
|
||||
{
|
||||
if(to < mSelection.firstSelectedIndex)
|
||||
{
|
||||
mSelection.fromIndex = to;
|
||||
mSelection.toIndex = mSelection.firstSelectedIndex;
|
||||
emit selectionChangedSignal(to);
|
||||
}
|
||||
else if(to > mSelection.firstSelectedIndex)
|
||||
{
|
||||
mSelection.fromIndex = mSelection.firstSelectedIndex;
|
||||
mSelection.toIndex = to;
|
||||
emit selectionChangedSignal(to);
|
||||
}
|
||||
else if(to == mSelection.firstSelectedIndex)
|
||||
{
|
||||
setSingleSelection(to);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::expandUp()
|
||||
{
|
||||
int wRowIndex = mSelection.firstSelectedIndex - 1;
|
||||
if(wRowIndex >= 0)
|
||||
{
|
||||
if(wRowIndex < mSelection.fromIndex)
|
||||
{
|
||||
mSelection.fromIndex = wRowIndex;
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
mSelection.toIndex = wRowIndex;
|
||||
}
|
||||
|
||||
emit selectionChangedSignal(wRowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::expandDown()
|
||||
{
|
||||
int wRowIndex = mSelection.firstSelectedIndex + 1;
|
||||
int endIndex = getRowCount() - 1;
|
||||
if(wRowIndex <= endIndex)
|
||||
{
|
||||
|
||||
if(wRowIndex > mSelection.toIndex)
|
||||
{
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
mSelection.toIndex = wRowIndex;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.fromIndex = wRowIndex;
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
}
|
||||
|
||||
|
||||
emit selectionChangedSignal(wRowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::expandTop()
|
||||
{
|
||||
if(getRowCount() > 0)
|
||||
{
|
||||
expandSelectionUpTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::expandBottom()
|
||||
{
|
||||
int endIndex = getRowCount() - 1;
|
||||
if(endIndex >= 0)
|
||||
{
|
||||
expandSelectionUpTo(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::setSingleSelection(int index)
|
||||
{
|
||||
mSelection.firstSelectedIndex = index;
|
||||
mSelection.fromIndex = index;
|
||||
mSelection.toIndex = index;
|
||||
emit selectionChangedSignal(index);
|
||||
}
|
||||
|
||||
int AbstractStdTable::getInitialSelection()
|
||||
{
|
||||
return mSelection.firstSelectedIndex;
|
||||
}
|
||||
|
||||
QList<int> AbstractStdTable::getSelection()
|
||||
{
|
||||
QList<int> selection;
|
||||
selection.reserve(mSelection.toIndex - mSelection.fromIndex);
|
||||
for(int i = mSelection.fromIndex; i <= mSelection.toIndex; i++)
|
||||
{
|
||||
selection.append(i);
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
|
||||
void AbstractStdTable::selectStart()
|
||||
{
|
||||
if(getRowCount() > 0)
|
||||
{
|
||||
setSingleSelection(0);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::selectEnd()
|
||||
{
|
||||
int endIndex = getRowCount() - 1;
|
||||
if(endIndex >= 0)
|
||||
{
|
||||
setSingleSelection(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::selectNext()
|
||||
{
|
||||
int wNext = getInitialSelection() + 1;
|
||||
|
||||
// Bounding
|
||||
wNext = wNext > getRowCount() - 1 ? getRowCount() - 1 : wNext;
|
||||
wNext = wNext < 0 ? 0 : wNext;
|
||||
|
||||
setSingleSelection(wNext);
|
||||
}
|
||||
|
||||
void AbstractStdTable::selectPrevious()
|
||||
{
|
||||
int wNext = getInitialSelection() - 1;
|
||||
|
||||
// Bounding
|
||||
wNext = wNext > getRowCount() - 1 ? getRowCount() - 1 : wNext;
|
||||
wNext = wNext < 0 ? 0 : wNext;
|
||||
|
||||
setSingleSelection(wNext);
|
||||
}
|
||||
|
||||
void AbstractStdTable::selectAll()
|
||||
{
|
||||
int index = 0;
|
||||
int indexEnd = getRowCount() - 1;
|
||||
|
||||
mSelection.firstSelectedIndex = index;
|
||||
mSelection.fromIndex = index;
|
||||
mSelection.toIndex = indexEnd;
|
||||
|
||||
emit selectionChangedSignal(index);
|
||||
}
|
||||
|
||||
bool AbstractStdTable::isSelected(int base, int offset)
|
||||
{
|
||||
int wIndex = base + offset;
|
||||
|
||||
if(wIndex >= mSelection.fromIndex && wIndex <= mSelection.toIndex)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AbstractStdTable::scrollSelect(int offset)
|
||||
{
|
||||
if(!isValidIndex(offset, 0))
|
||||
return false;
|
||||
|
||||
int rangefrom = getTableOffset();
|
||||
int rangeto = rangefrom + getViewableRowsCount() - 1;
|
||||
if(offset < rangefrom) //offset lays before the current view
|
||||
setTableOffset(offset);
|
||||
else if(offset > (rangeto - 1)) //offset lays after the current view
|
||||
setTableOffset(offset - getViewableRowsCount() + 2);
|
||||
setSingleSelection(offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Data Management
|
||||
************************************************************************************/
|
||||
void AbstractStdTable::addColumnAt(int width, QString title, bool isClickable, QString copyTitle)
|
||||
{
|
||||
AbstractTableView::addColumnAt(width, title, isClickable);
|
||||
|
||||
//Append copy title
|
||||
if(!copyTitle.length())
|
||||
mCopyTitles.push_back(title);
|
||||
else
|
||||
mCopyTitles.push_back(copyTitle);
|
||||
}
|
||||
|
||||
void AbstractStdTable::deleteAllColumns()
|
||||
{
|
||||
setRowCount(0);
|
||||
AbstractTableView::deleteAllColumns();
|
||||
mCopyTitles.clear();
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyLineSlot()
|
||||
{
|
||||
int colCount = getColumnCount();
|
||||
QString finalText = "";
|
||||
if(colCount == 1)
|
||||
finalText = getCellContent(getInitialSelection(), 0);
|
||||
else
|
||||
{
|
||||
for(int selected : getSelection())
|
||||
{
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
QString cellContent = getCellContent(selected, i);
|
||||
if(!cellContent.length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(title.length())
|
||||
finalText += title + "=";
|
||||
finalText += cellContent.trimmed();;
|
||||
finalText += "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
Bridge::CopyToClipboard(finalText);
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyLineToLogSlot()
|
||||
{
|
||||
int colCount = getColumnCount();
|
||||
int selected = getInitialSelection();
|
||||
QString finalText = "";
|
||||
if(colCount == 1)
|
||||
finalText = getCellContent(selected, 0);
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
QString cellContent = getCellContent(selected, i);
|
||||
if(!cellContent.length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(title.length())
|
||||
finalText += title + "=";
|
||||
finalText += cellContent.trimmed();;
|
||||
finalText += "\r\n";
|
||||
}
|
||||
}
|
||||
emit Bridge::getBridge()->addMsgToLog(finalText.toUtf8());
|
||||
}
|
||||
|
||||
QString AbstractStdTable::copyTable(const std::vector<int> & colWidths)
|
||||
{
|
||||
int colCount = getColumnCount();
|
||||
int rowCount = getRowCount();
|
||||
QString finalText = "";
|
||||
if(colCount == 1)
|
||||
{
|
||||
for(int i = 0; i < rowCount; i++)
|
||||
{
|
||||
QString cellContent = getCellContent(i, 0);
|
||||
if(!cellContent.length()) //skip empty cells
|
||||
continue;
|
||||
finalText += cellContent + "\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::vector<int> colWidths;
|
||||
//for(int i = 0; i < colCount; i++)
|
||||
// colWidths.push_back(getMaxColumnLength(i));
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
if(i)
|
||||
finalText += " ";
|
||||
int colWidth = colWidths[i];
|
||||
if(colWidth)
|
||||
finalText += getColTitle(i).leftJustified(colWidth, QChar(' '), true);
|
||||
else
|
||||
finalText += getColTitle(i);
|
||||
}
|
||||
finalText += "\r\n";
|
||||
for(int i = 0; i < rowCount; i++)
|
||||
{
|
||||
QString finalRowText = "";
|
||||
for(int j = 0; j < colCount; j++)
|
||||
{
|
||||
if(j)
|
||||
finalRowText += " ";
|
||||
QString cellContent = getCellContent(i, j);
|
||||
int colWidth = colWidths[j];
|
||||
if(colWidth && j != colCount - 1)
|
||||
finalRowText += cellContent.leftJustified(colWidth, QChar(' '), true);
|
||||
else
|
||||
finalRowText += cellContent;
|
||||
}
|
||||
finalText += finalRowText + "\r\n";
|
||||
}
|
||||
}
|
||||
return finalText;
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyTableSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
colWidths.push_back(getColumnWidth(i) / getCharWidth());
|
||||
Bridge::CopyToClipboard(copyTable(colWidths));
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyTableToLogSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
colWidths.push_back(getColumnWidth(i) / getCharWidth());
|
||||
emit Bridge::getBridge()->addMsgToLog(copyTable(colWidths).toUtf8());
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyTableResizeSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int rowCount = getRowCount();
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
int max = getCellContent(0, i).length();
|
||||
for(int j = 1; j < rowCount; j++)
|
||||
max = std::max(getCellContent(j, i).length(), max);
|
||||
colWidths.push_back(max);
|
||||
}
|
||||
Bridge::CopyToClipboard(copyTable(colWidths));
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyTableResizeToLogSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int rowCount = getRowCount();
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
int max = getCellContent(0, i).length();
|
||||
for(int j = 1; j < rowCount; j++)
|
||||
max = std::max(getCellContent(j, i).length(), max);
|
||||
colWidths.push_back(max);
|
||||
}
|
||||
emit Bridge::getBridge()->addMsgToLog(copyTable(colWidths).toUtf8());
|
||||
}
|
||||
|
||||
void AbstractStdTable::copyEntrySlot()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
if(!action)
|
||||
return;
|
||||
int col = action->objectName().toInt();
|
||||
QString finalText = getCellContent(getInitialSelection(), col);
|
||||
while(finalText.endsWith(" ")) finalText.chop(1);
|
||||
Bridge::CopyToClipboard(finalText);
|
||||
}
|
||||
|
||||
void AbstractStdTable::setupCopyMenu(QMenu* copyMenu)
|
||||
{
|
||||
if(!getColumnCount())
|
||||
return;
|
||||
copyMenu->setIcon(DIcon("copy.png"));
|
||||
//Copy->Whole Line
|
||||
QAction* mCopyLine = new QAction(DIcon("copy_table_line.png"), tr("&Line"), copyMenu);
|
||||
connect(mCopyLine, SIGNAL(triggered()), this, SLOT(copyLineSlot()));
|
||||
copyMenu->addAction(mCopyLine);
|
||||
//Copy->Cropped Table
|
||||
QAction* mCopyTable = new QAction(DIcon("copy_cropped_table.png"), tr("Cropped &Table"), copyMenu);
|
||||
connect(mCopyTable, SIGNAL(triggered()), this, SLOT(copyTableSlot()));
|
||||
copyMenu->addAction(mCopyTable);
|
||||
//Copy->Full Table
|
||||
QAction* mCopyTableResize = new QAction(DIcon("copy_full_table.png"), tr("&Full Table"), copyMenu);
|
||||
connect(mCopyTableResize, SIGNAL(triggered()), this, SLOT(copyTableResizeSlot()));
|
||||
copyMenu->addAction(mCopyTableResize);
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->Whole Line To Log
|
||||
QAction* mCopyLineToLog = new QAction(DIcon("copy_table_line.png"), tr("Line, To Log"), copyMenu);
|
||||
connect(mCopyLineToLog, SIGNAL(triggered()), this, SLOT(copyLineToLogSlot()));
|
||||
copyMenu->addAction(mCopyLineToLog);
|
||||
//Copy->Cropped Table To Log
|
||||
QAction* mCopyTableToLog = new QAction(DIcon("copy_cropped_table.png"), tr("Cropped Table, To Log"), copyMenu);
|
||||
connect(mCopyTableToLog, SIGNAL(triggered()), this, SLOT(copyTableToLogSlot()));
|
||||
copyMenu->addAction(mCopyTableToLog);
|
||||
//Copy->Full Table To Log
|
||||
QAction* mCopyTableResizeToLog = new QAction(DIcon("copy_full_table.png"), tr("Full Table, To Log"), copyMenu);
|
||||
connect(mCopyTableResizeToLog, SIGNAL(triggered()), this, SLOT(copyTableResizeToLogSlot()));
|
||||
copyMenu->addAction(mCopyTableResizeToLog);
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->ColName
|
||||
for(int i = 0; i < getColumnCount(); i++)
|
||||
{
|
||||
if(!getCellContent(getInitialSelection(), i).length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(!title.length()) //skip empty copy titles
|
||||
continue;
|
||||
QAction* mCopyAction = new QAction(DIcon("copy_item.png"), title, copyMenu);
|
||||
mCopyAction->setObjectName(QString::number(i));
|
||||
connect(mCopyAction, SIGNAL(triggered()), this, SLOT(copyEntrySlot()));
|
||||
copyMenu->addAction(mCopyAction);
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::setupCopyMenu(MenuBuilder* copyMenu)
|
||||
{
|
||||
if(!getColumnCount())
|
||||
return;
|
||||
//Copy->Whole Line
|
||||
copyMenu->addAction(makeAction(DIcon("copy_table_line.png"), tr("&Line"), SLOT(copyLineSlot())));
|
||||
//Copy->Cropped Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_cropped_table.png"), tr("Cropped &Table"), SLOT(copyTableSlot())));
|
||||
//Copy->Full Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_full_table.png"), tr("&Full Table"), SLOT(copyTableResizeSlot())));
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->Whole Line To Log
|
||||
copyMenu->addAction(makeAction(DIcon("copy_table_line.png"), tr("Line, To Log"), SLOT(copyLineToLogSlot())));
|
||||
//Copy->Cropped Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_cropped_table.png"), tr("Cropped Table, To Log"), SLOT(copyTableToLogSlot())));
|
||||
//Copy->Full Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_full_table.png"), tr("Full Table, To Log"), SLOT(copyTableResizeToLogSlot())));
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->ColName
|
||||
copyMenu->addBuilder(new MenuBuilder(this, [this](QMenu * menu)
|
||||
{
|
||||
for(int i = 0; i < getColumnCount(); i++)
|
||||
{
|
||||
if(!getCellContent(getInitialSelection(), i).length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(!title.length()) //skip empty copy titles
|
||||
continue;
|
||||
QAction* action = new QAction(DIcon("copy_item.png"), title, menu);
|
||||
action->setObjectName(QString::number(i));
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(copyEntrySlot()));
|
||||
menu->addAction(action);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
void AbstractStdTable::setCopyMenuOnly(bool bSet, bool bDebugOnly)
|
||||
{
|
||||
mCopyMenuOnly = bSet;
|
||||
mCopyMenuDebugOnly = bDebugOnly;
|
||||
}
|
||||
|
||||
void AbstractStdTable::contextMenuRequestedSlot(const QPoint & pos)
|
||||
{
|
||||
if(!mCopyMenuOnly)
|
||||
{
|
||||
emit contextMenuSignal(pos);
|
||||
return;
|
||||
}
|
||||
if(mCopyMenuDebugOnly && !DbgIsDebugging())
|
||||
return;
|
||||
QMenu wMenu(this);
|
||||
QMenu wCopyMenu(tr("&Copy"), this);
|
||||
setupCopyMenu(&wCopyMenu);
|
||||
if(wCopyMenu.actions().length())
|
||||
{
|
||||
wMenu.addSeparator();
|
||||
wMenu.addMenu(&wCopyMenu);
|
||||
wMenu.exec(mapToGlobal(pos));
|
||||
}
|
||||
}
|
||||
|
||||
void AbstractStdTable::headerButtonPressedSlot(int col)
|
||||
{
|
||||
if(!mIsColumnSortingAllowed)
|
||||
return;
|
||||
if(mSort.column != col)
|
||||
{
|
||||
mSort.column = col;
|
||||
mSort.ascending = true;
|
||||
}
|
||||
else
|
||||
mSort.ascending = !mSort.ascending;
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void AbstractStdTable::reloadData()
|
||||
{
|
||||
if(mSort.column != -1) //re-sort if the user wants to sort
|
||||
{
|
||||
sortRows(mSort.column, mSort.ascending);
|
||||
}
|
||||
AbstractTableView::reloadData();
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractTableView.h"
|
||||
|
||||
class AbstractStdTable : public AbstractTableView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit AbstractStdTable(QWidget* parent = 0);
|
||||
QString paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h);
|
||||
void reloadData();
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
void enableMultiSelection(bool enabled);
|
||||
void enableColumnSorting(bool enabled);
|
||||
|
||||
// Selection Management
|
||||
void expandSelectionUpTo(int to);
|
||||
void expandUp();
|
||||
void expandDown();
|
||||
void expandTop();
|
||||
void expandBottom();
|
||||
void setSingleSelection(int index);
|
||||
int getInitialSelection();
|
||||
QList<int> getSelection();
|
||||
void selectStart();
|
||||
void selectEnd();
|
||||
void selectNext();
|
||||
void selectPrevious();
|
||||
void selectAll();
|
||||
bool isSelected(int base, int offset);
|
||||
bool scrollSelect(int offset);
|
||||
|
||||
// Data Management
|
||||
void addColumnAt(int width, QString title, bool isClickable, QString copyTitle = "");
|
||||
void deleteAllColumns() override;
|
||||
|
||||
virtual QString getCellContent(int r, int c) = 0;
|
||||
virtual bool isValidIndex(int r, int c) = 0;
|
||||
virtual void sortRows(int column, bool ascending) = 0;
|
||||
|
||||
//context menu helpers
|
||||
void setupCopyMenu(QMenu* copyMenu);
|
||||
void setupCopyMenu(MenuBuilder* copyMenu);
|
||||
void setCopyMenuOnly(bool bSet, bool bDebugOnly = true);
|
||||
|
||||
signals:
|
||||
void selectionChangedSignal(int index);
|
||||
void keyPressedSignal(QKeyEvent* event);
|
||||
void doubleClickedSignal();
|
||||
void contextMenuSignal(const QPoint & pos);
|
||||
|
||||
public slots:
|
||||
void copyLineSlot();
|
||||
void copyTableSlot();
|
||||
void copyTableResizeSlot();
|
||||
void copyLineToLogSlot();
|
||||
void copyTableToLogSlot();
|
||||
void copyTableResizeToLogSlot();
|
||||
void copyEntrySlot();
|
||||
void contextMenuRequestedSlot(const QPoint & pos);
|
||||
void headerButtonPressedSlot(int col);
|
||||
|
||||
protected:
|
||||
QString copyTable(const std::vector<int> & colWidths);
|
||||
|
||||
struct
|
||||
{
|
||||
int firstSelectedIndex = 0;
|
||||
int fromIndex = 0;
|
||||
int toIndex = 0;
|
||||
} mSelection;
|
||||
|
||||
enum
|
||||
{
|
||||
NoState,
|
||||
MultiRowsSelectionState
|
||||
} mGuiState = NoState;
|
||||
|
||||
bool mIsMultiSelectionAllowed = false;
|
||||
bool mCopyMenuOnly = false;
|
||||
bool mCopyMenuDebugOnly = true;
|
||||
bool mIsColumnSortingAllowed = true;
|
||||
|
||||
std::vector<QString> mCopyTitles;
|
||||
|
||||
struct SortData
|
||||
{
|
||||
int column = -1;
|
||||
bool ascending = true;
|
||||
} mSort;
|
||||
};
|
|
@ -1,414 +1,8 @@
|
|||
#include "StdTable.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
StdTable::StdTable(QWidget* parent) : AbstractTableView(parent)
|
||||
StdTable::StdTable(QWidget* parent) : AbstractStdTable(parent)
|
||||
{
|
||||
SelectionData_t data;
|
||||
memset(&data, 0, sizeof(SelectionData_t));
|
||||
mSelection = data;
|
||||
|
||||
mIsMultiSelectionAllowed = false;
|
||||
mIsColumnSortingAllowed = true;
|
||||
|
||||
mData.clear();
|
||||
mSort.first = -1;
|
||||
|
||||
mGuiState = StdTable::NoState;
|
||||
|
||||
mCopyMenuOnly = false;
|
||||
mCopyMenuDebugOnly = true;
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(Bridge::getBridge(), SIGNAL(repaintTableView()), this, SLOT(reloadData()));
|
||||
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(contextMenuRequestedSlot(QPoint)));
|
||||
connect(this, SIGNAL(headerButtonPressed(int)), this, SLOT(headerButtonPressedSlot(int)));
|
||||
}
|
||||
|
||||
QString StdTable::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h)
|
||||
{
|
||||
if(isSelected(rowBase, rowOffset))
|
||||
painter->fillRect(QRect(x, y, w, h), QBrush(selectionColor));
|
||||
return getCellContent(rowBase + rowOffset, col);
|
||||
}
|
||||
|
||||
void StdTable::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
bool wAccept = true;
|
||||
int y = transY(event->y());
|
||||
|
||||
if(mGuiState == StdTable::MultiRowsSelectionState)
|
||||
{
|
||||
//qDebug() << "State = MultiRowsSelectionState";
|
||||
|
||||
if(y >= 0 && y <= this->getTableHeight())
|
||||
{
|
||||
int wRowIndex = getTableOffset() + getIndexOffsetFromY(y);
|
||||
|
||||
if(wRowIndex < getRowCount())
|
||||
{
|
||||
if(mIsMultiSelectionAllowed)
|
||||
expandSelectionUpTo(wRowIndex);
|
||||
else
|
||||
setSingleSelection(wRowIndex);
|
||||
|
||||
updateViewport();
|
||||
|
||||
wAccept = false;
|
||||
}
|
||||
}
|
||||
else if(y < 0)
|
||||
{
|
||||
verticalScrollBar()->triggerAction(QAbstractSlider::SliderSingleStepSub);
|
||||
}
|
||||
else if(y > getTableHeight())
|
||||
{
|
||||
verticalScrollBar()->triggerAction(QAbstractSlider::SliderSingleStepAdd);
|
||||
}
|
||||
}
|
||||
|
||||
if(wAccept)
|
||||
AbstractTableView::mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void StdTable::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
bool wAccept = false;
|
||||
|
||||
if(((event->buttons() & Qt::LeftButton) != 0) && ((event->buttons() & Qt::RightButton) == 0))
|
||||
{
|
||||
if(getGuiState() == AbstractTableView::NoState)
|
||||
{
|
||||
if(event->y() > getHeaderHeight())
|
||||
{
|
||||
int wRowIndex = getTableOffset() + getIndexOffsetFromY(transY(event->y()));
|
||||
|
||||
if(wRowIndex < getRowCount())
|
||||
{
|
||||
if(mIsMultiSelectionAllowed && (event->modifiers() & Qt::ShiftModifier))
|
||||
expandSelectionUpTo(wRowIndex);
|
||||
else
|
||||
setSingleSelection(wRowIndex);
|
||||
|
||||
mGuiState = StdTable::MultiRowsSelectionState;
|
||||
|
||||
updateViewport();
|
||||
|
||||
wAccept = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!wAccept)
|
||||
AbstractTableView::mousePressEvent(event);
|
||||
}
|
||||
|
||||
void StdTable::mouseDoubleClickEvent(QMouseEvent* event)
|
||||
{
|
||||
if(event->y() > getHeaderHeight() && event->button() == Qt::LeftButton)
|
||||
emit doubleClickedSignal();
|
||||
AbstractTableView::mouseDoubleClickEvent(event);
|
||||
}
|
||||
|
||||
void StdTable::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
bool wAccept = true;
|
||||
|
||||
if((event->buttons() & Qt::LeftButton) == 0)
|
||||
{
|
||||
if(mGuiState == StdTable::MultiRowsSelectionState)
|
||||
{
|
||||
mGuiState = StdTable::NoState;
|
||||
|
||||
updateViewport();
|
||||
|
||||
wAccept = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(wAccept)
|
||||
AbstractTableView::mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void StdTable::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
emit keyPressedSignal(event);
|
||||
int key = event->key();
|
||||
Qt::KeyboardModifiers modifiers = event->modifiers();
|
||||
|
||||
if(key == Qt::Key_Up ||
|
||||
key == Qt::Key_Down ||
|
||||
key == Qt::Key_Home ||
|
||||
key == Qt::Key_End ||
|
||||
key == Qt::Key_A)
|
||||
{
|
||||
dsint wBotIndex = getTableOffset();
|
||||
dsint wTopIndex = wBotIndex + getNbrOfLineToPrint() - 1;
|
||||
|
||||
switch(key)
|
||||
{
|
||||
case Qt::Key_Up:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+Up -> expand selection upwards
|
||||
{
|
||||
expandUp();
|
||||
}
|
||||
else //Up -> select previous
|
||||
{
|
||||
selectPrevious();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Down:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+Down -> expand selection downwards
|
||||
{
|
||||
expandDown();
|
||||
}
|
||||
else //Down -> select next
|
||||
{
|
||||
selectNext();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Home:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+Home -> expand selection to top
|
||||
{
|
||||
expandTop();
|
||||
}
|
||||
else if(modifiers == Qt::NoModifier) //Home -> select first line
|
||||
{
|
||||
selectStart();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_End:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ShiftModifier) //Shift+End -> expand selection to bottom
|
||||
{
|
||||
expandBottom();
|
||||
}
|
||||
else if(modifiers == Qt::NoModifier) //End -> select last line
|
||||
{
|
||||
selectEnd();
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_A:
|
||||
if(mIsMultiSelectionAllowed && modifiers == Qt::ControlModifier) //Ctrl+A -> select all
|
||||
{
|
||||
selectAll();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(getInitialSelection() < wBotIndex)
|
||||
{
|
||||
setTableOffset(getInitialSelection());
|
||||
}
|
||||
else if(getInitialSelection() >= wTopIndex)
|
||||
{
|
||||
setTableOffset(getInitialSelection() - getNbrOfLineToPrint() + 2);
|
||||
}
|
||||
|
||||
updateViewport();
|
||||
}
|
||||
else
|
||||
{
|
||||
AbstractTableView::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::enableMultiSelection(bool enabled)
|
||||
{
|
||||
mIsMultiSelectionAllowed = enabled;
|
||||
}
|
||||
|
||||
void StdTable::enableColumnSorting(bool enabled)
|
||||
{
|
||||
mIsColumnSortingAllowed = enabled;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Selection Management
|
||||
************************************************************************************/
|
||||
void StdTable::expandSelectionUpTo(int to)
|
||||
{
|
||||
if(to < mSelection.firstSelectedIndex)
|
||||
{
|
||||
mSelection.fromIndex = to;
|
||||
mSelection.toIndex = mSelection.firstSelectedIndex;
|
||||
emit selectionChangedSignal(to);
|
||||
}
|
||||
else if(to > mSelection.firstSelectedIndex)
|
||||
{
|
||||
mSelection.fromIndex = mSelection.firstSelectedIndex;
|
||||
mSelection.toIndex = to;
|
||||
emit selectionChangedSignal(to);
|
||||
}
|
||||
else if(to == mSelection.firstSelectedIndex)
|
||||
{
|
||||
setSingleSelection(to);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::expandUp()
|
||||
{
|
||||
int wRowIndex = mSelection.firstSelectedIndex - 1;
|
||||
if(wRowIndex >= 0)
|
||||
{
|
||||
if(wRowIndex < mSelection.fromIndex)
|
||||
{
|
||||
mSelection.fromIndex = wRowIndex;
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
mSelection.toIndex = wRowIndex;
|
||||
}
|
||||
|
||||
emit selectionChangedSignal(wRowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::expandDown()
|
||||
{
|
||||
int wRowIndex = mSelection.firstSelectedIndex + 1;
|
||||
int endIndex = getRowCount() - 1;
|
||||
if(wRowIndex <= endIndex)
|
||||
{
|
||||
|
||||
if(wRowIndex > mSelection.toIndex)
|
||||
{
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
mSelection.toIndex = wRowIndex;
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
mSelection.fromIndex = wRowIndex;
|
||||
mSelection.firstSelectedIndex = wRowIndex;
|
||||
}
|
||||
|
||||
|
||||
emit selectionChangedSignal(wRowIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::expandTop()
|
||||
{
|
||||
if(getRowCount() > 0)
|
||||
{
|
||||
expandSelectionUpTo(0);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::expandBottom()
|
||||
{
|
||||
int endIndex = getRowCount() - 1;
|
||||
if(endIndex >= 0)
|
||||
{
|
||||
expandSelectionUpTo(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::setSingleSelection(int index)
|
||||
{
|
||||
mSelection.firstSelectedIndex = index;
|
||||
mSelection.fromIndex = index;
|
||||
mSelection.toIndex = index;
|
||||
emit selectionChangedSignal(index);
|
||||
}
|
||||
|
||||
int StdTable::getInitialSelection()
|
||||
{
|
||||
return mSelection.firstSelectedIndex;
|
||||
}
|
||||
|
||||
QList<int> StdTable::getSelection()
|
||||
{
|
||||
QList<int> selection;
|
||||
selection.reserve(mSelection.toIndex - mSelection.fromIndex);
|
||||
for(int i = mSelection.fromIndex; i <= mSelection.toIndex; i++)
|
||||
{
|
||||
selection.append(i);
|
||||
}
|
||||
return selection;
|
||||
}
|
||||
|
||||
void StdTable::selectStart()
|
||||
{
|
||||
if(getRowCount() > 0)
|
||||
{
|
||||
setSingleSelection(0);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::selectEnd()
|
||||
{
|
||||
int endIndex = getRowCount() - 1;
|
||||
if(endIndex >= 0)
|
||||
{
|
||||
setSingleSelection(endIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::selectNext()
|
||||
{
|
||||
int wNext = getInitialSelection() + 1;
|
||||
|
||||
// Bounding
|
||||
wNext = wNext > getRowCount() - 1 ? getRowCount() - 1 : wNext;
|
||||
wNext = wNext < 0 ? 0 : wNext;
|
||||
|
||||
setSingleSelection(wNext);
|
||||
}
|
||||
|
||||
void StdTable::selectPrevious()
|
||||
{
|
||||
int wNext = getInitialSelection() - 1;
|
||||
|
||||
// Bounding
|
||||
wNext = wNext > getRowCount() - 1 ? getRowCount() - 1 : wNext;
|
||||
wNext = wNext < 0 ? 0 : wNext;
|
||||
|
||||
setSingleSelection(wNext);
|
||||
}
|
||||
|
||||
void StdTable::selectAll()
|
||||
{
|
||||
int index = 0;
|
||||
int indexEnd = getRowCount() - 1;
|
||||
|
||||
mSelection.firstSelectedIndex = index;
|
||||
mSelection.fromIndex = index;
|
||||
mSelection.toIndex = indexEnd;
|
||||
|
||||
emit selectionChangedSignal(index);
|
||||
}
|
||||
|
||||
bool StdTable::isSelected(int base, int offset)
|
||||
{
|
||||
int wIndex = base + offset;
|
||||
|
||||
if(wIndex >= mSelection.fromIndex && wIndex <= mSelection.toIndex)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool StdTable::scrollSelect(int offset)
|
||||
{
|
||||
if(!isValidIndex(offset, 0))
|
||||
return false;
|
||||
|
||||
int rangefrom = getTableOffset();
|
||||
int rangeto = rangefrom + getViewableRowsCount() - 1;
|
||||
if(offset < rangefrom) //offset lays before the current view
|
||||
setTableOffset(offset);
|
||||
else if(offset > (rangeto - 1)) //offset lays after the current view
|
||||
setTableOffset(offset - getViewableRowsCount() + 2);
|
||||
setSingleSelection(offset);
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
|
@ -520,303 +114,12 @@ bool StdTable::isValidIndex(int r, int c)
|
|||
return c < int(mData.at(r).size());
|
||||
}
|
||||
|
||||
void StdTable::copyLineSlot()
|
||||
void StdTable::sortRows(int column, bool ascending)
|
||||
{
|
||||
int colCount = getColumnCount();
|
||||
QString finalText = "";
|
||||
if(colCount == 1)
|
||||
finalText = getCellContent(getInitialSelection(), 0);
|
||||
else
|
||||
auto sortFn = mColumnSortFunctions.at(column);
|
||||
std::stable_sort(mData.begin(), mData.end(), [column, ascending, &sortFn](const std::vector<CellData> & a, const std::vector<CellData> & b)
|
||||
{
|
||||
for(int selected : getSelection())
|
||||
{
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
QString cellContent = getCellContent(selected, i);
|
||||
if(!cellContent.length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(title.length())
|
||||
finalText += title + "=";
|
||||
finalText += cellContent.trimmed();;
|
||||
finalText += "\r\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
Bridge::CopyToClipboard(finalText);
|
||||
}
|
||||
|
||||
void StdTable::copyLineToLogSlot()
|
||||
{
|
||||
int colCount = getColumnCount();
|
||||
int selected = getInitialSelection();
|
||||
QString finalText = "";
|
||||
if(colCount == 1)
|
||||
finalText = getCellContent(selected, 0);
|
||||
else
|
||||
{
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
QString cellContent = getCellContent(selected, i);
|
||||
if(!cellContent.length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(title.length())
|
||||
finalText += title + "=";
|
||||
finalText += cellContent.trimmed();;
|
||||
finalText += "\r\n";
|
||||
}
|
||||
}
|
||||
emit Bridge::getBridge()->addMsgToLog(finalText.toUtf8());
|
||||
}
|
||||
|
||||
QString StdTable::copyTable(const std::vector<int> & colWidths)
|
||||
{
|
||||
int colCount = getColumnCount();
|
||||
int rowCount = getRowCount();
|
||||
QString finalText = "";
|
||||
if(colCount == 1)
|
||||
{
|
||||
for(int i = 0; i < rowCount; i++)
|
||||
{
|
||||
QString cellContent = getCellContent(i, 0);
|
||||
if(!cellContent.length()) //skip empty cells
|
||||
continue;
|
||||
finalText += cellContent + "\r\n";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//std::vector<int> colWidths;
|
||||
//for(int i = 0; i < colCount; i++)
|
||||
// colWidths.push_back(getMaxColumnLength(i));
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
if(i)
|
||||
finalText += " ";
|
||||
int colWidth = colWidths[i];
|
||||
if(colWidth)
|
||||
finalText += getColTitle(i).leftJustified(colWidth, QChar(' '), true);
|
||||
else
|
||||
finalText += getColTitle(i);
|
||||
}
|
||||
finalText += "\r\n";
|
||||
for(int i = 0; i < rowCount; i++)
|
||||
{
|
||||
QString finalRowText = "";
|
||||
for(int j = 0; j < colCount; j++)
|
||||
{
|
||||
if(j)
|
||||
finalRowText += " ";
|
||||
QString cellContent = getCellContent(i, j);
|
||||
int colWidth = colWidths[j];
|
||||
if(colWidth && j != colCount - 1)
|
||||
finalRowText += cellContent.leftJustified(colWidth, QChar(' '), true);
|
||||
else
|
||||
finalRowText += cellContent;
|
||||
}
|
||||
finalText += finalRowText + "\r\n";
|
||||
}
|
||||
}
|
||||
return finalText;
|
||||
}
|
||||
|
||||
void StdTable::copyTableSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
colWidths.push_back(getColumnWidth(i) / getCharWidth());
|
||||
Bridge::CopyToClipboard(copyTable(colWidths));
|
||||
}
|
||||
|
||||
void StdTable::copyTableToLogSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
colWidths.push_back(getColumnWidth(i) / getCharWidth());
|
||||
emit Bridge::getBridge()->addMsgToLog(copyTable(colWidths).toUtf8());
|
||||
}
|
||||
|
||||
void StdTable::copyTableResizeSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int rowCount = getRowCount();
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
int max = getCellContent(0, i).length();
|
||||
for(int j = 1; j < rowCount; j++)
|
||||
max = std::max(getCellContent(j, i).length(), max);
|
||||
colWidths.push_back(max);
|
||||
}
|
||||
Bridge::CopyToClipboard(copyTable(colWidths));
|
||||
}
|
||||
|
||||
void StdTable::copyTableResizeToLogSlot()
|
||||
{
|
||||
std::vector<int> colWidths;
|
||||
int rowCount = getRowCount();
|
||||
int colCount = getColumnCount();
|
||||
for(int i = 0; i < colCount; i++)
|
||||
{
|
||||
int max = getCellContent(0, i).length();
|
||||
for(int j = 1; j < rowCount; j++)
|
||||
max = std::max(getCellContent(j, i).length(), max);
|
||||
colWidths.push_back(max);
|
||||
}
|
||||
emit Bridge::getBridge()->addMsgToLog(copyTable(colWidths).toUtf8());
|
||||
}
|
||||
|
||||
void StdTable::copyEntrySlot()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
if(!action)
|
||||
return;
|
||||
int col = action->objectName().toInt();
|
||||
QString finalText = getCellContent(getInitialSelection(), col);
|
||||
while(finalText.endsWith(" ")) finalText.chop(1);
|
||||
Bridge::CopyToClipboard(finalText);
|
||||
}
|
||||
|
||||
void StdTable::setupCopyMenu(QMenu* copyMenu)
|
||||
{
|
||||
if(!getColumnCount())
|
||||
return;
|
||||
copyMenu->setIcon(DIcon("copy.png"));
|
||||
//Copy->Whole Line
|
||||
QAction* mCopyLine = new QAction(DIcon("copy_table_line.png"), tr("&Line"), copyMenu);
|
||||
connect(mCopyLine, SIGNAL(triggered()), this, SLOT(copyLineSlot()));
|
||||
copyMenu->addAction(mCopyLine);
|
||||
//Copy->Cropped Table
|
||||
QAction* mCopyTable = new QAction(DIcon("copy_cropped_table.png"), tr("Cropped &Table"), copyMenu);
|
||||
connect(mCopyTable, SIGNAL(triggered()), this, SLOT(copyTableSlot()));
|
||||
copyMenu->addAction(mCopyTable);
|
||||
//Copy->Full Table
|
||||
QAction* mCopyTableResize = new QAction(DIcon("copy_full_table.png"), tr("&Full Table"), copyMenu);
|
||||
connect(mCopyTableResize, SIGNAL(triggered()), this, SLOT(copyTableResizeSlot()));
|
||||
copyMenu->addAction(mCopyTableResize);
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->Whole Line To Log
|
||||
QAction* mCopyLineToLog = new QAction(DIcon("copy_table_line.png"), tr("Line, To Log"), copyMenu);
|
||||
connect(mCopyLineToLog, SIGNAL(triggered()), this, SLOT(copyLineToLogSlot()));
|
||||
copyMenu->addAction(mCopyLineToLog);
|
||||
//Copy->Cropped Table To Log
|
||||
QAction* mCopyTableToLog = new QAction(DIcon("copy_cropped_table.png"), tr("Cropped Table, To Log"), copyMenu);
|
||||
connect(mCopyTableToLog, SIGNAL(triggered()), this, SLOT(copyTableToLogSlot()));
|
||||
copyMenu->addAction(mCopyTableToLog);
|
||||
//Copy->Full Table To Log
|
||||
QAction* mCopyTableResizeToLog = new QAction(DIcon("copy_full_table.png"), tr("Full Table, To Log"), copyMenu);
|
||||
connect(mCopyTableResizeToLog, SIGNAL(triggered()), this, SLOT(copyTableResizeToLogSlot()));
|
||||
copyMenu->addAction(mCopyTableResizeToLog);
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->ColName
|
||||
for(int i = 0; i < getColumnCount(); i++)
|
||||
{
|
||||
if(!getCellContent(getInitialSelection(), i).length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(!title.length()) //skip empty copy titles
|
||||
continue;
|
||||
QAction* mCopyAction = new QAction(DIcon("copy_item.png"), title, copyMenu);
|
||||
mCopyAction->setObjectName(QString::number(i));
|
||||
connect(mCopyAction, SIGNAL(triggered()), this, SLOT(copyEntrySlot()));
|
||||
copyMenu->addAction(mCopyAction);
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::setupCopyMenu(MenuBuilder* copyMenu)
|
||||
{
|
||||
if(!getColumnCount())
|
||||
return;
|
||||
//Copy->Whole Line
|
||||
copyMenu->addAction(makeAction(DIcon("copy_table_line.png"), tr("&Line"), SLOT(copyLineSlot())));
|
||||
//Copy->Cropped Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_cropped_table.png"), tr("Cropped &Table"), SLOT(copyTableSlot())));
|
||||
//Copy->Full Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_full_table.png"), tr("&Full Table"), SLOT(copyTableResizeSlot())));
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->Whole Line To Log
|
||||
copyMenu->addAction(makeAction(DIcon("copy_table_line.png"), tr("Line, To Log"), SLOT(copyLineToLogSlot())));
|
||||
//Copy->Cropped Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_cropped_table.png"), tr("Cropped Table, To Log"), SLOT(copyTableToLogSlot())));
|
||||
//Copy->Full Table
|
||||
copyMenu->addAction(makeAction(DIcon("copy_full_table.png"), tr("Full Table, To Log"), SLOT(copyTableResizeToLogSlot())));
|
||||
//Copy->Separator
|
||||
copyMenu->addSeparator();
|
||||
//Copy->ColName
|
||||
copyMenu->addBuilder(new MenuBuilder(this, [this](QMenu * menu)
|
||||
{
|
||||
for(int i = 0; i < getColumnCount(); i++)
|
||||
{
|
||||
if(!getCellContent(getInitialSelection(), i).length()) //skip empty cells
|
||||
continue;
|
||||
QString title = mCopyTitles.at(i);
|
||||
if(!title.length()) //skip empty copy titles
|
||||
continue;
|
||||
QAction* action = new QAction(DIcon("copy_item.png"), title, menu);
|
||||
action->setObjectName(QString::number(i));
|
||||
connect(action, SIGNAL(triggered()), this, SLOT(copyEntrySlot()));
|
||||
menu->addAction(action);
|
||||
}
|
||||
return true;
|
||||
}));
|
||||
}
|
||||
|
||||
void StdTable::setCopyMenuOnly(bool bSet, bool bDebugOnly)
|
||||
{
|
||||
mCopyMenuOnly = bSet;
|
||||
mCopyMenuDebugOnly = bDebugOnly;
|
||||
}
|
||||
|
||||
void StdTable::contextMenuRequestedSlot(const QPoint & pos)
|
||||
{
|
||||
if(!mCopyMenuOnly)
|
||||
{
|
||||
emit contextMenuSignal(pos);
|
||||
return;
|
||||
}
|
||||
if(mCopyMenuDebugOnly && !DbgIsDebugging())
|
||||
return;
|
||||
QMenu wMenu(this);
|
||||
QMenu wCopyMenu(tr("&Copy"), this);
|
||||
setupCopyMenu(&wCopyMenu);
|
||||
if(wCopyMenu.actions().length())
|
||||
{
|
||||
wMenu.addSeparator();
|
||||
wMenu.addMenu(&wCopyMenu);
|
||||
wMenu.exec(mapToGlobal(pos));
|
||||
}
|
||||
}
|
||||
|
||||
void StdTable::headerButtonPressedSlot(int col)
|
||||
{
|
||||
if(!mIsColumnSortingAllowed)
|
||||
return;
|
||||
if(mSort.first != col) //first = column to sort
|
||||
{
|
||||
mSort.first = col;
|
||||
mSort.second = false; //second = ascending/descending
|
||||
}
|
||||
else
|
||||
mSort.second = !mSort.second;
|
||||
reloadData();
|
||||
}
|
||||
|
||||
void StdTable::reloadData()
|
||||
{
|
||||
if(mSort.first != -1) //re-sort if the user wants to sort
|
||||
{
|
||||
auto sortFn = mColumnSortFunctions.at(mSort.first);
|
||||
std::stable_sort(mData.begin(), mData.end(), [this, &sortFn](const std::vector<CellData> & a, const std::vector<CellData> & b)
|
||||
{
|
||||
auto less = sortFn(a.at(mSort.first).text, b.at(mSort.first).text);
|
||||
return mSort.second ? !less : less;
|
||||
});
|
||||
}
|
||||
AbstractTableView::reloadData();
|
||||
auto less = sortFn(a.at(column).text, b.at(column).text);
|
||||
return ascending ? less : !less;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,41 +1,13 @@
|
|||
#ifndef STDTABLE_H
|
||||
#define STDTABLE_H
|
||||
|
||||
#include "AbstractTableView.h"
|
||||
#include "AbstractStdTable.h"
|
||||
|
||||
class StdTable : public AbstractTableView
|
||||
class StdTable : public AbstractStdTable
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit StdTable(QWidget* parent = 0);
|
||||
QString paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h);
|
||||
void reloadData();
|
||||
|
||||
void mouseMoveEvent(QMouseEvent* event) override;
|
||||
void mousePressEvent(QMouseEvent* event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent* event) override;
|
||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||
void keyPressEvent(QKeyEvent* event) override;
|
||||
|
||||
void enableMultiSelection(bool enabled);
|
||||
void enableColumnSorting(bool enabled);
|
||||
|
||||
// Selection Management
|
||||
void expandSelectionUpTo(int to);
|
||||
void expandUp();
|
||||
void expandDown();
|
||||
void expandTop();
|
||||
void expandBottom();
|
||||
void setSingleSelection(int index);
|
||||
int getInitialSelection();
|
||||
QList<int> getSelection();
|
||||
void selectStart();
|
||||
void selectEnd();
|
||||
void selectNext();
|
||||
void selectPrevious();
|
||||
void selectAll();
|
||||
bool isSelected(int base, int offset);
|
||||
bool scrollSelect(int offset);
|
||||
|
||||
// Sorting
|
||||
struct SortBy
|
||||
|
@ -51,36 +23,13 @@ public:
|
|||
void deleteAllColumns() override;
|
||||
void setRowCount(dsint count) override;
|
||||
void setCellContent(int r, int c, QString s);
|
||||
QString getCellContent(int r, int c);
|
||||
QString getCellContent(int r, int c) override;
|
||||
void setCellUserdata(int r, int c, duint userdata);
|
||||
duint getCellUserdata(int r, int c);
|
||||
bool isValidIndex(int r, int c);
|
||||
|
||||
//context menu helpers
|
||||
void setupCopyMenu(QMenu* copyMenu);
|
||||
void setupCopyMenu(MenuBuilder* copyMenu);
|
||||
void setCopyMenuOnly(bool bSet, bool bDebugOnly = true);
|
||||
|
||||
signals:
|
||||
void selectionChangedSignal(int index);
|
||||
void keyPressedSignal(QKeyEvent* event);
|
||||
void doubleClickedSignal();
|
||||
void contextMenuSignal(const QPoint & pos);
|
||||
|
||||
public slots:
|
||||
void copyLineSlot();
|
||||
void copyTableSlot();
|
||||
void copyTableResizeSlot();
|
||||
void copyLineToLogSlot();
|
||||
void copyTableToLogSlot();
|
||||
void copyTableResizeToLogSlot();
|
||||
void copyEntrySlot();
|
||||
void contextMenuRequestedSlot(const QPoint & pos);
|
||||
void headerButtonPressedSlot(int col);
|
||||
bool isValidIndex(int r, int c) override;
|
||||
void sortRows(int column, bool ascending) override;
|
||||
|
||||
protected:
|
||||
QString copyTable(const std::vector<int> & colWidths);
|
||||
|
||||
struct CellData
|
||||
{
|
||||
QString text;
|
||||
|
@ -110,28 +59,8 @@ protected:
|
|||
SortBy::t mSortFn;
|
||||
};
|
||||
|
||||
enum GuiState_t {NoState, MultiRowsSelectionState};
|
||||
|
||||
typedef struct _SelectionData_t
|
||||
{
|
||||
int firstSelectedIndex;
|
||||
int fromIndex;
|
||||
int toIndex;
|
||||
} SelectionData_t;
|
||||
|
||||
GuiState_t mGuiState;
|
||||
|
||||
SelectionData_t mSelection;
|
||||
|
||||
bool mIsMultiSelectionAllowed;
|
||||
bool mCopyMenuOnly;
|
||||
bool mCopyMenuDebugOnly;
|
||||
bool mIsColumnSortingAllowed;
|
||||
|
||||
std::vector<std::vector<CellData>> mData; //listof(row) where row = (listof(col) where col = string)
|
||||
std::vector<SortBy::t> mColumnSortFunctions;
|
||||
std::vector<QString> mCopyTitles;
|
||||
QPair<int, bool> mSort;
|
||||
};
|
||||
|
||||
#endif // STDTABLE_H
|
||||
|
|
|
@ -124,32 +124,26 @@ void BreakpointsView::updateColors()
|
|||
updateBreakpointsSlot();
|
||||
}
|
||||
|
||||
void BreakpointsView::reloadData()
|
||||
void BreakpointsView::sortRows(int column, bool ascending)
|
||||
{
|
||||
if(mSort.first != -1) //re-sort if the user wants to sort
|
||||
std::stable_sort(mData.begin(), mData.end(), [this, column, ascending](const std::vector<CellData> & a, const std::vector<CellData> & b)
|
||||
{
|
||||
auto col = mSort.first;
|
||||
auto greater = mSort.second;
|
||||
std::stable_sort(mData.begin(), mData.end(), [this, col, greater](const std::vector<CellData> & a, const std::vector<CellData> & b)
|
||||
//this function sorts on header type first and then on column content
|
||||
auto aBp = &mBps.at(a.at(ColAddr).userdata), bBp = &mBps.at(b.at(ColAddr).userdata);
|
||||
auto aType = aBp->type, bType = bBp->type;
|
||||
auto aHeader = aBp->addr || aBp->active, bHeader = bBp->addr || bBp->active;
|
||||
struct Hax
|
||||
{
|
||||
//this function sorts on header type first and then on column content
|
||||
auto aBp = &mBps.at(a.at(ColAddr).userdata), bBp = &mBps.at(b.at(ColAddr).userdata);
|
||||
auto aType = aBp->type, bType = bBp->type;
|
||||
auto aHeader = aBp->addr || aBp->active, bHeader = bBp->addr || bBp->active;
|
||||
struct Hax
|
||||
const bool & greater;
|
||||
const QString & s;
|
||||
Hax(const bool & greater, const QString & s) : greater(greater), s(s) { }
|
||||
bool operator<(const Hax & b)
|
||||
{
|
||||
const bool & greater;
|
||||
const QString & s;
|
||||
Hax(const bool & greater, const QString & s) : greater(greater), s(s) { }
|
||||
bool operator<(const Hax & b)
|
||||
{
|
||||
return greater ? s > b.s : s < b.s;
|
||||
}
|
||||
} aHax(greater, a.at(col).text), bHax(greater, b.at(col).text);
|
||||
return std::tie(aType, aHeader, aHax) < std::tie(bType, bHeader, bHax);
|
||||
});
|
||||
}
|
||||
AbstractTableView::reloadData();
|
||||
return greater ? s > b.s : s < b.s;
|
||||
}
|
||||
} aHax(!ascending, a.at(column).text), bHax(!ascending, b.at(column).text);
|
||||
return std::tie(aType, aHeader, aHax) < std::tie(bType, bHeader, bHax);
|
||||
});
|
||||
}
|
||||
|
||||
QString BreakpointsView::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h)
|
||||
|
|
|
@ -17,7 +17,7 @@ public:
|
|||
protected:
|
||||
void setupContextMenu();
|
||||
void updateColors() override;
|
||||
void reloadData() override;
|
||||
void sortRows(int column, bool ascending) override;
|
||||
QString paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h) override;
|
||||
|
||||
private slots:
|
||||
|
|
|
@ -185,7 +185,8 @@ SOURCES += \
|
|||
Src/Tracer/TraceBrowser.cpp \
|
||||
Src/Tracer/TraceFileReader.cpp \
|
||||
Src/Tracer/TraceFileSearch.cpp \
|
||||
Src/Gui/MultiItemsSelectWindow.cpp
|
||||
Src/Gui/MultiItemsSelectWindow.cpp \
|
||||
Src/BasicView/AbstractStdTable.cpp
|
||||
|
||||
|
||||
HEADERS += \
|
||||
|
@ -306,7 +307,8 @@ HEADERS += \
|
|||
Src/Tracer/TraceFileReader.h \
|
||||
Src/Tracer/TraceFileReaderInternal.h \
|
||||
Src/Tracer/TraceFileSearch.h \
|
||||
Src/Gui/MultiItemsSelectWindow.h
|
||||
Src/Gui/MultiItemsSelectWindow.h \
|
||||
Src/BasicView/AbstractStdTable.h
|
||||
|
||||
|
||||
FORMS += \
|
||||
|
|
|
@ -224,7 +224,8 @@ SOURCES += \
|
|||
gui/Src/Tracer/TraceBrowser.cpp \
|
||||
gui/Src/Tracer/TraceFileReader.cpp \
|
||||
gui/Src/Tracer/TraceFileSearch.cpp \
|
||||
gui/Src/Gui/MultiItemsSelectWindow.cpp
|
||||
gui/Src/Gui/MultiItemsSelectWindow.cpp \
|
||||
gui/Src/BasicView/AbstractStdTable.cpp
|
||||
|
||||
HEADERS += \
|
||||
gui/Src/Exports.h \
|
||||
|
@ -460,7 +461,8 @@ HEADERS += \
|
|||
gui/Src/Tracer/TraceFileReader.h \
|
||||
gui/Src/Tracer/TraceFileReaderInternal.h \
|
||||
gui/Src/Tracer/TraceFileSearch.h \
|
||||
gui/Src/Gui/MultiItemsSelectWindow.h
|
||||
gui/Src/Gui/MultiItemsSelectWindow.h \
|
||||
gui/Src/BasicView/AbstractStdTable.h
|
||||
|
||||
FORMS += \
|
||||
gui/Src/Gui/AppearanceDialog.ui \
|
||||
|
|
Loading…
Reference in New Issue