summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTannin <devnull@localhost>2014-01-05 18:50:56 +0100
committerTannin <devnull@localhost>2014-01-05 18:50:56 +0100
commitdb09b806b9e765b5cb49a9a80f74a4440fff3027 (patch)
tree47d8bc442416698d2e5b34c49d7ddd3b6efd04ce /src
parent859c0aed984240467e9e59f72aa4c9714df9fb0b (diff)
- Mod Organizer can now display most image types (including dds) and txt files from the data
tree, presenting a comparison of variants in case of overwritten files
Diffstat (limited to 'src')
-rw-r--r--src/mainwindow.cpp46
-rw-r--r--src/mainwindow.h4
-rw-r--r--src/modinfodialog.cpp15
-rw-r--r--src/organizer.pro13
-rw-r--r--src/previewdialog.cpp57
-rw-r--r--src/previewdialog.h36
-rw-r--r--src/previewdialog.ui90
-rw-r--r--src/previewgenerator.cpp111
-rw-r--r--src/previewgenerator.h51
-rw-r--r--src/shared/directoryentry.h1
10 files changed, 408 insertions, 16 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 1f1d5f95..80465fb9 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -55,6 +55,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "gameinfoimpl.h"
#include "savetextasdialog.h"
#include "problemsdialog.h"
+#include "previewdialog.h"
#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
@@ -4372,6 +4373,44 @@ void MainWindow::unhideFile()
}
}
+void MainWindow::previewDataFile()
+{
+ QString fileName = QDir::fromNativeSeparators(m_ContextItem->data(0, Qt::UserRole).toString());
+
+ // what we have is an absolute path to the file in its actual location (for the primary origin)
+ // what we want is the path relative to the virtual data directory
+
+ // crude: we search for the next slash after the base mod directory to skip everything up to the data-relative directory
+ int offset = m_Settings.getModDirectory().size() + 1;
+ offset = fileName.indexOf("/", offset);
+ fileName = fileName.mid(offset + 1);
+
+ const FileEntry::Ptr file = m_DirectoryStructure->searchFile(ToWString(fileName), NULL);
+
+ if (file.get() == NULL) {
+ reportError(tr("file not found: %1").arg(fileName));
+ return;
+ }
+
+ // set up preview dialog
+ PreviewDialog preview(fileName);
+ auto addFunc = [&] (int originId) {
+ FilesOrigin &origin = m_DirectoryStructure->getOriginByID(originId);
+ QString filePath = QDir::fromNativeSeparators(ToQString(origin.getPath())) + "/" + fileName;
+ if (QFile::exists(filePath)) {
+ // it's very possible the file doesn't exist, because it's inside an archive. we don't support that
+ preview.addVariant(ToQString(origin.getName()), m_PreviewGenerator.genPreview(filePath));
+ }
+ };
+
+ addFunc(file->getOrigin());
+ foreach (int i, file->getAlternatives()) {
+ addFunc(i);
+ }
+ if (preview.numVariants() > 0) {
+ preview.exec();
+ }
+}
void MainWindow::openDataFile()
{
@@ -4439,6 +4478,12 @@ void MainWindow::on_dataTree_customContextMenuRequested(const QPoint &pos)
if ((m_ContextItem != NULL) && (m_ContextItem->childCount() == 0)) {
menu.addAction(tr("Open/Execute"), this, SLOT(openDataFile()));
menu.addAction(tr("Add as Executable"), this, SLOT(addAsExecutable()));
+
+ QString fileName = m_ContextItem->text(0);
+ if (m_PreviewGenerator.previewSupported(QFileInfo(fileName).completeSuffix())) {
+ menu.addAction(tr("Preview"), this, SLOT(previewDataFile()));
+ }
+
// offer to hide/unhide file, but not for files from archives
if (!m_ContextItem->data(0, Qt::UserRole + 1).toBool()) {
if (m_ContextItem->text(0).endsWith(ModInfo::s_HiddenExt)) {
@@ -4447,6 +4492,7 @@ void MainWindow::on_dataTree_customContextMenuRequested(const QPoint &pos)
menu.addAction(tr("Hide"), this, SLOT(hideFile()));
}
}
+
menu.addSeparator();
}
menu.addAction(tr("Write To File..."), this, SLOT(writeDataToFile()));
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 31fbeef3..21c121fb 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -48,6 +48,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "pluginlistsortproxy.h"
#include "tutorialcontrol.h"
#include "savegameinfowidgetgamebryo.h"
+#include "previewgenerator.h"
#include <guessedvalue.h>
#include <directoryentry.h>
#include <boost/signals2.hpp>
@@ -367,6 +368,8 @@ private:
QString m_CurrentLanguage;
std::vector<QTranslator*> m_Translators;
+ PreviewGenerator m_PreviewGenerator;
+
private slots:
void showMessage(const QString &message);
@@ -398,6 +401,7 @@ private slots:
void writeDataToFile();
void openDataFile();
void addAsExecutable();
+ void previewDataFile();
void hideFile();
void unhideFile();
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index 1da050ed..674e7165 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -398,19 +398,10 @@ void ModInfoDialog::on_textFileList_currentItemChanged(QListWidgetItem *current,
void ModInfoDialog::openTextFile(const QString &fileName)
{
- QFile textFile(fileName);
- textFile.open(QIODevice::ReadOnly);
- QByteArray buffer = textFile.readAll();
- QTextCodec *codec = QTextCodec::codecForUtfText(buffer, m_UTF8Codec);
- QString text = codec->toUnicode(buffer);
- if (codec->fromUnicode(text) != buffer) {
- qDebug("conversion failed assuming local encoding");
- codec = QTextCodec::codecForLocale();
- text = codec->toUnicode(buffer);
- }
- ui->textFileView->setText(text);
+ QString encoding;
+ ui->textFileView->setText(MOBase::readFileText(fileName, &encoding));
ui->textFileView->setProperty("currentFile", fileName);
- ui->textFileView->setProperty("encoding", codec->name());
+ ui->textFileView->setProperty("encoding", encoding);
ui->saveTXTButton->setEnabled(false);
}
diff --git a/src/organizer.pro b/src/organizer.pro
index 5988056e..07feb326 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -7,7 +7,7 @@
contains(QT_VERSION, "^5.*") {
QT += core gui widgets network declarative script xml sql xmlpatterns
} else {
- QT += core gui network xml declarative script sql xmlpatterns
+ QT += core gui network xml declarative script sql xmlpatterns opengl
}
TARGET = ModOrganizer
@@ -78,7 +78,9 @@ SOURCES += \
../esptk/record.cpp \
../esptk/espfile.cpp \
../esptk/subrecord.cpp \
- noeditdelegate.cpp
+ noeditdelegate.cpp \
+ previewgenerator.cpp \
+ previewdialog.cpp
HEADERS += \
transfersavesdialog.h \
@@ -145,7 +147,9 @@ HEADERS += \
../esptk/espfile.h \
../esptk/subrecord.h \
../esptk/espexceptions.h \
- noeditdelegate.h
+ noeditdelegate.h \
+ previewgenerator.h \
+ previewdialog.h
FORMS += \
transfersavesdialog.ui \
@@ -174,7 +178,8 @@ FORMS += \
activatemodsdialog.ui \
profileinputdialog.ui \
savetextasdialog.ui \
- problemsdialog.ui
+ problemsdialog.ui \
+ previewdialog.ui
INCLUDEPATH += ../shared ../archive ../uibase ../bsatk ../esptk "$(BOOSTPATH)"
diff --git a/src/previewdialog.cpp b/src/previewdialog.cpp
new file mode 100644
index 00000000..de33cdd0
--- /dev/null
+++ b/src/previewdialog.cpp
@@ -0,0 +1,57 @@
+#include "previewdialog.h"
+#include "ui_previewdialog.h"
+#include <QFileInfo>
+
+PreviewDialog::PreviewDialog(const QString &fileName, QWidget *parent) :
+ QDialog(parent),
+ ui(new Ui::PreviewDialog)
+{
+ ui->setupUi(this);
+ ui->nameLabel->setText(QFileInfo(fileName).fileName());
+ ui->nextButton->setEnabled(false);
+ ui->previousButton->setEnabled(false);
+}
+
+PreviewDialog::~PreviewDialog()
+{
+ delete ui;
+}
+
+void PreviewDialog::addVariant(const QString &modName, QWidget *widget)
+{
+ widget->setProperty("modName", modName);
+ ui->variantsStack->addWidget(widget);
+ if (ui->variantsStack->count() > 1) {
+ ui->nextButton->setEnabled(true);
+ ui->previousButton->setEnabled(true);
+ }
+}
+
+int PreviewDialog::numVariants() const
+{
+ return ui->variantsStack->count();
+}
+
+void PreviewDialog::on_variantsStack_currentChanged(int index)
+{
+ ui->modLabel->setText(ui->variantsStack->widget(index)->property("modName").toString());
+}
+
+void PreviewDialog::on_closeButton_clicked()
+{
+ this->accept();
+}
+
+void PreviewDialog::on_previousButton_clicked()
+{
+ int i = ui->variantsStack->currentIndex() - 1;
+ if (i < 0) {
+ i = ui->variantsStack->count() - 1;
+ }
+ ui->variantsStack->setCurrentIndex(i);
+}
+
+void PreviewDialog::on_nextButton_clicked()
+{
+ ui->variantsStack->setCurrentIndex((ui->variantsStack->currentIndex() + 1) % ui->variantsStack->count());
+}
diff --git a/src/previewdialog.h b/src/previewdialog.h
new file mode 100644
index 00000000..0011bc50
--- /dev/null
+++ b/src/previewdialog.h
@@ -0,0 +1,36 @@
+#ifndef PREVIEWDIALOG_H
+#define PREVIEWDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class PreviewDialog;
+}
+
+class PreviewDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit PreviewDialog(const QString &fileName, QWidget *parent = 0);
+ ~PreviewDialog();
+
+ void addVariant(const QString &modName, QWidget *widget);
+ int numVariants() const;
+
+private slots:
+
+ void on_variantsStack_currentChanged(int arg1);
+
+ void on_closeButton_clicked();
+
+ void on_previousButton_clicked();
+
+ void on_nextButton_clicked();
+
+private:
+
+ Ui::PreviewDialog *ui;
+};
+
+#endif // PREVIEWDIALOG_H
diff --git a/src/previewdialog.ui b/src/previewdialog.ui
new file mode 100644
index 00000000..e2dc824a
--- /dev/null
+++ b/src/previewdialog.ui
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PreviewDialog</class>
+ <widget class="QDialog" name="PreviewDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>736</width>
+ <height>583</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preview</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="1,1,0,0">
+ <item>
+ <widget class="QLabel" name="nameLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="modLabel">
+ <property name="text">
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="previousButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/previous</normaloff>:/MO/gui/previous</iconset>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="nextButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/next</normaloff>:/MO/gui/next</iconset>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QStackedWidget" name="variantsStack"/>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton">
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="resources.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/src/previewgenerator.cpp b/src/previewgenerator.cpp
new file mode 100644
index 00000000..5b0a44d8
--- /dev/null
+++ b/src/previewgenerator.cpp
@@ -0,0 +1,111 @@
+/*
+Copyright (C) 2014 Sebastian Herbord. All rights reserved.
+
+This file is part of Mod Organizer.
+
+Mod Organizer 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.
+
+Mod Organizer 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 Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "previewgenerator.h"
+#include <QFileInfo>
+#include <QLabel>
+#include <QImageReader>
+#include <QTextEdit>
+#include <QGLPixelBuffer>
+#include <QDesktopWidget>
+#include <utility.h>
+
+PreviewGenerator::PreviewGenerator()
+{
+ // set up image reader to be used for all image types qt (the current installation) supports
+ auto imageReader = std::bind(&PreviewGenerator::genImagePreview, this, std::placeholders::_1);
+
+ foreach (const QByteArray &fileType, QImageReader::supportedImageFormats()) {
+ m_PreviewGenerators[QString(fileType).toLower()] = imageReader;
+ }
+
+ m_PreviewGenerators["txt"]
+ = std::bind(&PreviewGenerator::genTxtPreview, this, std::placeholders::_1);
+
+ m_PreviewGenerators["dds"]
+ = std::bind(&PreviewGenerator::genDDSPreview, this, std::placeholders::_1);
+
+ QDesktopWidget desk;
+ m_MaxSize = desk.screenGeometry().size() * 0.8;
+}
+
+bool PreviewGenerator::previewSupported(const QString &fileExtension) const
+{
+ return m_PreviewGenerators.find(fileExtension.toLower()) != m_PreviewGenerators.end();
+}
+
+QWidget *PreviewGenerator::genPreview(const QString &fileName) const
+{
+ auto iter = m_PreviewGenerators.find(QFileInfo(fileName).completeSuffix().toLower());
+ if (iter != m_PreviewGenerators.end()) {
+ return iter->second(fileName);
+ } else {
+ return nullptr;
+ }
+}
+
+QWidget *PreviewGenerator::genImagePreview(const QString &fileName) const
+{
+ QLabel *label = new QLabel();
+ label->setPixmap(QPixmap(fileName));
+ return label;
+}
+
+QWidget *PreviewGenerator::genTxtPreview(const QString &fileName) const
+{
+ QTextEdit *edit = new QTextEdit();
+ edit->setText(MOBase::readFileText(fileName));
+ edit->setReadOnly(true);
+ return edit;
+}
+
+QWidget *PreviewGenerator::genDDSPreview(const QString &fileName) const
+{
+ QGLWidget glWidget;
+ glWidget.makeCurrent();
+
+ GLuint texture = glWidget.bindTexture(fileName);
+ if (!texture)
+ return nullptr;
+
+ // Determine the size of the DDS image
+ GLint width, height;
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &width);
+ glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &height);
+
+ if (width == 0 || height == 0)
+ return nullptr;
+
+ QGLPixelBuffer pbuffer(QSize(width, height), glWidget.format(), &glWidget);
+ if (!pbuffer.makeCurrent())
+ return nullptr;
+
+ pbuffer.drawTexture(QRectF(-1, -1, 2, 2), texture);
+
+ QLabel *label = new QLabel();
+ QImage image = pbuffer.toImage();
+ if ((image.size().width() > m_MaxSize.width()) ||
+ (image.size().height() > m_MaxSize.height())) {
+ image = image.scaled(m_MaxSize, Qt::KeepAspectRatio);
+ }
+
+ label->setPixmap(QPixmap::fromImage(image));
+ return label;
+}
diff --git a/src/previewgenerator.h b/src/previewgenerator.h
new file mode 100644
index 00000000..4648e27e
--- /dev/null
+++ b/src/previewgenerator.h
@@ -0,0 +1,51 @@
+/*
+Copyright (C) 2014 Sebastian Herbord. All rights reserved.
+
+This file is part of Mod Organizer.
+
+Mod Organizer 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.
+
+Mod Organizer 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 Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef PREVIEWGENERATOR_H
+#define PREVIEWGENERATOR_H
+
+#include <QString>
+#include <QWidget>
+#include <map>
+#include <functional>
+
+class PreviewGenerator
+{
+public:
+ PreviewGenerator();
+
+ bool previewSupported(const QString &fileExtension) const;
+
+ QWidget *genPreview(const QString &fileName) const;
+
+private:
+
+ QWidget *genImagePreview(const QString &fileName) const;
+ QWidget *genTxtPreview(const QString &fileName) const;
+ QWidget *genDDSPreview(const QString &fileName) const;
+
+private:
+
+ std::map<QString, std::function<QWidget*(const QString&)> > m_PreviewGenerators;
+
+ QSize m_MaxSize;
+
+};
+
+#endif // PREVIEWGENERATOR_H
diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h
index 22f00a74..ad5d179b 100644
--- a/src/shared/directoryentry.h
+++ b/src/shared/directoryentry.h
@@ -71,6 +71,7 @@ public:
const std::vector<int> &getAlternatives() const { return m_Alternatives; }
const std::wstring &getName() const { return m_Name; }
+ int getOrigin() const { return m_Origin; }
int getOrigin(bool &archive) const { archive = (m_Archive.length() != 0); return m_Origin; }
const std::wstring &getArchive() const { return m_Archive; }
bool isFromArchive() const { return m_Archive.length() != 0; }