fb2temp.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. #include "fb2temp.hpp"
  2. #include <QAbstractListModel>
  3. #include <QCryptographicHash>
  4. #include <QFileInfo>
  5. #include <QImageReader>
  6. #include <QUrl>
  7. #include <QVBoxLayout>
  8. #include <QtDebug>
  9. #include "fb2text.hpp"
  10. //---------------------------------------------------------------------------
  11. // FbTemporaryFile
  12. //---------------------------------------------------------------------------
  13. FbTemporaryFile::FbTemporaryFile(const QString &name)
  14. : QTemporaryFile()
  15. , m_name(name)
  16. {
  17. }
  18. qint64 FbTemporaryFile::write(const QByteArray &data)
  19. {
  20. open();
  21. if (m_hash.isEmpty()) m_hash = md5(data);
  22. qint64 size = QTemporaryFile::write(data);
  23. close();
  24. return size;
  25. }
  26. QString FbTemporaryFile::md5(const QByteArray &data)
  27. {
  28. return QCryptographicHash::hash(data, QCryptographicHash::Md5).toBase64();
  29. }
  30. QByteArray FbTemporaryFile::data()
  31. {
  32. open();
  33. QByteArray data = readAll();
  34. close();
  35. return data;
  36. }
  37. //---------------------------------------------------------------------------
  38. // FbTemporaryList
  39. //---------------------------------------------------------------------------
  40. FbTemporaryList::FbTemporaryList()
  41. {
  42. }
  43. FbTemporaryList::~FbTemporaryList()
  44. {
  45. FbTemporaryIterator it(*this);
  46. while (it.hasNext()) delete it.next();
  47. }
  48. QString FbTemporaryList::add(const QString &path, const QByteArray &data)
  49. {
  50. QString hash = FbTemporaryFile::md5(data);
  51. QString name = this->name(hash);
  52. if (name.isEmpty()) {
  53. name = newName(path);
  54. FbTemporaryFile * temp = new FbTemporaryFile(name);
  55. temp->setHash(hash);
  56. temp->write(data);
  57. append(temp);
  58. }
  59. return name;
  60. }
  61. QString FbTemporaryList::newName(const QString &path)
  62. {
  63. QFileInfo info(path);
  64. QString name = info.fileName();
  65. if (!exists(name)) return name;
  66. QString base = info.baseName();
  67. QString suff = info.suffix();
  68. for (int i = 1; ; i++) {
  69. QString name = QString("%1(%2).%3").arg(base).arg(i).arg(suff);
  70. if (exists(name)) continue;
  71. return name;
  72. }
  73. }
  74. FbTemporaryFile * FbTemporaryList::get(const QString &name) const
  75. {
  76. FbTemporaryIterator it(*this);
  77. while (it.hasNext()) {
  78. FbTemporaryFile * file = it.next();
  79. if (file->name() == name) return file;
  80. }
  81. return NULL;
  82. }
  83. QByteArray FbTemporaryList::data(const QString &name) const
  84. {
  85. FbTemporaryIterator it(*this);
  86. while (it.hasNext()) {
  87. FbTemporaryFile *file = it.next();
  88. if (file->name() == name) return file->data();
  89. }
  90. return QByteArray();
  91. }
  92. const QString & FbTemporaryList::set(const QString &name, const QByteArray &data, const QString &hash)
  93. {
  94. FbTemporaryFile * file = get(name);
  95. if (!file) append(file = new FbTemporaryFile(name));
  96. file->setHash(hash);
  97. file->write(data);
  98. return file->hash();
  99. }
  100. QString FbTemporaryList::name(const QString &hash) const
  101. {
  102. FbTemporaryIterator it(*this);
  103. while (it.hasNext()) {
  104. FbTemporaryFile *file = it.next();
  105. if (file->hash() == hash) return file->name();
  106. }
  107. return QString();
  108. }
  109. bool FbTemporaryList::exists(const QString &name) const
  110. {
  111. FbTemporaryIterator it(*this);
  112. while (it.hasNext()) {
  113. FbTemporaryFile *file = it.next();
  114. if (file->name() == name) return true;
  115. }
  116. return false;
  117. }
  118. #if 0
  119. //---------------------------------------------------------------------------
  120. // FbNetworkDiskCache
  121. //---------------------------------------------------------------------------
  122. QNetworkCacheMetaData FbNetworkDiskCache::metaData(const QUrl &url)
  123. {
  124. qCritical() << url.toString();
  125. return QNetworkDiskCache::metaData(url);
  126. }
  127. QIODevice * FbNetworkDiskCache::data(const QUrl &url)
  128. {
  129. qCritical() << url.toString();
  130. return QNetworkDiskCache::data(url);
  131. }
  132. #endif
  133. //---------------------------------------------------------------------------
  134. // FbImageReply
  135. //---------------------------------------------------------------------------
  136. FbImageReply::FbImageReply(QNetworkAccessManager::Operation op, const QNetworkRequest &request, const QByteArray &data)
  137. : QNetworkReply()
  138. , content(data)
  139. , offset(0)
  140. {
  141. setOperation(op);
  142. setRequest(request);
  143. setUrl(request.url());
  144. open(ReadOnly | Unbuffered);
  145. setHeader(QNetworkRequest::ContentLengthHeader, QVariant(content.size()));
  146. setAttribute(QNetworkRequest::CacheSaveControlAttribute, QVariant(false));
  147. QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
  148. QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
  149. }
  150. qint64 FbImageReply::readData(char *data, qint64 maxSize)
  151. {
  152. if (offset >= content.size()) return -1;
  153. QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
  154. qint64 number = qMin(maxSize, content.size() - offset);
  155. memcpy(data, content.constData() + offset, number);
  156. offset += number;
  157. return number;
  158. }
  159. //---------------------------------------------------------------------------
  160. // FbNetworkAccessManager
  161. //
  162. // http://doc.trolltech.com/qq/32/qq32-webkit-protocols.html
  163. //---------------------------------------------------------------------------
  164. FbNetworkAccessManager::FbNetworkAccessManager(FbTextEdit &view)
  165. : QNetworkAccessManager(&view)
  166. , m_view(view)
  167. {
  168. QWebSettings::clearMemoryCaches();
  169. }
  170. QNetworkReply * FbNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
  171. {
  172. if (request.url().scheme() == "fb2" && request.url().path() == m_view.url().path()) return imageRequest(op, request);
  173. return QNetworkAccessManager::createRequest(op, request, outgoingData);
  174. }
  175. QNetworkReply * FbNetworkAccessManager::imageRequest(Operation op, const QNetworkRequest &request)
  176. {
  177. QString name = request.url().fragment();
  178. QByteArray data = m_files.data(name);
  179. return new FbImageReply(op, request, data);
  180. }
  181. QString FbNetworkAccessManager::name(int index) const
  182. {
  183. if (0 <= index && index < count()) {
  184. return m_files[index]->name();
  185. }
  186. return QString();
  187. }
  188. QByteArray FbNetworkAccessManager::data(int index) const
  189. {
  190. if (0 <= index && index < count()) {
  191. return m_files[index]->data();
  192. }
  193. return QByteArray();
  194. }
  195. void FbNetworkAccessManager::data(QString name, QByteArray data)
  196. {
  197. m_files.set(name, data);
  198. }
  199. //---------------------------------------------------------------------------
  200. // FbListModel
  201. //---------------------------------------------------------------------------
  202. FbListModel::FbListModel(FbNetworkAccessManager &files, QObject *parent)
  203. : QAbstractListModel(parent)
  204. , m_files(files)
  205. {
  206. }
  207. int FbListModel::rowCount(const QModelIndex &parent) const
  208. {
  209. if (parent.isValid()) return 0;
  210. return m_files.count();
  211. }
  212. QVariant FbListModel::data(const QModelIndex &index, int role) const
  213. {
  214. if (index.isValid()) {
  215. switch (role) {
  216. case Qt::DisplayRole: return m_files.name(index.row());
  217. }
  218. }
  219. return QVariant();
  220. }
  221. //---------------------------------------------------------------------------
  222. // FbListView
  223. //---------------------------------------------------------------------------
  224. #include <QSplitter>
  225. #include <QScrollArea>
  226. FbListView::FbListView(FbNetworkAccessManager &files, QWidget *parent)
  227. : QListView(parent)
  228. , m_files(files)
  229. {
  230. m_label = new QLabel(this);
  231. m_label->setScaledContents(true);
  232. }
  233. void FbListView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
  234. {
  235. QListView::currentChanged(current, previous);
  236. int row = current.row();
  237. if (0 <= row && row < m_files.count()) {
  238. QByteArray data = m_files.data(row);
  239. QPixmap pixmap;
  240. pixmap.loadFromData(data);
  241. m_label->setPixmap(pixmap);
  242. m_label->resize(pixmap.size());
  243. }
  244. }
  245. //---------------------------------------------------------------------------
  246. // FbListWidget
  247. //---------------------------------------------------------------------------
  248. FbListWidget::FbListWidget(FbTextEdit &view, QWidget* parent)
  249. : QWidget(parent)
  250. , m_view(view)
  251. {
  252. QVBoxLayout *layout = new QVBoxLayout(this);
  253. layout->setSpacing(0);
  254. layout->setContentsMargins(0, 0, 0, 0);
  255. QSplitter *splitter = new QSplitter(Qt::Vertical, this);
  256. m_list = new FbListView(view.files(), splitter);
  257. splitter->addWidget(m_list);
  258. QScrollArea * scroll = new QScrollArea(splitter);
  259. scroll->setWidget(m_list->label());
  260. splitter->addWidget(scroll);
  261. splitter->setSizes(QList<int>() << 1 << 1);
  262. layout->addWidget(splitter);
  263. connect(&m_view, SIGNAL(loadFinished(bool)), SLOT(loadFinished(bool)));
  264. loadFinished(true);
  265. // m_tool = new QToolBar(this);
  266. // layout->addWidget(m_tool);
  267. }
  268. void FbListWidget::loadFinished(bool ok)
  269. {
  270. m_list->setModel(new FbListModel(m_view.files(), this));
  271. m_list->reset();
  272. }