summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ChatPage.cc31
-rw-r--r--src/MatrixClient.cc44
-rw-r--r--src/TextInputWidget.cc65
-rw-r--r--src/dialogs/PreviewImageOverlay.cc142
-rw-r--r--src/timeline/TimelineView.cc8
-rw-r--r--src/timeline/TimelineViewManager.cc7
-rw-r--r--src/timeline/widgets/AudioItem.cc6
-rw-r--r--src/timeline/widgets/FileItem.cc6
-rw-r--r--src/timeline/widgets/ImageItem.cc17
-rw-r--r--src/timeline/widgets/VideoItem.cc2
10 files changed, 278 insertions, 50 deletions
diff --git a/src/ChatPage.cc b/src/ChatPage.cc
index ebdec835..f49c0a08 100644
--- a/src/ChatPage.cc
+++ b/src/ChatPage.cc
@@ -228,17 +228,26 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client,
                 client_.data(),
                 &MatrixClient::joinRoom);
 
-        connect(text_input_, &TextInputWidget::uploadImage, this, [=](QString filename) {
-                client_->uploadImage(current_room_, filename);
-        });
+        connect(text_input_,
+                &TextInputWidget::uploadImage,
+                this,
+                [=](QSharedPointer<QIODevice> data, const QString &fn) {
+                        client_->uploadImage(current_room_, data, fn);
+                });
 
-        connect(text_input_, &TextInputWidget::uploadFile, this, [=](QString filename) {
-                client_->uploadFile(current_room_, filename);
-        });
+        connect(text_input_,
+                &TextInputWidget::uploadFile,
+                this,
+                [=](QSharedPointer<QIODevice> data, const QString &fn) {
+                        client_->uploadFile(current_room_, data, fn);
+                });
 
-        connect(text_input_, &TextInputWidget::uploadAudio, this, [=](QString filename) {
-                client_->uploadAudio(current_room_, filename);
-        });
+        connect(text_input_,
+                &TextInputWidget::uploadAudio,
+                this,
+                [=](QSharedPointer<QIODevice> data, const QString &fn) {
+                        client_->uploadAudio(current_room_, data, fn);
+                });
 
         connect(
           client_.data(), &MatrixClient::roomCreationFailed, this, &ChatPage::showNotification);
@@ -246,9 +255,9 @@ ChatPage::ChatPage(QSharedPointer<MatrixClient> client,
         connect(client_.data(),
                 &MatrixClient::imageUploaded,
                 this,
-                [=](QString roomid, QString filename, QString url) {
+                [=](QString roomid, QSharedPointer<QIODevice> data, QString filename, QString url) {
                         text_input_->hideUploadSpinner();
-                        view_manager_->queueImageMessage(roomid, filename, url);
+                        view_manager_->queueImageMessage(roomid, data, filename, url);
                 });
         connect(client_.data(),
                 &MatrixClient::fileUploaded,
diff --git a/src/MatrixClient.cc b/src/MatrixClient.cc
index 72467385..67203d59 100644
--- a/src/MatrixClient.cc
+++ b/src/MatrixClient.cc
@@ -821,14 +821,16 @@ MatrixClient::messages(const QString &roomid, const QString &from_token, int lim
 }
 
 void
-MatrixClient::uploadImage(const QString &roomid, const QString &filename)
+MatrixClient::uploadImage(const QString &roomid,
+                          const QSharedPointer<QIODevice> data,
+                          const QString &filename)
 {
-        auto reply = makeUploadRequest(filename);
+        auto reply = makeUploadRequest(data);
 
         if (reply == nullptr)
                 return;
 
-        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, filename]() {
+        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, data, filename]() {
                 reply->deleteLater();
 
                 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -838,12 +840,12 @@ MatrixClient::uploadImage(const QString &roomid, const QString &filename)
                         return;
                 }
 
-                auto data = reply->readAll();
+                auto res_data = reply->readAll();
 
-                if (data.isEmpty())
+                if (res_data.isEmpty())
                         return;
 
-                auto json = QJsonDocument::fromJson(data);
+                auto json = QJsonDocument::fromJson(res_data);
 
                 if (!json.isObject()) {
                         qDebug() << "Media upload: Response is not a json object.";
@@ -857,16 +859,18 @@ MatrixClient::uploadImage(const QString &roomid, const QString &filename)
                         return;
                 }
 
-                emit imageUploaded(roomid, filename, object.value("content_uri").toString());
+                emit imageUploaded(roomid, data, filename, object.value("content_uri").toString());
         });
 }
 
 void
