maxLibQt
ExportableTableView.cpp
Go to the documentation of this file.
1 /*
2  ExportableTableView
3  https://github.com/mpaperno/maxLibQt
4 
5  COPYRIGHT: (c)2017 Maxim Paperno; All Right Reserved.
6  Contact: http://www.WorldDesign.com/contact
7 
8  LICENSE:
9 
10  Commercial License Usage
11  Licensees holding valid commercial licenses may use this file in
12  accordance with the terms contained in a written agreement between
13  you and the copyright holder.
14 
15  GNU General Public License Usage
16  Alternatively, this file may be used under the terms of the GNU
17  General Public License as published by the Free Software Foundation,
18  either version 3 of the License, or (at your option) any later version.
19 
20  This program is distributed in the hope that it will be useful,
21  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23  GNU General Public License for more details.
24 
25  A copy of the GNU General Public License is available at <http://www.gnu.org/licenses/>.
26 */
27 
28 #include "ExportableTableView.h"
29 
31 {
35 
36  QAction * selAll = new QAction(tr("Select All"), this);
38  addAction(selAll);
39 
40  QAction * cpyTab = new QAction(tr("Copy selection as TAB-delimited text"), this);
42  cpyTab->setProperty("delim", "\t");
43  addAction(cpyTab);
44 
45  QAction * cpyCsv = new QAction(tr("Copy selection as comma-delimited text (CSV)"), this);
47  cpyCsv->setProperty("delim", ", ");
48  addAction(cpyCsv);
49 
50  QAction * cpyPipe = new QAction(tr("Copy selection as pipe-delimited text"), this);
51  cpyPipe->setShortcut(Qt::CTRL + Qt::ALT + Qt::Key_C);
52  cpyPipe->setProperty("delim", " | ");
53  addAction(cpyPipe);
54 
55  QAction * cpyHtml = new QAction(tr("Copy selection as HTML"), this);
57  cpyHtml->setProperty("delim", "html");
58  addAction(cpyHtml);
59 
60  QAction * saveFile = new QAction(tr("Save selection to file"), this);
62  addAction(saveFile);
63 
71 }
72 
74 {
75  return "th, td {font-family: sans-serif; padding: 3px 15px 3px 3px;} " \
76  "th {text-align: left;}";
77 }
78 
80 {
81  return "<!DOCTYPE html>\n<html>\n<head><meta charset='utf-8'/><style>" \
82  "%1" \
83  "</style></head>\n<body>\n" \
84  "<table border=0 cellspacing=2>\n" \
85  "%2" \
86  "</table>\n" \
87  "</body></html>";
88 }
89 
91 {
92  m_htmlStyle = value;
93 }
94 
96 {
97  m_htmlTemplate = value;
98 }
99 
100 QString ExportableTableView::toPlainText(const QModelIndexList &indexList, const QString &delim) const
101 {
102  QString ret, header;
103  const QChar rowDelim = '\n';
104  bool firstRow = true;
105  for (int i = 0; i < indexList.count(); ++i) {
106  const QModelIndex & idx = indexList.at(i);
107 
108  if (firstRow)
109  header.append(model()->headerData(idx.column(), Qt::Horizontal).toString());
110 
111  ret.append(idx.data(Qt::DisplayRole).toString());
112 
113  if (i + 1 == indexList.count() || indexList.at(i+1).row() != idx.row()) {
114  ret.append(rowDelim);
115  if (firstRow && !header.isEmpty())
116  header.append(rowDelim);
117  firstRow = false;
118  }
119  else {
120  ret.append(delim);
121  if (firstRow && !header.isEmpty())
122  header.append(delim);
123  }
124  }
125  if (!header.isEmpty())
126  ret.prepend(header);
127 
128  return ret;
129 }
130 
131 QString ExportableTableView::toHtml(const QModelIndexList &indexList) const
132 {
133  QString ret, header, row;
134  bool firstRow = true;
135 
136  for (int i = 0; i < indexList.count(); ++i) {
137  const QModelIndex & idx = indexList.at(i);
139  const QString fg = (idx.data(Qt::ForegroundRole).isValid() ? idx.data(Qt::ForegroundRole).value<QBrush>().color().name(QColor::HexRgb) : "initial");
140  const QString bg = (idx.data(Qt::BackgroundRole).isValid() ? idx.data(Qt::BackgroundRole).value<QBrush>().color().name(QColor::HexRgb) : "initial");
141  const QString ttl = (idx.data(Qt::ToolTipRole).isValid() ? idx.data(Qt::ToolTipRole).toString().replace("\"", "\"\"") : QString());
142 
143  QString fnt;
144  if (idx.data(Qt::FontRole).isValid()) {
145  const QFont font = idx.data(Qt::FontRole).value<QFont>();
146  fnt = "font: \"" % font.family() % "\" " % QString::number(font.pointSize()) % "pt;";
147  }
148 
149  if (firstRow)
150  header.append(QString("<th>%1</th>\n").arg(model()->headerData(idx.column(), Qt::Horizontal).toString()));
151 
152  row.append("<td style='color: %2; background-color: %3; %4' align='%5' valign='%6' %7>%1</td>\n"); // cell template
153  row = row.arg(idx.data(Qt::DisplayRole).toString()).arg(fg).arg(bg).arg(fnt);
154  row = row.arg((algn & Qt::AlignRight) ? "right" : (algn & Qt::AlignHCenter) ? "center" : "left");
155  row = row.arg((algn & Qt::AlignTop) ? "top" : (algn & Qt::AlignBottom) ? "bottom" : "middle");
156  row = row.arg(ttl.isEmpty() ? ttl : QString("title=\"%1\"").arg(ttl));
157 
158  if (i + 1 == indexList.count() || indexList.at(i+1).row() != idx.row()) {
159  ret.append(QString("<tr>\n%1</tr>\n").arg(row));
160  row.clear();
161  firstRow = false;
162  }
163  }
164 
165  ret = QString("<tbody>\n%1</tbody>\n").arg(ret);
166  if (!header.isEmpty())
167  ret.prepend(QString("<thead>\n<tr>\n%1</tr>\n</thead>\n").arg(header));
168  ret = m_htmlTemplate.arg(m_htmlStyle).arg(ret);
169 
170  return ret;
171 }
172 
173 bool ExportableTableView::saveToFile(const QModelIndexList &indexList, const QString &fileName)
174 {
176 
177  if (indexList.isEmpty())
178  return false;
179 
180  QString fname = fileName;
181  if (fname.isEmpty()) {
182  QString types = tr("Tab-delimited text") % " (*.tab);;" % tr("Comma-delimited text") % " (*.csv);;" % tr("Pipe-delimited text") % " (*.txt);;" % tr("HTML") % " (*.html)";
183  fname = QFileDialog::getSaveFileName(this, tr("Save to file"), lastDir, types);
184  }
185 
186  if (fname.isEmpty())
187  return false;
188 
189  QFile file(fname);
190  QFileInfo fi(file);
191  lastDir = fi.absolutePath();
192 
194  return false;
195 
196  if (fi.suffix() == "html")
197  file.write(toHtml(indexList).toUtf8());
198  else
199  file.write(toPlainText(indexList, (fi.suffix() == "tab" ? "\t" : fi.suffix() == "csv" ? ", " : " | ")).toUtf8());
200  file.close();
201 
202  return true;
203 }
204 
206 {
207  int w = 0;
208  for (int i = 0; i < model()->columnCount(); ++i)
209  w += sizeHintForColumn(i);
210  return QSize(w + verticalScrollBar()->sizeHint().width() + 60, sizeHintForRow(0) * model()->rowCount());
211 }
212 
214 {
216 }
217 
219 {
220  QMimeData * mdata = new QMimeData;
221  mdata->setHtml(toHtml(getSelectedOrAll()));
223 }
224 
226 {
227  QString delim = "\t";
228  if (sender() && sender()->property("delim").isValid())
229  delim = sender()->property("delim").toString();
230  if (delim == "html")
231  copyHtml();
232  else
233  copyText(delim);
234 }
235 
237 {
239 }
240 
242 {
243  QModelIndexList sel = selectionModel()->selectedIndexes();
244  if (sel.isEmpty()) {
245  selectAll();
246  sel = selectionModel()->selectedIndexes();
247  }
248  return sel;
249 }
250 
252 {
253  QMenu menu;
254  menu.addActions(actions());
255  menu.exec(mapToGlobal(pos));
256 }
void customContextMenuRequested(const QPoint &pos)
static QString getDefaultHtmlStyle()
Get the default style sheet used for HTML export.
void save()
Saves currently selected cell(s) to a file of the user's choice and format.
void triggered(bool checked)
QString & append(QChar ch)
QString toHtml(const QModelIndexList &indexList) const
Saves data from the passed model indices to an HTML-formatted string.
QString writableLocation(QStandardPaths::StandardLocation type)
QItemSelectionModel * selectionModel() const const
void addAction(QAction *action)
void setHtmlStyle(const QString &value)
Set the style sheet for HTML export.
void addActions(QList< QAction * > actions)
QObject * sender() const const
QString & prepend(QChar ch)
void onCustomContextMenuRequested(const QPoint &pos)
QPoint mapToGlobal(const QPoint &pos) const const
T value() const const
bool saveToFile(const QModelIndexList &indexList, const QString &fileName=QString())
Saves data from the passed model indices to a file in text or HTML format.
CustomContextMenu
AlignLeft
virtual int sizeHintForRow(int row) const const override
QString tr(const char *s, const char *c, int n)
void clear()
void copyText(const QString &delim=QString("\t"))
Copies currently selected cell(s) to the clipboard as plain text.
int width() const const
QString number(int n, int base)
QVariant property(const char *name) const const
int toInt(bool *ok) const const
DisplayRole
bool isEmpty() const const
int row() const const
QPoint pos() const const
void setMimeData(QMimeData *src, QClipboard::Mode mode)
QScrollBar * verticalScrollBar() const const
virtual bool open(QIODevice::OpenMode mode) override
QAction * exec()
static QString getDefaultHtmlTemplate()
Get the default overall template used for HTML export.
const QFont & font() const const
void setContextMenuPolicy(Qt::ContextMenuPolicy policy)
void setShortcut(const QKeySequence &shortcut)
void copy()
Designed for QAction connections, it calls copyText() or copyHtml() based on delimiter specified in s...
QString & replace(int position, int n, QChar after)
QString suffix() const const
QVariant data(int role) const const
virtual void selectAll()
ExportableTableView(QWidget *parent=Q_NULLPTR)
ExportableTableView.
virtual void close() override
QString family() const const
virtual int columnCount(const QModelIndex &parent) const const=0
QString toPlainText(const QModelIndexList &indexList, const QString &delim="\t") const
Saves data from the passed model indices to a text string.
virtual int sizeHintForColumn(int column) const const override
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options)
int column() const const
qint64 write(const char *data, qint64 maxSize)
QModelIndexList getSelectedOrAll()
Return a list of selected cells.
bool isValid() const const
bool setProperty(const char *name, const QVariant &value)
QSize sizeHint() const override
void setText(const QString &text, QClipboard::Mode mode)
Horizontal
void setHtml(const QString &html)
QAbstractItemModel * model() const const
QString absolutePath() const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QList< QAction * > actions() const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
QString toString() const const
QClipboard * clipboard()
int pointSize() const const
void setHtmlTemplate(const QString &value)
Set the overall template for HTML export.
void copyHtml()
Copies currently selected cell(s) to the clipboard as HTML (with MIME content-type "text/html").
QByteArray toUtf8() const const