SoDaRadio-5.0.3-master:8901fb5
soda_logtable.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2017 Matthew H. Reilly (kb1vc)
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
8 
9  Redistributions of source code must retain the above copyright
10  notice, this list of conditions and the following disclaimer.
11  Redistributions in binary form must reproduce the above copyright
12  notice, this list of conditions and the following disclaimer in
13  the documentation and/or other materials provided with the
14  distribution.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 
29 #include "soda_logtable.hpp"
30 #include <iostream>
31 #include <QFile>
32 #include <QMessageBox>
33 #include <QXmlStreamWriter>
34 #include <QXmlStreamReader>
35 #include <QDebug>
36 #include <QDateTime>
37 
38 GUISoDa::LogTable::LogTable(QWidget *parent) :
39  QTableWidget(parent)
40 {
41  horizontalHeader()->setStretchLastSection(true);
42 
43  QStringList headers;
44  headers << "Date" << "Time" << "From Call" << "From Grid" << "To Call" << "To Grid"
45  << "Mode" << "RX Freq" << "TX Freq" << "Comment";
46  setColumnCount(headers.size());
47 
48  setKeys(headers);
49 
50  setShowGrid(true);
51 
52 
53  connect(this, &GUISoDa::LogTable::cellChanged,
54  [this](int row, int col) {
55  emit entryUpdated(row,
56  this->current_headers.at(col),
57  this->item(row, col)->text()); });
58 
59  connect(this, SIGNAL(cellChanged(int, int)),
60  this, SLOT(recordChange(int, int)));
61 
62  next_used_row = 0;
63 
64  // open a default log file in the current working dir as
65  // SoDa_DDMMYY_HHMMSS.soda_log
66  QDateTime utc_time(QDateTime::currentDateTime().toUTC());
67 
68  QString logfname = QString("SoDa_%1_%2.soda_log").arg(utc_time.toString("ddMMyy")).arg(utc_time.toString("hhmmss"));
69  log_file_out = NULL;
70  setLogFile(logfname);
71 }
72 
73 void GUISoDa::LogTable::setKeys(QStringList headers)
74 {
75  current_headers = headers; // save the header list -- they'll be used for keys.
76  setHorizontalHeaderLabels(headers);
77 }
78 
80 {
81  // write the log report
82  // close the log file.
83  if(log_file_out != NULL) {
84  int logsize = log_file_out->size();
85  if(logsize == 0) {
86  log_file_out->remove();
87  }
88  else {
89  log_file_out->close();
90  }
91  }
92 }
93 
95  for(int i = 0; i < columnCount(); i++) {
96  if(item(r, i)) return false;
97  }
98  return true;
99 }
100 
101 void GUISoDa::LogTable::writeLogReport(const QString & fname)
102 {
103  int rows = rowCount();
104  int cols = columnCount();
105 
106  setLogFile(fname);
107 
108  // we're going to write row,col,value streams to the output
109  QTextStream out(log_file_out);
110  for(int i = 0; i < rows; i++) {
111 
112  if(emptyRow(i)) continue;
113 
114  for(int j = 0; j < cols; j++) {
115  QTableWidgetItem * itm(item(i,j));
116  if(itm) {
117  out << QString("%1:%2:%3").arg(i).arg(j).arg(itm->text()) << endl;
118  }
119  }
120  }
121  log_file_out->flush();
122 }
123 
125 {
126  if((log_file_out != NULL) && log_file_out->isOpen()) {
127  QTextStream out(log_file_out);
128  QTableWidgetItem * itm(item(r,c));
129  if(itm) {
130  out << QString("%1:%2:%3").arg(r).arg(c).arg(item(r,c)->text()) << endl;
131  }
132  else {
133  out << QString("%1:%2: ").arg(r).arg(c) << endl;
134  }
135  log_file_out->flush();
136  }
137 }
138 
139 
140 void GUISoDa::LogTable::readLogReport(const QString & fname)
141 {
142  // load the table from the input stream.
143  qDebug() << QString("Reading log file [%1]").arg(fname);
144  QFile infile(fname);
145 
146  if(!infile.open(QFile::ReadOnly)) {
147  QMessageBox::information(this, tr("Unable to open file for reading"),
148  infile.errorString());
149  return;
150  }
151 
152  QString lbuf;
153  QTextStream instr(&infile);
154  int row_start = next_used_row;
155  int max_row = -1;
156  while(!(lbuf = instr.readLine()).isNull()) {
157  int co0 = lbuf.indexOf(':');
158  int co1 = lbuf.indexOf(':',co0+1);
159 
160  // strip out row, col.
161  int row = lbuf.mid(0,co0).toInt() + row_start;
162  int col = lbuf.mid(co0+1,co1 - (co0+1)).toInt();
163  QString val = lbuf.mid(co1+1);
164  if((row + 10) > rowCount()) setRowCount(rowCount() + 20);
165  setItem(row, col, new QTableWidgetItem(val));
166  if(row > max_row) max_row = row;
167  }
168  next_used_row = max_row + 1;
169  infile.close();
170 }
171 
173 {
174  QString fname = QFileDialog::getOpenFileName(this,
175  tr("Read Log Report from File"),
176  "",
177  tr("*.soda_log (*.soda_log);;All Files(*)"));
178  if(!fname.isEmpty()) readLogReport(fname);
179 }
180 
182 {
183  QString fname = QFileDialog::getSaveFileName(this,
184  tr("Write Log Report to File"),
185  "",
186  tr("*.soda_log (*.soda_log);;All Files(*)"));
187  if(!fname.isEmpty()) writeLogReport(fname);
188 }
189 
190 
191 void GUISoDa::LogTable::logContact(const QString & from_call,
192  const QString & from_grid,
193  const QString & to_call,
194  const QString & to_grid,
195  const QString & mode,
196  const QString & comment,
197  double rx_freq,
198  double tx_freq)
199 {
200  QDateTime utc_time(QDateTime::currentDateTime().toUTC());
201 
202  setField(next_used_row, "Date", utc_time.toString("d-MMM-yyyy"));
203  setField(next_used_row, "Time", utc_time.toString("hh:mm:ss"));
204  setField(next_used_row, "From Call", from_call);
205  setField(next_used_row, "From Grid", from_grid);
206  setField(next_used_row, "To Call", to_call);
207  setField(next_used_row, "To Grid", to_grid);
208  setField(next_used_row, "Mode", mode);
209  setField(next_used_row, "Comment", comment);
210  setField(next_used_row, "RX Freq", rx_freq);
211  setField(next_used_row, "TX Freq", tx_freq);
212  // scroll so the edit log window shows the last line in the log
213  scrollToItem(item(next_used_row, 1));
214 
215  // bump the pointer to the next row
216  next_used_row++;
217  // if we're almost out, allocate a bunch of new rows.
218  if((next_used_row + 10) > rowCount()) {
219  setRowCount(rowCount() + 20);
220  }
221 }
222 
223 void GUISoDa::LogTable::setLogFile(const QString & fname)
224 {
225  if(log_file_out != NULL) {
226  log_file_out->close();
227  }
228 
229  log_file_out = new QFile(fname);
230  if(!log_file_out->open(QIODevice::WriteOnly)) {
231  QMessageBox::information(this, tr("Unable to open file for writing"),
232  log_file_out->errorString());
233  return;
234  }
235 }
void recordChange(int r, int c)
QStringList current_headers
void writeLogReport(const QString &fname)
void setLogFile(const QString &fname)
void readLogReport(const QString &fname)
void logContact(const QString &from_call, const QString &from_grid, const QString &to_call, const QString &to_grid, const QString &mode, const QString &comment, double rx_freq, double tx_freq)
void entryUpdated(int row, const QString &key, const QString &val)
LogTable(QWidget *parent=Q_NULLPTR)
void setKeys(QStringList headers)
bool emptyRow(int r)
void setField(int row, const QString &key_st, const QString &st)