/* Copyright (c) 2008-2019 Jan W. Krieger () This software is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License (LGPL) as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License (LGPL) for more details. You should have received a copy of the GNU Lesser General Public License (LGPL) along with this program. If not, see . */ #include "jkqtplottergui/jkqtpenhancedtableview.h" #include #include #include #include #include #include #include #include #include #include #include #include "jkqtplottertools/jkqtptools.h" #include "jkqtplottertools/jkqtpenhancedpainter.h" JKQTPEnhancedTableView::JKQTPEnhancedTableView(QWidget *parent): QTableView(parent) { setContextMenuPolicy(Qt::ActionsContextMenu); QAction* act; act=new QAction(QIcon(":/JKQTPlotter/jkqtp_copy16.png"), tr("Copy Selection to Clipboard (for Excel ...)"), this); connect(act, SIGNAL(triggered()), this, SLOT(copySelectionToExcel())); addAction(act); act=new QAction(QIcon(":/JKQTPlotter/jkqtp_copy16_nohead.png"), tr("Copy Selection to clipboard (for Excel ...) without header row/column"), this); connect(act, SIGNAL(triggered()), this, SLOT(copySelectionToExcelNoHead())); addAction(act); act=new QAction(QIcon(":/JKQTPlotter/jkqtp_copy16.png"), tr("Copy Selection to Clipboard (as CSV)"), this); connect(act, SIGNAL(triggered()), this, SLOT(copySelectionToCSV())); addAction(act); act=new QAction(QIcon(":/JKQTPlotter/jkqtp_copy16_nohead.png"), tr("Copy Selection to clipboard (as CSV ...) without header row/column"), this); connect(act, SIGNAL(triggered()), this, SLOT(copySelectionToCSVNoHead())); addAction(act); act=new QAction(QIcon(":/JKQTPlotter/jkqtp_printtable.png"), tr("Print Table"), this); connect(act, SIGNAL(triggered()), this, SLOT(print())); addAction(act); printAction=act; } JKQTPEnhancedTableView::~JKQTPEnhancedTableView() = default; QString JKQTPEnhancedTableView::toHtml(int borderWidth, bool /*non_breaking*/, int fontSizePt) const { if (!model()) return ""; QString fsstyle=""; if (fontSizePt>0) { fsstyle=QString(" font-size: %1pt;").arg(fontSizePt); } QString html=QString("").arg(borderWidth); for (int row=-1; rowrowCount(); row++) { html+=""; if (row==-1) { for (int col=-1; colcolumnCount(); col++) { html+=QString(""; } } else { for (int col=-1; colcolumnCount(); col++) { if (col==-1) { html+=QString(""; } else { QModelIndex index=model()->index(row, col); QVariant check=index.data(Qt::CheckStateRole); QBrush back=index.data(Qt::BackgroundRole).value(); QString style=fsstyle+"white-space: nowrap; "; //qDebug()<<"r="<").arg(fsstyle); else html+=QString(""; } } } html+=""; } html+="
").arg(fsstyle); if (col>=0) { html+=model()->headerData(col, Qt::Horizontal).toString(); } html+="").arg(fsstyle); html+=model()->headerData(row, Qt::Vertical).toString(); html+="").arg(style); if (check.isValid()) { if (check.toInt()!=0) { html+= QString("|×|  "); } else { html+= QString("| |  "); } } html+=index.data().toString(); html+="
"; return html; } void JKQTPEnhancedTableView::copySelectionToExcel(int copyrole, bool storeHead) { if (!model()) return; if (!selectionModel()) return; QModelIndexList sel=selectionModel()->selectedIndexes(); QLocale loc=QLocale::system(); loc.setNumberOptions(QLocale::OmitGroupSeparator); if (sel.size()==1) { QVariant vdata=sel[0].data(copyrole); QString txt=""; switch (vdata.type()) { case QVariant::Int: case QVariant::LongLong: case QVariant::UInt: case QVariant::ULongLong: case QVariant::Bool: txt=vdata.toString(); break; case QVariant::Double: txt=loc.toString(vdata.toDouble()); break; case QVariant::PointF: txt=loc.toString(vdata.toPointF().x()); break; default: txt=QString("\"%1\"").arg(vdata.toString().replace('"', "''").replace('\n', "\\n ").replace('\r', "\\r ").replace('\t', " ")); break; } QApplication::clipboard()->setText(txt); } else { QSet rows, cols; int colmin=0; int rowmin=0; for (int i=0; i rowlist=QList::fromSet(rows); qSort(rowlist.begin(), rowlist.end()); QList collist=QList::fromSet(cols); qSort(collist.begin(), collist.end()); int rowcnt=rowlist.size(); int colcnt=collist.size(); QList data; // header row: // // | | | ... QStringList hrow; if (storeHead) { hrow.append(""); // empty header for first column (vertical headers!) for (int c=0; cheaderData(collist[c], Qt::Horizontal).toString().replace('"', "''").replace('\n', "\\n ").replace('\r', "\\r ").replace('\t', " "))); } data.append(hrow); } // now add dta rows: // // <~~~~~~~~~ colcnt times ~~~~~~~~~~> // | | | ... | for (int r=0; rheaderData(rowlist[r], Qt::Vertical).toString().replace('"', "''").replace('\n', "\\n ").replace('\r', "\\r ").replace('\t', " "))); // vertical header for (int c=0; c=0) && (c>=0) && (r<=data.size()) && (c<=colcnt))data[r+shift][c+shift]=txt; } QString result=""; for (int r=0; rsetText(result); } } void JKQTPEnhancedTableView::copySelectionToExcelNoHead(int copyrole) { copySelectionToExcel(copyrole, false); } void JKQTPEnhancedTableView::copySelectionToCSV(int copyrole, bool storeHead, const QString &separator, const QChar &decimalpoint) { if (!model()) return; if (!selectionModel()) return; QModelIndexList sel=selectionModel()->selectedIndexes(); QLocale loc=QLocale::c(); loc.setNumberOptions(QLocale::OmitGroupSeparator); if (sel.size()==1) { QVariant vdata=sel[0].data(copyrole); QString txt=""; switch (vdata.type()) { case QVariant::Int: case QVariant::LongLong: case QVariant::UInt: case QVariant::ULongLong: case QVariant::Bool: txt=vdata.toString(); break; case QVariant::Double: txt=JKQTPDoubleToQString(vdata.toDouble(), 15, 'g', decimalpoint); break; case QVariant::PointF: txt=JKQTPDoubleToQString(vdata.toPointF().x(), 15, 'g', decimalpoint); break; default: txt=QString("\"%1\"").arg(vdata.toString().replace('"', "''").replace('\n', "\\n ").replace('\r', "\\r ").replace('\t', " ")); break; } QApplication::clipboard()->setText(txt); } else { QSet rows, cols; int colmin=0; int rowmin=0; for (int i=0; i rowlist=QList::fromSet(rows); qSort(rowlist.begin(), rowlist.end()); QList collist=QList::fromSet(cols); qSort(collist.begin(), collist.end()); int rowcnt=rowlist.size(); int colcnt=collist.size(); QList data; // header row: // // | | | ... QStringList hrow; if (storeHead) { hrow.append(""); // empty header for first column (vertical headers!) for (int c=0; cheaderData(collist[c], Qt::Horizontal).toString().replace('"', "''").replace('\n', "\\n ").replace('\r', "\\r ").replace('\t', " "))); } data.append(hrow); } // now add dta rows: // // <~~~~~~~~~ colcnt times ~~~~~~~~~~> // | | | ... | for (int r=0; rheaderData(rowlist[r], Qt::Vertical).toString().replace('"', "''").replace('\n', "\\n ").replace('\r', "\\r ").replace('\t', " "))); // vertical header for (int c=0; c=0) && (c>=0) && (r<=data.size()) && (c<=colcnt))data[r+shift][c+shift]=txt; } QString result=""; for (int r=0; rsetText(result); } } void JKQTPEnhancedTableView::copySelectionToCSVNoHead(int copyrole, const QString &separator, const QChar &decimalpoint) { copySelectionToCSV(copyrole, false, separator, decimalpoint); } void JKQTPEnhancedTableView::keyPressEvent(QKeyEvent *event) { if (event->matches(QKeySequence::Copy)) { copySelectionToExcel(Qt::EditRole, false); event->accept(); } else if (event->matches(QKeySequence::Print)) { print(); event->accept(); } else QTableView::keyPressEvent(event); emit keyPressed(event->key(), event->modifiers(), event->text()); } void JKQTPEnhancedTableView::print() { QPrinter* tablePrinter=getPrinter(nullptr); if (tablePrinter) { QDialog* dlg=new QDialog(this); dlg->setWindowTitle(tr("Table print options ...")); QGridLayout* lay=new QGridLayout(); dlg->setLayout(lay); lay->addWidget(new QLabel(tr("scaling:")), 0,0); QCheckBox* chk1Wide=new QCheckBox(tr("one page wide"), dlg); QCheckBox* chk1High=new QCheckBox(tr("one page high"), dlg); lay->addWidget(chk1Wide, 0, 1); lay->addWidget(chk1High, 1, 1); QDialogButtonBox* btns=new QDialogButtonBox(QDialogButtonBox::Ok|QDialogButtonBox::Cancel,Qt::Horizontal,dlg); connect(btns, SIGNAL(accepted()), dlg, SLOT(accept())); connect(btns, SIGNAL(rejected()), dlg, SLOT(reject())); lay->addWidget(btns, 2, 0,1,2); if (dlg->exec()) { print(tablePrinter, chk1Wide->isChecked(), chk1High->isChecked()); } delete dlg; delete tablePrinter; } } void JKQTPEnhancedTableView::print(QPrinter *printer, bool onePageWide, bool onePageHigh) { QPrinter* p=printer; //p->setPageMargins(10,10,10,10,QPrinter::Millimeter); /*if (width()>height()) { p->setOrientation(QPrinter::Landscape); } else { p->setOrientation(QPrinter::Portrait); }*/ clearSelection(); /// PRINT HERE ////////////////////////////////////////////////////////////////////////////////// // calculate the total width/height table would need without scaling const int rows = model()->rowCount(); const int cols = model()->columnCount(); double vhw=verticalHeader()->width()+8; double totalWidth = vhw; double minWidth=1e33; double maxWidth=0; for (int c = -1; c < cols; ++c) { double w=columnWidth(c); totalWidth += w; if (wmaxWidth) maxWidth=w; } double hhh=horizontalHeader()->height()+8; double totalHeight = hhh; double minHeight=1e33; double maxHeight=0; for (int r = 0; r < rows; ++r) { double h=rowHeight(r); totalHeight += h; if (hmaxHeight) maxHeight=h; } double scale=1.0; // adjust scale, so the widest/highest column fits on one page /*if (maxWidth*scale>p->pageRect().width()) scale=p->pageRect().width()/maxWidth; if (maxHeight*scale>p->pageRect().height()) scale=p->pageRect().height()/maxHeight;*/ if (onePageWide) { if (totalWidth>p->pageRect().width()) scale=p->pageRect().width()/totalWidth; } if (onePageHigh) { if (totalHeight>p->pageRect().height()) scale=qMin(scale, p->pageRect().height()/totalHeight); } //qDebug()< pageCols, pageRows; pageCols<<0; pageRows<<0; { // find number of pages needed double x=vhw, x0=vhw; if (!onePageWide) { for (int c=0; cp->pageRect().width()/scale) { pagesWide++; x=0; pageCols<0 && cols>pageCols.last()) pageCols<p->pageRect().height()/scale) { pagesHigh++; pageRows<0 && rows>pageRows.last()) pageRows<width()+8; double hhh=horizontalHeader()->height()+8; double scaleX=size.width()/double(pageRec.width()); double scaleY=size.height()/double(pageRec.height()); double scale=qMin(scaleX, scaleY); QListpageCols, pageRows; pageCols<<0<columnCount(); pageRows<<0<rowCount(); paint(painter, scale, -1, hhh, vhw, pageCols, pageRows); painter.restore(); } QSizeF JKQTPEnhancedTableView::getTotalSize() const { const int rows = model()->rowCount(); const int cols = model()->columnCount(); double vhw=verticalHeader()->width()+8; double totalWidth = vhw; for (int c = -1; c < cols; ++c) { double w=columnWidth(c); totalWidth += w; } double hhh=horizontalHeader()->height()+8; double totalHeight = hhh; for (int r = 0; r < rows; ++r) { double h=rowHeight(r); totalHeight += h; } return QSizeF((totalWidth), (totalHeight)); } void JKQTPEnhancedTableView::paint(QPainter &painter, double scale, int page, double hhh, double vhw, const QList& pageCols, const QList& pageRows, QPrinter* p) { painter.save(); QStyleOptionViewItem option = viewOptions(); painter.scale(scale, scale); QPen headerPen("black"); headerPen.setWidth(2); QPen cellPen("gray"); cellPen.setWidth(1); QFont headerFont=horizontalHeader()->font(); headerFont.setBold(true); int pagesWide=pageCols.size()-1; int pagesHigh=pageRows.size()-1; //painter.translate(p->pageRect().topLeft()); int pageCnt=0; for (int ph=0; phpageRect().topLeft(), pic); double y=0; if (ph==0) { y=hhh; } //qDebug()<<" rows = "<(x), static_cast(y), static_cast(vhw), rh); //verticalHeader()->itemDelegate()->paint(&painter, option, model()->index(r, c, QModelIndex())); x=vhw; } for (int c=pageCols[pw]; c(x), static_cast(y), static_cast(cw), rh); itemDelegate()->paint(&painter, option, model()->index(r, c, QModelIndex())); painter.setPen(cellPen); painter.drawRect(option.rect); x=x+cw; } y=y+rh; } if (ph==0) { y=0; int x=0; if (pw%pagesWide==0) x=static_cast(vhw); painter.setPen(headerPen); for (int c=pageCols[pw]; c(y), columnWidth(c), static_cast(hhh)); painter.fillRect(rec, QColor("lightgrey")); painter.setFont(headerFont); painter.setPen(headerPen); painter.drawText(QRect(rec.x()+4, rec.y()+4, rec.width()-8, rec.height()-8), model()->headerData(c, Qt::Horizontal).toString()); painter.drawRect(rec); //if (x==vhw &&) painter.drawLine(rec.topLeft(), QPoint(rec.left(), p->pageRect().height())); x=x+columnWidth(c); } } if (pw%pagesWide==0) { y=0; int x=0; if (ph==0) y=hhh; for (int r=pageRows[ph]; r(y), static_cast(vhw), rowHeight(r)); painter.fillRect(rec, QColor("lightgrey")); painter.setPen(headerPen); painter.setFont(headerFont); painter.drawText(QRect(rec.x()+4, rec.y()+4, rec.width()-8, rec.height()-8), model()->headerData(r, Qt::Vertical).toString()); painter.drawRect(rec); //if (x==vhw &&) painter.drawLine(rec.topLeft(), QPoint(rec.left(), p->pageRect().height())); y=y+rowHeight(r); } } if (p && pwnewPage(); } pageCnt++; } if (p && phnewPage(); } painter.restore(); } QPrinter *JKQTPEnhancedTableView::getPrinter(QPrinter *printerIn, bool *localPrinter) { QPrinter* p=printerIn; if (p==nullptr) { p=new QPrinter(); if (localPrinter) *localPrinter=true; } QPrintDialog *dialog = new QPrintDialog(p, nullptr); dialog->setWindowTitle(tr("Print Table")); if (dialog->exec() != QDialog::Accepted) { if (localPrinter && *localPrinter) delete p; delete dialog; return printerIn; } p=dialog->printer(); delete dialog; return p; }