123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543 |
- #include "fb2imgs.hpp"
- #include <QAbstractListModel>
- #include <QBuffer>
- #include <QCryptographicHash>
- #include <QDialogButtonBox>
- #include <QFileDialog>
- #include <QFileInfo>
- #include <QImageReader>
- #include <QLabel>
- #include <QLineEdit>
- #include <QSplitter>
- #include <QUrl>
- #include <QVBoxLayout>
- #include <QWebFrame>
- #include <QTabWidget>
- #include <QtDebug>
- #include "fb2list.hpp"
- #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)
- {
- manager = qobject_cast<FbNetworkAccessManager*>(text->page()->networkAccessManager());
- }
- int FbImgsModel::columnCount(const QModelIndex &parent) const
- {
- Q_UNUSED(parent);
- return 4;
- }
- int FbImgsModel::rowCount(const QModelIndex &parent) const
- {
- return parent.isValid() ? 0 : manager->count();
- }
- 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();
- }
- QVariant FbImgsModel::data(const QModelIndex &index, int role) const
- {
- if (index.isValid()) {
- switch (role) {
- case Qt::DisplayRole: {
- return manager->info(index.row(), index.column());
- } break;
- case Qt::TextAlignmentRole: {
- switch (index.column()) {
- case 3: return Qt::AlignRight;
- default: return Qt::AlignLeft;
- }
- }
- }
- }
- return QVariant();
- }
- //---------------------------------------------------------------------------
- // 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 FbListView(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(showCurrent(QString)), SLOT(showCurrent(QString)));
- loadFinished();
- }
- void FbImgsWidget::loadFinished()
- {
- if (QAbstractItemModel *m = m_list->model()) m->deleteLater();
- 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::showCurrent(const QString &name)
- {
- QUrl url = m_text->url();
- url.setFragment(name);
- m_view->setHtml(imgHtml(url));
- }
|