Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/lintest/fb2edit.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/fb2imgs.cpp')
-rw-r--r--source/fb2imgs.cpp577
1 files changed, 577 insertions, 0 deletions
diff --git a/source/fb2imgs.cpp b/source/fb2imgs.cpp
new file mode 100644
index 0000000..69372b9
--- /dev/null
+++ b/source/fb2imgs.cpp
@@ -0,0 +1,577 @@
+#include "fb2imgs.hpp"
+
+#include <QAbstractListModel>
+#include <QBuffer>
+#include <QCryptographicHash>
+#include <QDialogButtonBox>
+#include <QFileDialog>
+#include <QFileInfo>
+#include <QImageReader>
+#include <QLabel>
+#include <QLineEdit>
+#include <QUrl>
+#include <QVBoxLayout>
+#include <QWebFrame>
+#include <QTabWidget>
+#include <QtDebug>
+
+#include "fb2page.hpp"
+#include "fb2text.hpp"
+#include "fb2utils.h"
+
+static QString imgHtml(const QUrl &url)
+{
+ return QString("<img src=\"%1\" valign=center align=center width=100%>").arg(url.toString());
+}
+
+//---------------------------------------------------------------------------
+// FbBinary
+//---------------------------------------------------------------------------
+
+FbBinary::FbBinary(const QString &name)
+ : QTemporaryFile()
+ , m_name(name)
+ , m_size(0)
+{
+}
+
+qint64 FbBinary::write(QByteArray &data)
+{
+ open();
+ if (m_hash.isEmpty()) m_hash = md5(data);
+ m_size = QTemporaryFile::write(data);
+ QBuffer buffer(&data);
+ buffer.open(QIODevice::ReadOnly);
+ m_type = QImageReader::imageFormat(&buffer);
+ close();
+ return m_size;
+}
+
+QString FbBinary::md5(const QByteArray &data)
+{
+ return QCryptographicHash::hash(data, QCryptographicHash::Md5).toBase64();
+}
+
+QByteArray FbBinary::data()
+{
+ open();
+ QByteArray data = readAll();
+ close();
+ return data;
+}
+
+//---------------------------------------------------------------------------
+// FbStore
+//---------------------------------------------------------------------------
+
+FbStore::FbStore(QObject *parent)
+ : QObject(parent)
+{
+}
+
+FbStore::~FbStore()
+{
+ FbTemporaryIterator it(*this);
+ while (it.hasNext()) delete it.next();
+}
+
+void FbStore::binary(const QString &name, const QByteArray &data)
+{
+ set(name, data);
+}
+
+QString FbStore::add(const QString &path, QByteArray &data)
+{
+ QString hash = FbBinary::md5(data);
+ QString name = this->name(hash);
+ if (name.isEmpty()) {
+ name = newName(path);
+ FbBinary * temp = new FbBinary(name);
+ temp->setHash(hash);
+ temp->write(data);
+ append(temp);
+ }
+ return name;
+}
+
+QString FbStore::newName(const QString &path)
+{
+ QFileInfo info(path);
+ QString name = info.fileName();
+ if (!exists(name)) return name;
+ QString base = info.baseName();
+ QString suff = info.suffix();
+ for (int i = 1; ; i++) {
+ QString name = QString("%1(%2).%3").arg(base).arg(i).arg(suff);
+ if (exists(name)) continue;
+ return name;
+ }
+}
+
+FbBinary * FbStore::get(const QString &name) const
+{
+ FbTemporaryIterator it(*this);
+ while (it.hasNext()) {
+ FbBinary * file = it.next();
+ if (file->name() == name) return file;
+ }
+ return NULL;
+}
+
+QByteArray FbStore::data(const QString &name) const
+{
+ FbTemporaryIterator it(*this);
+ while (it.hasNext()) {
+ FbBinary *file = it.next();
+ if (file->name() == name) return file->data();
+ }
+ return QByteArray();
+}
+
+const QString & FbStore::set(const QString &name, QByteArray data, const QString &hash)
+{
+ FbBinary * file = get(name);
+ if (!file) append(file = new FbBinary(name));
+ file->setHash(hash);
+ file->write(data);
+ return file->hash();
+}
+
+QString FbStore::name(const QString &hash) const
+{
+ FbTemporaryIterator it(*this);
+ while (it.hasNext()) {
+ FbBinary *file = it.next();
+ if (file->hash() == hash) return file->name();
+ }
+ return QString();
+}
+
+bool FbStore::exists(const QString &name) const
+{
+ FbTemporaryIterator it(*this);
+ while (it.hasNext()) {
+ FbBinary *file = it.next();
+ if (file->name() == name) return true;
+ }
+ return false;
+}
+
+#if 0
+
+//---------------------------------------------------------------------------
+// FbNetworkDiskCache
+//---------------------------------------------------------------------------
+
+QNetworkCacheMetaData FbNetworkDiskCache::metaData(const QUrl &url)
+{
+ qCritical() << url.toString();
+ return QNetworkDiskCache::metaData(url);
+}
+
+QIODevice * FbNetworkDiskCache::data(const QUrl &url)
+{
+ qCritical() << url.toString();
+ return QNetworkDiskCache::data(url);
+}
+
+#endif
+
+//---------------------------------------------------------------------------
+// FbImageReply
+//---------------------------------------------------------------------------
+
+FbImageReply::FbImageReply(QNetworkAccessManager::Operation op, const QNetworkRequest &request, const QByteArray &data)
+ : QNetworkReply()
+ , content(data)
+ , offset(0)
+{
+ setOperation(op);
+ setRequest(request);
+ setUrl(request.url());
+ open(ReadOnly | Unbuffered);
+ setHeader(QNetworkRequest::ContentLengthHeader, QVariant(content.size()));
+ setAttribute(QNetworkRequest::CacheSaveControlAttribute, QVariant(false));
+ QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
+ QMetaObject::invokeMethod(this, "finished", Qt::QueuedConnection);
+}
+
+qint64 FbImageReply::readData(char *data, qint64 maxSize)
+{
+ if (offset >= content.size()) return -1;
+ QMetaObject::invokeMethod(this, "readyRead", Qt::QueuedConnection);
+ qint64 number = qMin(maxSize, content.size() - offset);
+ memcpy(data, content.constData() + offset, number);
+ offset += number;
+ return number;
+}
+
+//---------------------------------------------------------------------------
+// FbNetworkAccessManager
+//
+// http://doc.trolltech.com/qq/32/qq32-webkit-protocols.html
+//---------------------------------------------------------------------------
+
+FbNetworkAccessManager::FbNetworkAccessManager(QObject *parent)
+ : QNetworkAccessManager(parent)
+ , m_store(new FbStore(this))
+{
+}
+
+void FbNetworkAccessManager::setStore(const QUrl url, FbStore *store)
+{
+ m_path = url.path();
+ if (m_store) delete m_store;
+ if (!store) store = new FbStore(this);
+ store->setParent(this);
+ m_store = store;
+}
+
+QNetworkReply * FbNetworkAccessManager::createRequest(Operation op, const QNetworkRequest &request, QIODevice *outgoingData)
+{
+ if (m_store) {
+ const QUrl &url = request.url();
+ const QString path = url.path();
+ if (url.scheme() == "fb2" && path == m_path) {
+ QString name = request.url().fragment();
+ QByteArray data = m_store->data(name);
+ return new FbImageReply(op, request, data);
+ }
+ }
+ return QNetworkAccessManager::createRequest(op, request, outgoingData);
+}
+
+QVariant FbNetworkAccessManager::info(int row, int col) const
+{
+ if (!m_store) return QVariant();
+ if (0 <= row && row < count()) {
+ FbBinary *file = m_store->at(row);
+ switch (col) {
+ case 2: return file->type();
+ case 3: return file->size();
+ }
+ return m_store->at(row)->name();
+ }
+ return QVariant();
+}
+
+QByteArray FbNetworkAccessManager::data(int index) const
+{
+ if (!m_store) return QByteArray();
+ if (0 <= index && index < count()) {
+ return m_store->at(index)->data();
+ }
+ return QByteArray();
+}
+
+//---------------------------------------------------------------------------
+// FbComboCtrl
+//---------------------------------------------------------------------------
+
+FbComboCtrl::FbComboCtrl(QWidget *parent)
+ : QLineEdit(parent)
+{
+ button = new QToolButton(this);
+ button->setCursor(Qt::ArrowCursor);
+ button->setFocusPolicy(Qt::NoFocus);
+ connect(button, SIGNAL(clicked()), SIGNAL(popup()));
+ QHBoxLayout *layout = new QHBoxLayout(this);
+ layout->addWidget(button, 0, Qt::AlignRight);
+ layout->setSpacing(0);
+ layout->setMargin(0);
+}
+
+void FbComboCtrl::resizeEvent(QResizeEvent* event)
+{
+ QLineEdit::resizeEvent(event);
+ QMargins margins(0, 0, button->width(), 0);
+ setTextMargins(margins);
+}
+
+void FbComboCtrl::setIcon(const QIcon &icon)
+{
+ button->setIcon(icon);
+}
+
+//---------------------------------------------------------------------------
+// FbImageDlg::FbTab
+//---------------------------------------------------------------------------
+
+FbImageDlg::FbTab::FbTab(QWidget* parent, QAbstractItemModel *model)
+ : QWidget(parent)
+ , combo(0)
+ , edit(0)
+{
+ QGridLayout * layout = new QGridLayout(this);
+
+ label = new QLabel(this);
+ label->setText(tr("File name:"));
+ layout->addWidget(label, 0, 0, 1, 1);
+
+ QWidget *control;
+ if (model) {
+ control = combo = new QComboBox(this);
+ combo->setModel(model);
+ } else {
+ control = edit = new FbComboCtrl(this);
+ }
+
+ QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ control->setSizePolicy(sizePolicy);
+ layout->addWidget(control, 0, 1, 1, 1);
+
+ QFrame *frame = new FbTextFrame(this);
+ frame->setMinimumSize(QSize(300, 200));
+ layout->addWidget(frame, 1, 0, 1, 2);
+
+ preview = new QWebView(this);
+ frame->layout()->addWidget(preview);
+}
+
+//---------------------------------------------------------------------------
+// FbImageDlg
+//---------------------------------------------------------------------------
+
+FbImageDlg::FbImageDlg(FbTextEdit *text)
+ : QDialog(text)
+ , owner(text)
+ , tabFile(0)
+ , tabPict(0)
+{
+ setWindowTitle(tr("Insert picture"));
+
+ QLayout *layout = new QVBoxLayout(this);
+
+ notebook = new QTabWidget(this);
+ layout->addWidget(notebook);
+
+ QDialogButtonBox *buttons = new QDialogButtonBox(this);
+ buttons->setOrientation(Qt::Horizontal);
+ buttons->setStandardButtons(QDialogButtonBox::Cancel|QDialogButtonBox::Ok);
+ layout->addWidget(buttons);
+
+ connect(buttons, SIGNAL(accepted()), SLOT(accept()));
+ connect(buttons, SIGNAL(rejected()), SLOT(reject()));
+ connect(notebook, SIGNAL(currentChanged(int)), SLOT(notebookChanged(int)));
+
+ tabFile = new FbTab(notebook);
+ tabFile->edit->setIcon(FbIcon("document-open"));
+ tabFile->preview->setHtml(QString());
+ connect(tabFile->edit, SIGNAL(textChanged(QString)), SLOT(filenameChanged(QString)));
+ connect(tabFile->edit, SIGNAL(popup()), SLOT(selectFile()));
+ notebook->addTab(tabFile, tr("Select file"));
+
+ if (text->store()->count()) {
+ FbImgsModel *model = new FbImgsModel(text, this);
+ tabPict = new FbTab(notebook, model);
+ tabPict->combo->setCurrentIndex(0);
+ tabPict->preview->setHtml(QString(), text->url());
+ tabPict->preview->page()->setNetworkAccessManager(text->page()->networkAccessManager());
+ notebook->addTab(tabPict, tr("From collection"));
+ connect(tabPict->combo, SIGNAL(activated(QString)), SLOT(pictureActivated(QString)));
+ }
+
+ tabFile->edit->setFocus();
+ resize(minimumSizeHint());
+}
+
+void FbImageDlg::notebookChanged(int index)
+{
+ if (index) {
+ disconnect(notebook, SIGNAL(currentChanged(int)), this, SLOT(notebookChanged(int)));
+ if (tabPict) pictureActivated(tabPict->combo->itemText(0));
+ }
+}
+
+void FbImageDlg::selectFile()
+{
+ QString filters;
+ filters += tr("Common Graphics (*.png *.jpg *.jpeg *.gif)") += ";;";
+ filters += tr("Portable Network Graphics (PNG) (*.png)") += ";;";
+ filters += tr("JPEG (*.jpg *.jpeg)") += ";;";
+ filters += tr("Graphics Interchange Format (*.gif)") += ";;";
+ filters += tr("All Files (*)");
+ QWidget *p = qobject_cast<QWidget*>(parent());
+ QString path = QFileDialog::getOpenFileName(p, tr("Insert image..."), QString(), filters);
+ if (path.isEmpty()) return;
+ tabFile->edit->setText(path);
+}
+
+void FbImageDlg::filenameChanged(const QString & text)
+{
+ if (QFileInfo(text).exists()) {
+ QUrl url = QUrl::fromLocalFile(text);
+ preview(tabFile->preview, url);
+ } else {
+ tabFile->preview->setHtml(QString());
+ }
+}
+
+void FbImageDlg::pictureActivated(const QString & text)
+{
+ QUrl url = tabPict->preview->url();
+ url.setFragment(text);
+ preview(tabPict->preview, url);
+}
+
+void FbImageDlg::preview(QWebView *preview, const QUrl &url)
+{
+ preview->setHtml(imgHtml(url), preview->url());
+}
+
+QString FbImageDlg::result() const
+{
+ if (tabPict && notebook->currentWidget() == tabPict) {
+ return tabPict->combo->currentText();
+ } else if (notebook->currentWidget() == tabFile) {
+ QString path = tabFile->edit->text();
+ QFile file(path);
+ if (file.open(QIODevice::ReadOnly)) {
+ QNetworkAccessManager *m = owner->page()->networkAccessManager();
+ FbNetworkAccessManager *manager = qobject_cast<FbNetworkAccessManager*>(m);
+ QByteArray data = file.readAll();
+ return manager->add(path, data);
+ }
+ }
+ return QString();
+}
+
+//---------------------------------------------------------------------------
+// FbImgsModel
+//---------------------------------------------------------------------------
+
+FbImgsModel::FbImgsModel(FbTextEdit *text, QObject *parent)
+ : QAbstractListModel(parent)
+ , m_text(text)
+{
+}
+
+int FbImgsModel::columnCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ return 4;
+}
+
+int FbImgsModel::rowCount(const QModelIndex &parent) const
+{
+ Q_UNUSED(parent);
+ FbNetworkAccessManager * f = files();
+ return f ? f->count() : 0;
+}
+
+QVariant FbImgsModel::headerData(int section, Qt::Orientation orientation, int role) const
+{
+ if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
+ switch (section) {
+ case 1: return tr("File name");
+ case 2: return tr("Type");
+ case 3: return tr("Size");
+ }
+ }
+ return QVariant();
+}
+
+FbNetworkAccessManager * FbImgsModel::files() const
+{
+ if (FbTextPage *page = qobject_cast<FbTextPage*>(m_text->page())) {
+ return qobject_cast<FbNetworkAccessManager*>(page->networkAccessManager());
+ } else {
+ return 0;
+ }
+}
+
+QVariant FbImgsModel::data(const QModelIndex &index, int role) const
+{
+ if (index.isValid()) {
+ switch (role) {
+ case Qt::DisplayRole: {
+ FbNetworkAccessManager * f = files();
+ return f ? f->info(index.row(), index.column()) : QVariant();
+ } break;
+ case Qt::TextAlignmentRole: {
+ switch (index.column()) {
+ case 3: return Qt::AlignRight;
+ default: return Qt::AlignLeft;
+ }
+ }
+ }
+ }
+ return QVariant();
+}
+
+//---------------------------------------------------------------------------
+// FbImgsView
+//---------------------------------------------------------------------------
+
+#include <QSplitter>
+#include <QScrollArea>
+
+FbImgsView::FbImgsView(QWidget *parent)
+ : QTreeView(parent)
+{
+ setAllColumnsShowFocus(true);
+}
+
+void FbImgsView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
+{
+ QTreeView::currentChanged(current, previous);
+ QModelIndex index = model()->index(current.row(), 0);
+ emit showImage(model()->data(index).toString());
+}
+
+FbImgsModel * FbImgsView::model() const
+{
+ return qobject_cast<FbImgsModel*>(QTreeView::model());
+}
+
+//---------------------------------------------------------------------------
+// FbImgsWidget
+//---------------------------------------------------------------------------
+
+FbImgsWidget::FbImgsWidget(FbTextEdit *text, QWidget* parent)
+ : QWidget(parent)
+ , m_text(text)
+{
+ QVBoxLayout *layout = new QVBoxLayout(this);
+ layout->setSpacing(0);
+ layout->setContentsMargins(0, 0, 0, 0);
+
+ QSplitter *splitter = new QSplitter(Qt::Vertical, this);
+
+ m_list = new FbImgsView(splitter);
+ splitter->addWidget(m_list);
+
+ FbTextFrame *frame = new FbTextFrame(splitter);
+ splitter->addWidget(frame);
+
+ m_view = new FbTextBase(frame);
+ m_view->page()->setNetworkAccessManager(text->page()->networkAccessManager());
+ frame->layout()->addWidget(m_view);
+
+ splitter->setSizes(QList<int>() << 100 << 100);
+
+ layout->addWidget(splitter);
+
+ connect(m_text, SIGNAL(loadFinished(bool)), SLOT(loadFinished()));
+ connect(m_list, SIGNAL(showImage(QString)), SLOT(showImage(QString)));
+ loadFinished();
+}
+
+void FbImgsWidget::loadFinished()
+{
+ m_view->load(QUrl());
+ m_list->setModel(new FbImgsModel(m_text, this));
+ m_list->reset();
+ m_list->resizeColumnToContents(1);
+ m_list->resizeColumnToContents(2);
+ m_list->resizeColumnToContents(3);
+ m_list->setColumnHidden(0, true);
+}
+
+void FbImgsWidget::showImage(const QString &name)
+{
+ QUrl url = m_text->url();
+ url.setFragment(name);
+ m_view->setHtml(imgHtml(url));
+}
+