WARNING: USE THIS SOFTWARE AT YOUR OWN RISK! THIS IS EXPERIMENTAL SOFTWARE NOT INTENDED FOR PRODUCTION USE! Zuble is currently an early stage prototype. As such Zuble is minimally tested and inherently unstable. It is provided for experimental, development, and demonstration purposes only. Zuble QML Types   |  Zuble C++ Classes   |  Zuble Overview
Zuble  0.1
Zuble Framework C++/QML extension API
ZTableFile.cpp
Go to the documentation of this file.
1 /*
2  * Zuble - A run-time system for QML/Javascript applications
3  * Copyright (C) 2015 Bob Dinitto
4  *
5  * Filename: ZTableFile.cpp
6  * Created on: 7/6/2015
7  * Author: Bob Dinitto
8  *
9  * Zuble is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22  *
23  */
24 
25 #include "ZTableFile.h"
26 #include "ZTableModel.h"
27 #include "ZblException.h"
28 #include <QSaveFile>
29 #include <QFile>
30 #include <QJsonDocument>
31 #include <QJsonObject>
32 #include <QJsonArray>
33 
34 namespace Zbl
35 {
36 
38 
39 qint64 ZTableFile::m_maxFileBytes = 100000 * 1024;
40 
41 ZTableFile::ZTableFile(QObject *parent) :
42  QObject(parent)
43 {
45 
46  m_data = new ZTableModel(this);
47 
48  m_watcher = new QFileSystemWatcher(this);
49 
50  QMetaObject::Connection connection = connect(m_watcher,
51  &QFileSystemWatcher::fileChanged, this, &ZTableFile::fileModified);
52 
53  if(!connection)
54  zCritical() << "Data file object watcher connection failed.";
55 }
56 
58 {
59  if(!m_watcher)
60  throw ZblException(
61  "ZTableFile - Programming error: object not initialized");
62 }
63 
64 
65 #if 0
66 bool ZTableFile::open(int openMode)
67 {
68  bool retValue;
69  ZBLQ_INVOKABLE_SLOT_BEGIN_TRY
70  validateFile();
71  retValue = m_f->open(QFile::OpenMode(openMode));
72  ZBL_SLOT_END_RETURN(retValue, false,
73  Z_FAC_JS, ZFile::open, open failed)
74 }
75 #endif
76 
77 
78 
79 bool ZTableFile::readFile(const QString& filePath)
80 {
81  m_data->clearRoles();
82 
83  bool pathChanged = false;
84 
85  if(filePath.isEmpty() && m_filePath.isEmpty())
86  {
87  zWarning() << "Can't read data file for empty path.";
88 
89  return false;
90  }
91  else
92  {
93  if(filePath != m_filePath)
94  {
95  m_watcher->removePath(m_filePath);
96 
97  pathChanged = true;
98 
99  m_filePath = filePath;
100  }
101  }
102 
103  zDebug() << "Writing data file: " << filePath;
104 
105  QFile in(m_filePath);
106 
107  if(!in.exists())
108  {
109  zWarning() << "Can't read non-existent data file: " << m_filePath;
110  return false;
111  }
112 
113  bool ok = in.open(QIODevice::ReadOnly | QIODevice::Text);
114 
115  if(!ok)
116  {
117  zWarning() << "Can't open data file for reading: " << m_filePath;
118  zWarning() << "File error status: " << in.errorString();
119  return false;
120  }
121 
122  QByteArray ba = in.read(m_maxFileBytes);
123 
124  if(ba.isEmpty())
125  {
126  if(in.error() == QFile::NoError)
127  {
128  zWarning() << "Can't read empty data file: " << m_filePath;
129  }
130  else
131  {
132  zWarning() << "File I/O error reading data file: " << m_filePath;
133  zWarning() << "File error status: " << in.errorString();
134  }
135  in.close();
136  return false;
137  }
138 
139  in.close();
140 
141  QJsonParseError error;
142 
143  QJsonDocument doc = QJsonDocument::fromJson(ba, &error);
144 
145  if(error.error != QJsonParseError::NoError)
146  {
147  zWarning() << "JSON parse error reading data file: " << m_filePath;
148  zWarning() << "JSON error status: " << error.errorString();
149  return false;
150  }
151 
152  m_data->putJsonData(doc.object()); // TBD: EXCEPTION HANDLER NEEDED!
153 
154  if(!ok)
155  {
156  zWarning() << "Data format error reading file: " << m_filePath;
157  return false;
158  }
159 
160  if(pathChanged)
161  {
162  if(!m_watcher->addPath(m_filePath))
163  {
164  zWarning() << "Can't monitor data file: " << m_filePath;
165  }
166  }
167 
168  return true;
169 
170 }
171 
172 bool ZTableFile::writeFile(const QString& filePath)
173 {
174  QString previousFilePath;
175 
176  if(!filePath.isEmpty())
177  {
178  if(filePath != m_filePath)
179  {
180  previousFilePath = m_filePath;
181 
182  m_filePath = filePath;
183  }
184  }
185 
186  QSaveFile sf(m_filePath);
187 
188  bool ok = sf.open(QIODevice::WriteOnly | QIODevice::Text);
189 
190  if(!ok)
191  {
192  zWarning() << "Can't open data file for writing: "
193  << m_filePath;
194  return false;
195  }
196 
197  QJsonObject jo = m_data->getJsonData();
198 
199  QJsonDocument jd(jo);
200 
201  QByteArray ba = jd.toBinaryData();
202 
203  qint64 bytesOut = sf.write(ba);
204 
205  if(bytesOut == -1)
206  {
207  zWarning() << "Can't write to data file: " << m_filePath;
208  return false;
209  }
210 
211  ok = sf.commit();
212 
213  if(!ok)
214  {
215  zWarning() << "Can't commit data file: " << m_filePath;
216  return false;
217  }
218 
219  if(!previousFilePath.isEmpty())
220  {
221  m_watcher->removePath(previousFilePath);
222 
223  if(!m_watcher->addPath(m_filePath))
224  {
225  zWarning() << "Can't monitor data file: " << m_filePath;
226  }
227  }
228 
229  return true;
230 }
231 
232 
233 
234 
235 } // Zbl
Q_INVOKABLE bool writeFile(const QString &filePath)
Writes the data table to the specified file. Returns true if successful; otherwise returns false...
Definition: ZTableFile.cpp:172
Q_INVOKABLE bool open(int openMode)
Opens the device and sets its open mode to openMode. Returns true if successful; otherwise returns fa...
Definition: ZFile.cpp:173
#define Z_FAC_JS
Definition: zglobal.h:123
Q_INVOKABLE QJsonObject getJsonData() const
Copies data from the table model into a newly created JSON object and returns it. ...
QFileSystemWatcher * m_watcher
Monitors table data file for updates from this and other applications.
Definition: ZTableFile.h:96
#define ZBL_REGISTER_LOGGED_OBJECT
Definition: zglobal.h:104
ZTableFile(QObject *parent=0)
Definition: ZTableFile.cpp:41
Q_INVOKABLE bool readFile(const QString &filePath)
Reads the specified table file into the data table. Previous data in the table is discarded...
Definition: ZTableFile.cpp:79
ZBL_DECLARE_LOGGED_OBJECT void validateWatcher()
Definition: ZTableFile.cpp:57
ZTableModel * m_data
The data model that will send or receive data.
Definition: ZTableFile.h:102
static qint64 m_maxFileBytes
Definition: ZTableFile.h:105
Definition: ZAndGate.cpp:6
#define ZBL_DEFINE_LOGGED_OBJECT(class_name)
Definition: zglobal.h:99
#define zWarning()
Definition: zglobal.h:111
This two dimensional table model is used to store and manipulate data.
Definition: ZTableModel.h:96
void fileModified(const QString &path)
Sent whenever the data file is modified by this or other programs.
Q_INVOKABLE void clearRoles()
Removes all roles, role names and data from the model.
#define zDebug()
Definition: zglobal.h:113
Q_INVOKABLE void putJsonData(QJsonObject data)
Writes data from the specified JSON object into the data table. Previous contents of the data table a...
QString m_filePath
Path to the file that was last read or written.
Definition: ZTableFile.h:89
This class in theory allows reading and writing of ZTableModel objects to JSON files. (TBD: currently unused/untested?)
Definition: ZTableFile.h:44
Zuble&#39;s Qt Exception Object.
Definition: ZblException.h:45
#define ZBL_SLOT_END_RETURN(return_success, return_failed, facility, code, error_message)
Definition: zglobal.h:141
#define zCritical()
Definition: zglobal.h:112