-MatrixClient::uploadFile(const QString &roomid, const QString &filename)
+MatrixClient::uploadFile(const QString &roomid,
+                         const QSharedPointer<QIODevice> data,
+                         const QString &filename)
 {
-        auto reply = makeUploadRequest(filename);
+        auto reply = makeUploadRequest(data);
 
-        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, filename]() {
+        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, data, filename]() {
                 reply->deleteLater();
 
                 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -900,11 +904,13 @@ MatrixClient::uploadFile(const QString &roomid, const QString &filename)
 }
 
 void
-MatrixClient::uploadAudio(const QString &roomid, const QString &filename)
+MatrixClient::uploadAudio(const QString &roomid,
+                          const QSharedPointer<QIODevice> data,
+                          const QString &filename)
 {
-        auto reply = makeUploadRequest(filename);
+        auto reply = makeUploadRequest(data);
 
-        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, filename]() {
+        connect(reply, &QNetworkReply::finished, this, [this, reply, roomid, data, filename]() {
                 reply->deleteLater();
 
                 int status = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
@@ -1158,7 +1164,7 @@ MatrixClient::readEvent(const QString &room_id, const QString &event_id)
 }
 
 QNetworkReply *
-MatrixClient::makeUploadRequest(const QString &filename)
+MatrixClient::makeUploadRequest(QSharedPointer<QIODevice> iodev)
 {
         QUrlQuery query;
         query.addQueryItem("access_token", token_);
@@ -1167,20 +1173,18 @@ MatrixClient::makeUploadRequest(const QString &filename)
         endpoint.setPath(mediaApiUrl_ + "/upload");
         endpoint.setQuery(query);
 
-        QFile file(filename);
-        if (!file.open(QIODevice::ReadWrite)) {
-                qDebug() << "Error while reading" << filename;
+        if (!iodev->open(QIODevice::ReadOnly)) {
+                qWarning() << "Error while reading device:" << iodev->errorString();
                 return nullptr;
         }
 
         QMimeDatabase db;
-        QMimeType mime = db.mimeTypeForFile(filename, QMimeDatabase::MatchContent);
+        QMimeType mime = db.mimeTypeForData(iodev.data());
 
         QNetworkRequest request(QString(endpoint.toEncoded()));
-        request.setHeader(QNetworkRequest::ContentLengthHeader, file.size());
         request.setHeader(QNetworkRequest::ContentTypeHeader, mime.name());
 
-        auto reply = post(request, file.readAll());
+        auto reply = post(request, iodev.data());
 
         return reply;
 }
diff --git a/src/TextInputWidget.cc b/src/TextInputWidget.cc
index dc2bebe7..f9198c78 100644
--- a/src/TextInputWidget.cc
+++ b/src/TextInputWidget.cc
@@ -16,10 +16,13 @@
  */
 
 #include <QAbstractTextDocumentLayout>
+#include <QApplication>
+#include <QBuffer>
+#include <QClipboard>
 #include <QDebug>
-#include <QFile>
 #include <QFileDialog>
 #include <QImageReader>
+#include <QMimeData>
 #include <QMimeDatabase>
 #include <QMimeType>
 #include <QPainter>
@@ -33,6 +36,7 @@ static constexpr size_t INPUT_HISTORY_SIZE = 127;
 FilteredTextEdit::FilteredTextEdit(QWidget *parent)
   : QTextEdit{parent}
   , history_index_{0}
+  , previewDialog_{parent}
 {
         connect(document()->documentLayout(),
                 &QAbstractTextDocumentLayout::documentSizeChanged,
@@ -50,6 +54,12 @@ FilteredTextEdit::FilteredTextEdit(QWidget *parent)
         typingTimer_->setSingleShot(true);
 
         connect(typingTimer_, &QTimer::timeout, this, &FilteredTextEdit::stopTyping);
+        connect(&previewDialog_,
+                &dialogs::PreviewImageOverlay::confirmImageUpload,
+                this,
+                &FilteredTextEdit::receiveImage);
+
+        previewDialog_.hide();
 }
 
 void
@@ -101,6 +111,42 @@ FilteredTextEdit::keyPressEvent(QKeyEvent *event)
         }
 }
 
+bool
+FilteredTextEdit::canInsertFromMimeData(const QMimeData *source) const
+{
+        return (source->hasImage() || QTextEdit::canInsertFromMimeData(source));
+}
+
+void
+FilteredTextEdit::insertFromMimeData(const QMimeData *source)
+{
+        if (source->hasImage()) {
+                const auto formats = source->formats();
+                const auto idx     = formats.indexOf(
+                  QRegularExpression{"image/.+", QRegularExpression::CaseInsensitiveOption});
+
+                // Note: in the future we may want to look into what the best choice is from the
+                // formats list. For now we will default to PNG format.
+                QString type = "png";
+                if (idx != -1) {
+                        type = formats.at(idx).split('/')[1];
+                }
+
+                // Encode raw pixel data of image.
+                QByteArray data = source->data("image/" + type);
+                previewDialog_.setImageAndCreate(data, type);
+                previewDialog_.show();
+        } else if (source->hasFormat("x-special/gnome-copied-files") &&
+                   QImageReader{source->text()}.canRead()) {
+                // Special case for X11 users. See "Notes for X11 Users" in source.
+                // Source: http://doc.qt.io/qt-5/qclipboard.html
+                previewDialog_.setImageAndCreate(source->text());
+                previewDialog_.show();
+        } else {
+                QTextEdit::insertFromMimeData(source);
+        }
+}
+
 void
 FilteredTextEdit::stopTyping()
 {
@@ -146,6 +192,7 @@ FilteredTextEdit::submit()
         history_index_ = 0;
 
         QString text = toPlainText();
+
         if (text.startsWith('/')) {
                 int command_end = text.indexOf(' ');
                 if (command_end == -1)
@@ -170,6 +217,14 @@ FilteredTextEdit::textChanged()
         working_history_[history_index_] = toPlainText();
 }
 
+void
+FilteredTextEdit::receiveImage(const QByteArray img, const QString &img_name)
+{
+        QSharedPointer<QBuffer> buffer{new QBuffer{this}};
+        buffer->setData(img);
+        emit image(buffer, img_name);
+}
+
 TextInputWidget::TextInputWidget(QWidget *parent)
   : QFrame(parent)
 {
@@ -231,6 +286,7 @@ TextInputWidget::TextInputWidget(QWidget *parent)
         connect(sendFileBtn_, SIGNAL(clicked()), this, SLOT(openFileSelection()));
         connect(input_, &FilteredTextEdit::message, this, &TextInputWidget::sendTextMessage);
         connect(input_, &FilteredTextEdit::command, this, &TextInputWidget::command);
+        connect(input_, &FilteredTextEdit::image, this, &TextInputWidget::uploadImage);
         connect(emojiBtn_,
                 SIGNAL(emojiSelected(const QString &)),
                 this,
@@ -289,12 +345,13 @@ TextInputWidget::openFileSelection()
 
         const auto format = mime.name().split("/")[0];
 
+        QSharedPointer<QFile> file{new QFile{fileName, this}};
         if (format == "image")
-                emit uploadImage(fileName);
+                emit uploadImage(file, fileName);
         else if (format == "audio")
-                emit uploadAudio(fileName);
+                emit uploadAudio(file, fileName);
         else
-                emit uploadFile(fileName);
+                emit uploadFile(file, fileName);
 
         showUploadSpinner();
 }
diff --git a/src/dialogs/PreviewImageOverlay.cc b/src/dialogs/PreviewImageOverlay.cc
new file mode 100644
index 00000000..31ef00ed
--- /dev/null
+++ b/src/dialogs/PreviewImageOverlay.cc
@@ -0,0 +1,142 @@
+/*
+ * nheko Copyright (C) 2017  Konstantinos Sideris <siderisk@auth.gr>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <QApplication>
+#include <QBuffer>
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QHBoxLayout>
+#include <QVBoxLayout>
+
+#include "Config.h"
+
+#include "dialogs/PreviewImageOverlay.h"
+
+using namespace dialogs;
+
+static constexpr const char *DEFAULT = "Upload image?";
+static constexpr const char *ERROR   = "Failed to load image type '%1'. Continue upload?";
+
+PreviewImageOverlay::PreviewImageOverlay(QWidget *parent)
+  : QWidget{parent}
+  , titleLabel_{tr(DEFAULT), this}
+  , imageLabel_{this}
+  , imageName_{tr("clipboard"), this}
+  , upload_{tr("Upload"), this}
+  , cancel_{tr("Cancel"), this}
+{
+        auto hlayout = new QHBoxLayout;
+        hlayout->addWidget(&upload_);
+        hlayout->addWidget(&cancel_);
+
+        auto vlayout = new QVBoxLayout{this};
+        vlayout->addWidget(&titleLabel_);
+        vlayout->addWidget(&imageLabel_);
+        vlayout->addWidget(&imageName_);
+        vlayout->addLayout(hlayout);
+
+        connect(&upload_, &QPushButton::clicked, [&]() {
+                emit confirmImageUpload(imageData_, imageName_.text());
+                close();
+        });
+        connect(&cancel_, &QPushButton::clicked, [&]() { close(); });
+}
+
+void
+PreviewImageOverlay::init()
+{
+        auto window   = QApplication::activeWindow();
+        auto winsize  = window->frameGeometry().size();
+        auto center   = window->frameGeometry().center();
+        auto img_size = image_.size();
+
+        imageName_.setText(QFileInfo{imagePath_}.fileName());
+
+        setAutoFillBackground(true);
+        setWindowFlags(Qt::Tool | Qt::WindowStaysOnTopHint);
+        setWindowModality(Qt::WindowModal);
+
+        titleLabel_.setStyleSheet(
+          QString{"font-weight: bold; font-size: %1px;"}.arg(conf::headerFontSize));
+        titleLabel_.setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
+        titleLabel_.setAlignment(Qt::AlignCenter);
+        imageLabel_.setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Maximum);
+        imageLabel_.setAlignment(Qt::AlignCenter);
+        imageName_.setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+        imageName_.setAlignment(Qt::AlignCenter);
+        upload_.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+        cancel_.setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+        upload_.setFontSize(conf::btn::fontSize);
+        cancel_.setFontSize(conf::btn::fontSize);
+
+        // Scale image preview to the size of the current window if it is larger.
+        if ((img_size.height() * img_size.width()) > (winsize.height() * winsize.width())) {
+                imageLabel_.setPixmap(image_.scaled(winsize, Qt::KeepAspectRatio));
+        } else {
+                imageLabel_.setPixmap(image_);
+                move(center.x() - (width() * 0.5), center.y() - (height() * 0.5));
+        }
+        imageLabel_.setScaledContents(false);
+
+        raise();
+}
+
+void
+PreviewImageOverlay::setImageAndCreate(const QByteArray data, const QString &type)
+{
+        imageData_  = data;
+        imagePath_  = "clipboard." + type;
+        auto loaded = image_.loadFromData(imageData_);
+        if (!loaded) {
+                titleLabel_.setText(QString{tr(ERROR)}.arg(type));
+        } else {
+                titleLabel_.setText(tr(DEFAULT));
+        }
+
+        init();
+}
+
+void
+PreviewImageOverlay::setImageAndCreate(const QString &path)
+{
+        QFile file{path};
+        imagePath_ = path;
+
+        if (!file.open(QIODevice::ReadOnly)) {
+                qWarning() << "Failed to open image from:" << path;
+                qWarning() << "Reason:" << file.errorString();
+                close();
+                return;
+        }
+
+        if ((imageData_ = file.readAll()).isEmpty()) {
+                qWarning() << "Failed to read image:" << file.errorString();
+                close();
+                return;
+        }
+
+        auto loaded = image_.loadFromData(imageData_);
+        if (!loaded) {
+                auto t = QFileInfo{path}.suffix();
+                titleLabel_.setText(QString{tr(ERROR)}.arg(t));
+        } else {
+                titleLabel_.setText(tr(DEFAULT));
+        }
+
+        init();
+}
diff --git a/src/timeline/TimelineView.cc b/src/timeline/TimelineView.cc
index d21f30f0..75ce8141 100644
--- a/src/timeline/TimelineView.cc
+++ b/src/timeline/TimelineView.cc
@@ -510,12 +510,8 @@ TimelineView::sendNextPendingMessage()
         case mtx::events::MessageType::Image:
         case mtx::events::MessageType::File:
                 // FIXME: Improve the API
-                client_->sendRoomMessage(m.ty,
-                                         m.txn_id,
-                                         room_id_,
-                                         QFileInfo(m.filename).fileName(),
-                                         QFileInfo(m.filename),
-                                         m.body);
+                client_->sendRoomMessage(
+                  m.ty, m.txn_id, room_id_, m.filename, QFileInfo(m.filename), m.body);
                 break;
         default:
                 client_->sendRoomMessage(m.ty, m.txn_id, room_id_, m.body, QFileInfo());
diff --git a/src/timeline/TimelineViewManager.cc b/src/timeline/TimelineViewManager.cc
index de1e1e32..65c9ac83 100644
--- a/src/timeline/TimelineViewManager.cc
+++ b/src/timeline/TimelineViewManager.cc
@@ -85,6 +85,7 @@ TimelineViewManager::queueEmoteMessage(const QString &msg)
 
 void
 TimelineViewManager::queueImageMessage(const QString &roomid,
+                                       const QSharedPointer<QIODevice> data,
                                        const QString &filename,
                                        const QString &url)
 {
@@ -95,7 +96,7 @@ TimelineViewManager::queueImageMessage(const QString &roomid,
 
         auto view = views_[roomid];
 
-        view->addUserMessage<ImageItem, mtx::events::MessageType::Image>(url, filename);
+        view->addUserMessage<ImageItem, mtx::events::MessageType::Image>(url, data, filename);
 }
 
 void
@@ -110,7 +111,7 @@ TimelineViewManager::queueFileMessage(const QString &roomid,
 
         auto view = views_[roomid];
 
-        view->addUserMessage<FileItem, mtx::events::MessageType::File>(url, filename);
+        view->addUserMessage<FileItem, mtx::events::MessageType::File>(url, nullptr, filename);
 }
 
 void
@@ -125,7 +126,7 @@ TimelineViewManager::queueAudioMessage(const QString &roomid,
 
         auto view = views_[roomid];
 
-        view->addUserMessage<AudioItem, mtx::events::MessageType::Audio>(url, filename);
+        view->addUserMessage<AudioItem, mtx::events::MessageType::Audio>(url, nullptr, filename);
 }
 
 void
diff --git a/src/timeline/widgets/AudioItem.cc b/src/timeline/widgets/AudioItem.cc
index 5d9dd77b..e84cbb3a 100644
--- a/src/timeline/widgets/AudioItem.cc
+++ b/src/timeline/widgets/AudioItem.cc
@@ -89,14 +89,16 @@ AudioItem::AudioItem(QSharedPointer<MatrixClient> client,
 
 AudioItem::AudioItem(QSharedPointer<MatrixClient> client,
                      const QString &url,
+                     const QSharedPointer<QIODevice> data,
                      const QString &filename,
                      QWidget *parent)
   : QWidget(parent)
   , url_{url}
-  , text_{QFileInfo(filename).fileName()}
+  , text_{QFileInfo{filename}.fileName()}
   , client_{client}
 {
-        readableFileSize_ = calculateFileSize(QFileInfo(filename).size());
+        Q_UNUSED(data);
+        readableFileSize_ = calculateFileSize(QFileInfo{filename}.size());
 
         init();
 }
diff --git a/src/timeline/widgets/FileItem.cc b/src/timeline/widgets/FileItem.cc
index 3c38dc31..a6159309 100644
--- a/src/timeline/widgets/FileItem.cc
+++ b/src/timeline/widgets/FileItem.cc
@@ -76,14 +76,16 @@ FileItem::FileItem(QSharedPointer<MatrixClient> client,
 
 FileItem::FileItem(QSharedPointer<MatrixClient> client,
                    const QString &url,
+                   const QSharedPointer<QIODevice> data,
                    const QString &filename,
                    QWidget *parent)
   : QWidget(parent)
   , url_{url}
-  , text_{QFileInfo(filename).fileName()}
+  , text_{QFileInfo{filename}.fileName()}
   , client_{client}
 {
-        readableFileSize_ = calculateFileSize(QFileInfo(filename).size());
+        Q_UNUSED(data);
+        readableFileSize_ = calculateFileSize(QFileInfo{filename}.size());
 
         init();
 }
diff --git a/src/timeline/widgets/ImageItem.cc b/src/timeline/widgets/ImageItem.cc
index 9038456d..48a4c1eb 100644
--- a/src/timeline/widgets/ImageItem.cc
+++ b/src/timeline/widgets/ImageItem.cc
@@ -61,11 +61,12 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
 
 ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
                      const QString &url,
+                     const QSharedPointer<QIODevice> data,
                      const QString &filename,
                      QWidget *parent)
   : QWidget(parent)
   , url_{url}
-  , text_{QFileInfo(filename).fileName()}
+  , text_{filename}
   , client_{client}
 {
         setMouseTracking(true);
@@ -83,7 +84,19 @@ ImageItem::ImageItem(QSharedPointer<MatrixClient> client,
         url_                 = QString("%1/_matrix/media/r0/download/%2")
                  .arg(client_.data()->getHomeServer().toString(), media_params);
 
-        setImage(QPixmap(filename));
+        if (data.isNull()) {
+                qWarning() << "No image data to display";
+                return;
+        }
+
+        if (data->reset()) {
+                QPixmap p;
+                p.loadFromData(data->readAll());
+                setImage(p);
+        } else {
+                qWarning() << "Failed to seek to beginning of device:" << data->errorString();
+                return;
+        }
 }
 
 void
diff --git a/src/timeline/widgets/VideoItem.cc b/src/timeline/widgets/VideoItem.cc
index b3987b83..b46dff7b 100644
--- a/src/timeline/widgets/VideoItem.cc
+++ b/src/timeline/widgets/VideoItem.cc
@@ -66,6 +66,7 @@ VideoItem::VideoItem(QSharedPointer<MatrixClient> client,
 
 VideoItem::VideoItem(QSharedPointer<MatrixClient> client,
                      const QString &url,
+                     const QSharedPointer<QIODevice> data,
                      const QString &filename,
                      QWidget *parent)
   : QWidget(parent)
@@ -73,6 +74,7 @@ VideoItem::VideoItem(QSharedPointer<MatrixClient> client,
   , text_{QFileInfo(filename).fileName()}
   , client_{client}
 {
+        Q_UNUSED(data);
         readableFileSize_ = calculateFileSize(QFileInfo(filename).size());
 
         init();