Compare commits

...
9 Commits
Author SHA1 Message Date
Tannin bb98bfade6 - MO will now be elevated if needed 2014-02-23 18:53:38 +01:00
Tannin 00f4e1799f - slightly overworked display of icon delegates
- updated installer
2014-02-23 17:18:20 +01:00
Tannin 35fcf1c25b - made the indicator for drag&drop more visible
- message boxes can now be made to not (re-)activate the window
- executable names for starting from the command line are now case-insensitive
2014-02-22 19:22:12 +01:00
Tannin bed3c08a6d - bugfix: on-demand loading of data tree broke filtering on conflicting files 2014-02-18 19:08:12 +01:00
Tannin f9eba9dc15 - ini file changes that would have to overwrite ini tweaks are now stored in a separate file
and actually get used.
- a warning message advices users to clean out that separate file
- slightly improved default main window layout
- bugfix: newly created ini tweaks were added to the list with incorrect  properties
2014-02-17 21:15:20 +01:00
Tannin 9c8e43853d - a few hooks will now somewhat handle file names starting with \\?\
- mod meta information is now (also) saved by a timer to reduce the likelyhood
of a data loss in case of a crash
- mod meta files are now written to a temporary file and then renamed to real name to
reduce chance of breaking the file
- updated minimum compatible nmm version to 0.47.0
- bugfix: defaults for newestVersion, version and installationFile when creating
an empty mod were integers instead of strings
- bugfix: "Plugins" and "Archives" weren't translatable
2014-02-12 21:00:49 +01:00
Tannin 7aadb47637 - archives.txt is now written using the "safe"-write mechanism
- added the whole boss fork to the repository
- bugfix: boss db is now always re-initialised because otherwise there might have been differing results between runs
- bugfix: locked load order was ignored by integrated boss
- bugfix: archive list wasn't written back on all changes that affected it
- bugfix: CreateFile-hook didn't reroute files created with OPEN_ALWAYS to overwrite directory
- bugfix: NtQueryDirectoryFile-hook didn't return the correct status code when searching for a file that doesn't exist
2014-02-07 21:05:48 +01:00
Tannin 76fbe6effe - tabs in the mod info dialog can now be moved around by the user 2014-02-04 19:55:27 +01:00
Tannin 38ee6ccf0a Added tag release v1.1.1 for changeset 73a1f1438658 2014-02-02 15:14:07 +01:00
32 changed files with 7066 additions and 5305 deletions
+1 -1
View File
@@ -106,7 +106,7 @@ const Executable &ExecutablesList::find(const QString &title) const
Executable &ExecutablesList::find(const QString &title)
{
for (std::vector<Executable>::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) {
if (iter->m_Title == title) {
if (QString::compare(iter->m_Title, title, Qt::CaseInsensitive) == 0) {
return *iter;
}
}
+15 -6
View File
@@ -21,6 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QHBoxLayout>
#include <QLabel>
#include <QPainter>
#include <QDebug>
IconDelegate::IconDelegate(QObject *parent)
@@ -37,25 +38,33 @@ void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
int x = 4;
painter->save();
int iconWidth = icons.size() > 0 ? ((option.rect.width() / icons.size()) - 4) : 16;
iconWidth = std::min(16, iconWidth);
painter->translate(option.rect.topLeft());
for (auto iter = icons.begin(); iter != icons.end(); ++iter) {
painter->drawPixmap(x, 2, 16, 16, iter->pixmap(QSize(16, 16)));
x += 20;
painter->drawPixmap(x, 2, iconWidth, iconWidth, iter->pixmap(QSize(iconWidth, iconWidth)));
x += iconWidth + 4;
}
painter->restore();
}
QSize IconDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex &modelIndex) const
QSize IconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const
{
int count = getNumIcons(modelIndex);
unsigned int index = modelIndex.data(Qt::UserRole + 1).toInt();
QSize result;
if (index < ModInfo::getNumMods()) {
ModInfo::Ptr info = ModInfo::getByIndex(index);
return QSize(info->getFlags().size() * 20, 20);
result = QSize(count * 40, 20);
} else {
return QSize(1, 20);
result = QSize(1, 20);
}
if (option.rect.width() > 0) {
result.setWidth(std::min(option.rect.width(), result.width()));
}
return result;
}
+64
View File
@@ -67,6 +67,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QSplashScreen>
#include <QDirIterator>
#include <QDesktopServices>
#include <ShellAPI.h>
#include <eh.h>
#include <windows_error.h>
#include <boost/scoped_array.hpp>
@@ -277,6 +278,59 @@ void registerMetaTypes()
registerExecutable();
}
bool HaveWriteAccess(const std::wstring &path)
{
bool writable = false;
const static SECURITY_INFORMATION requestedFileInformation = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
DWORD length = 0;
if (!::GetFileSecurityW(path.c_str(), requestedFileInformation, NULL, NULL, &length)
&& (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)) {
std::string tempBuffer;
tempBuffer.reserve(length);
PSECURITY_DESCRIPTOR security = (PSECURITY_DESCRIPTOR)tempBuffer.data();
if (security
&& ::GetFileSecurity(path.c_str(), requestedFileInformation, security, length, &length)) {
HANDLE token = NULL;
const static DWORD tokenDesiredAccess = TOKEN_IMPERSONATE | TOKEN_QUERY | TOKEN_DUPLICATE | STANDARD_RIGHTS_READ;
if (!::OpenThreadToken(::GetCurrentThread(), tokenDesiredAccess, TRUE, &token)) {
if (!::OpenProcessToken(::GetCurrentProcess(), tokenDesiredAccess, &token)) {
throw std::runtime_error("Unable to get any thread or process token");
}
}
HANDLE impersonatedToken = NULL;
if (::DuplicateToken(token, SecurityImpersonation, &impersonatedToken)) {
GENERIC_MAPPING mapping = { 0xFFFFFFFF };
mapping.GenericRead = FILE_GENERIC_READ;
mapping.GenericWrite = FILE_GENERIC_WRITE;
mapping.GenericExecute = FILE_GENERIC_EXECUTE;
mapping.GenericAll = FILE_ALL_ACCESS;
DWORD genericAccessRights = FILE_GENERIC_WRITE;
::MapGenericMask(&genericAccessRights, &mapping);
PRIVILEGE_SET privileges = { 0 };
DWORD grantedAccess = 0;
DWORD privilegesLength = sizeof(privileges);
BOOL result = 0;
if (::AccessCheck(security, impersonatedToken, genericAccessRights, &mapping, &privileges, &privilegesLength, &grantedAccess, &result)) {
writable = result != 0;
}
::CloseHandle(impersonatedToken);
}
::CloseHandle(token);
}
}
return writable;
}
int main(int argc, char *argv[])
{
MOApplication application(argc, argv);
@@ -285,6 +339,16 @@ int main(int argc, char *argv[])
SetUnhandledExceptionFilter(MyUnhandledExceptionFilter);
if (!HaveWriteAccess(ToWString(application.applicationDirPath()))) {
QStringList arguments = application.arguments();
arguments.pop_front();
::ShellExecuteW( NULL
, L"runas"
, ToWString(QString("\"%1\"").arg(QCoreApplication::applicationFilePath())).c_str()
, ToWString(arguments.join(" ")).c_str()
, ToWString(QDir::currentPath()).c_str(), SW_SHOWNORMAL);
return 1;
}
LogBuffer::init(200, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log");
qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath())));
+52 -34
View File
@@ -58,6 +58,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "problemsdialog.h"
#include "previewdialog.h"
#include "aboutdialog.h"
#include "safewritefile.h"
#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
@@ -216,6 +217,9 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
ui->bsaList->setLocalMoveOnly(true);
ui->splitter->setStretchFactor(0, 3);
ui->splitter->setStretchFactor(1, 2);
resizeLists(initSettings.contains("mod_list_state"), initSettings.contains("plugin_list_state"));
QMenu *linkMenu = new QMenu(this);
@@ -294,6 +298,10 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
m_CheckBSATimer.setSingleShot(true);
connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList()));
m_SaveMetaTimer.setSingleShot(false);
connect(&m_SaveMetaTimer, SIGNAL(timeout()), this, SLOT(saveModMetas()));
m_SaveMetaTimer.start(5000);
m_DirectoryRefresher.moveToThread(&m_RefresherThread);
m_RefresherThread.start();
@@ -623,22 +631,18 @@ void MainWindow::createHelpWidget()
void MainWindow::saveArchiveList()
{
if (m_ArchivesInit) {
QFile archiveFile(m_CurrentProfile->getArchivesFileName());
if (archiveFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
for (int j = 0; j < tlItem->childCount(); ++j) {
QTreeWidgetItem *item = tlItem->child(j);
if (item->checkState(0) == Qt::Checked) {
archiveFile.write(item->text(0).toUtf8().append("\r\n"));
}
SafeWriteFile archiveFile(m_CurrentProfile->getArchivesFileName());
for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
QTreeWidgetItem *tlItem = ui->bsaList->topLevelItem(i);
for (int j = 0; j < tlItem->childCount(); ++j) {
QTreeWidgetItem *item = tlItem->child(j);
if (item->checkState(0) == Qt::Checked) {
archiveFile->write(item->text(0).toUtf8().append("\r\n"));
}
}
} else {
reportError(tr("failed to save archives order, do you have write access "
"to \"%1\"?").arg(m_CurrentProfile->getArchivesFileName()));
}
archiveFile.close();
archiveFile.commit();
qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_CurrentProfile->getArchivesFileName())));
} else {
qWarning("archive list not initialised");
}
@@ -701,18 +705,13 @@ bool MainWindow::saveCurrentLists()
return false;
}
// save plugin list
try {
savePluginList();
saveArchiveList();
} catch (const std::exception &e) {
reportError(tr("failed to save load order: %1").arg(e.what()));
}
// save only if the file doesn't exist at all, changes made in the ui are saved immediately
if (!QFile::exists(m_CurrentProfile->getArchivesFileName())) {
saveArchiveList();
}
return true;
}
@@ -1216,10 +1215,10 @@ IModInterface *MainWindow::createMod(GuessedValue<QString> &name)
QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat);
settingsFile.setValue("modid", 0);
settingsFile.setValue("version", 0);
settingsFile.setValue("newestVersion", 0);
settingsFile.setValue("version", "");
settingsFile.setValue("newestVersion", "");
settingsFile.setValue("category", 0);
settingsFile.setValue("installationFile", 0);
settingsFile.setValue("installationFile", "");
return ModInfo::createFrom(QDir(targetDirectory), &m_DirectoryStructure).data();
// }
}
@@ -1559,18 +1558,21 @@ void MainWindow::updateTo(QTreeWidgetItem *subTree, const std::wstring &director
columns.append("");
if (!(*current)->isEmpty()) {
QTreeWidgetItem *directoryChild = new QTreeWidgetItem(columns);
QTreeWidgetItem *onDemandLoad = new QTreeWidgetItem(QStringList());
onDemandLoad->setData(0, Qt::UserRole + 0, "__loaded_on_demand__");
onDemandLoad->setData(0, Qt::UserRole + 1, ToQString(temp.str()));
onDemandLoad->setData(0, Qt::UserRole + 2, conflictsOnly);
directoryChild->addChild(onDemandLoad);
subTree->addChild(directoryChild);
/* updateTo(directoryChild, temp.str(), **current, conflictsOnly);
if (directoryChild->childCount() != 0) {
subTree->addChild(directoryChild);
if (conflictsOnly) {
updateTo(directoryChild, temp.str(), **current, conflictsOnly);
if (directoryChild->childCount() != 0) {
subTree->addChild(directoryChild);
} else {
delete directoryChild;
}
} else {
delete directoryChild;
}*/
QTreeWidgetItem *onDemandLoad = new QTreeWidgetItem(QStringList());
onDemandLoad->setData(0, Qt::UserRole + 0, "__loaded_on_demand__");
onDemandLoad->setData(0, Qt::UserRole + 1, ToQString(temp.str()));
onDemandLoad->setData(0, Qt::UserRole + 2, conflictsOnly);
directoryChild->addChild(onDemandLoad);
subTree->addChild(directoryChild);
}
}
}
}
@@ -1964,6 +1966,15 @@ void MainWindow::checkBSAList()
}
void MainWindow::saveModMetas()
{
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
modInfo->saveMeta();
}
}
void MainWindow::fixCategories()
{
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
@@ -2709,6 +2720,8 @@ void MainWindow::modorder_changed()
m_DirectoryStructure->getOriginByName(ToWString(modInfo->name())).setPriority(priority);
}
}
refreshBSAList();
saveArchiveList();
m_DirectoryStructure->getFileRegister()->sortOrigins();
}
@@ -3003,8 +3016,9 @@ void MainWindow::modlistChanged(const QModelIndex &index, int role)
MessageDialog::showMessage(tr("Multiple esps activated, please check that they don't conflict."), this);
}
m_PluginList.refreshLoadOrder();
// immediately save plugin list
// immediately save affected lists
savePluginList();
saveArchiveList();
}
}
}
@@ -3150,6 +3164,7 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
dialog->activateWindow();
connect(dialog, SIGNAL(finished(int)), this, SLOT(overwriteClosed(int)));
} else {
modInfo->saveMeta();
ModInfoDialog dialog(modInfo, m_DirectoryStructure, this);
connect(&dialog, SIGNAL(nexusLinkActivated(QString)), this, SLOT(nexusLinkActivated(QString)));
connect(&dialog, SIGNAL(downloadRequest(QString)), this, SLOT(downloadRequestedNXM(QString)));
@@ -3160,7 +3175,10 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
connect(&dialog, SIGNAL(endorseMod(ModInfo::Ptr)), this, SLOT(endorseMod(ModInfo::Ptr)));
dialog.openTab(tab);
dialog.restoreTabState(m_Settings.directInterface().value("mod_info_tabs").toByteArray());
dialog.exec();
m_Settings.directInterface().setValue("mod_info_tabs", dialog.saveTabState());
modInfo->saveMeta();
emit modInfoDisplayed();
m_ModList.modInfoChanged(modInfo);
+3
View File
@@ -352,6 +352,7 @@ private:
bool m_DirectoryUpdate;
bool m_ArchivesInit;
QTimer m_CheckBSATimer;
QTimer m_SaveMetaTimer;
QTime m_StartTime;
SaveGameInfoWidget *m_CurrentSaveView;
@@ -495,6 +496,8 @@ private slots:
void startExeAction();
void checkBSAList();
void saveModMetas();
void updateStyle(const QString &style);
void modlistChanged(const QModelIndex &index, int role);
+4 -4
View File
@@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>868</width>
<height>701</height>
<width>926</width>
<height>710</height>
</rect>
</property>
<property name="windowTitle">
@@ -602,7 +602,7 @@ p, li { white-space: pre-wrap; }
</size>
</property>
<attribute name="title">
<string notr="true">Plugins</string>
<string>Plugins</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<property name="leftMargin">
@@ -738,7 +738,7 @@ p, li { white-space: pre-wrap; }
</widget>
<widget class="QWidget" name="bsaTab">
<attribute name="title">
<string notr="true">Archives</string>
<string>Archives</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<property name="leftMargin">
+6 -5
View File
@@ -79,12 +79,13 @@ void MessageDialog::resizeEvent(QResizeEvent *event)
}
void MessageDialog::showMessage(const QString &text, QWidget *reference)
void MessageDialog::showMessage(const QString &text, QWidget *reference, bool bringToFront)
{
qDebug("%s", qPrintable(text));
if (reference != NULL) {
MessageDialog *dialog = new MessageDialog(text, reference);
dialog->show();
reference->activateWindow();
if (bringToFront || (qApp->activeWindow() != NULL)) {
MessageDialog *dialog = new MessageDialog(text, reference);
dialog->show();
reference->activateWindow();
}
}
}
+48 -47
View File
@@ -17,50 +17,51 @@ 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 MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QDialog>
namespace Ui {
class MessageDialog;
}
/**
* borderless dialog used to display short messages that will automatically
* vanish after a moment
**/
class MessageDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief constructor
*
* @param text the message to display
* @param reference parent widget. This will also be used to position the message at the bottom center of the dialog
**/
explicit MessageDialog(const QString &text, QWidget *reference);
~MessageDialog();
/**
* factory function for message dialogs. This can be used as a fire-and-forget. The message
* will automatically positioned to the reference dialog and get a reasonable view time
*
* @param text the text to display. The length of this text is used to determine how long the dialog is to be shown
* @param reference the reference widget on top of which the message should be displayed
**/
static void showMessage(const QString &text, QWidget *reference);
protected:
virtual void resizeEvent(QResizeEvent *event);
private:
Ui::MessageDialog *ui;
};
#endif // MESSAGEDIALOG_H
#ifndef MESSAGEDIALOG_H
#define MESSAGEDIALOG_H
#include <QDialog>
namespace Ui {
class MessageDialog;
}
/**
* borderless dialog used to display short messages that will automatically
* vanish after a moment
**/
class MessageDialog : public QDialog
{
Q_OBJECT
public:
/**
* @brief constructor
*
* @param text the message to display
* @param reference parent widget. This will also be used to position the message at the bottom center of the dialog
**/
explicit MessageDialog(const QString &text, QWidget *reference);
~MessageDialog();
/**
* factory function for message dialogs. This can be used as a fire-and-forget. The message
* will automatically positioned to the reference dialog and get a reasonable view time
*
* @param text the text to display. The length of this text is used to determine how long the dialog is to be shown
* @param reference the reference widget on top of which the message should be displayed
* @param true if the message should bring MO to front to ensure this message is visible
**/
static void showMessage(const QString &text, QWidget *reference, bool bringToFront = true);
protected:
virtual void resizeEvent(QResizeEvent *event);
private:
Ui::MessageDialog *ui;
};
#endif // MESSAGEDIALOG_H
+48 -3
View File
@@ -25,6 +25,50 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QStringList>
#include <QPlastiqueStyle>
#include <QCleanlooksStyle>
#include <QProxyStyle>
#include <QStyleFactory>
#include <QPainter>
#include <QStyleOption>
#include <QDebug>
class ProxyStyle : public QProxyStyle {
public:
ProxyStyle(QStyle *baseStyle = 0)
: QProxyStyle(baseStyle)
{
}
void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const {
if(element == QStyle::PE_IndicatorItemViewItemDrop) {
painter->setRenderHint(QPainter::Antialiasing, true);
QColor col(option->palette.foreground().color());
QPen pen(col);
pen.setWidth(2);
col.setAlpha(50);
QBrush brush(col);
painter->setPen(pen);
painter->setBrush(brush);
if(option->rect.height() == 0) {
QPoint tri[3] = {
option->rect.topLeft(),
option->rect.topLeft() + QPoint(-5, 5),
option->rect.topLeft() + QPoint(-5, -5)
};
painter->drawPolygon(tri, 3);
painter->drawLine(QPoint(option->rect.topLeft().x(), option->rect.topLeft().y()), option->rect.topRight());
} else {
painter->drawRoundedRect(option->rect, 5, 5);
}
} else {
QProxyStyle::drawPrimitive(element, option, painter, widget);
}
}
};
MOApplication::MOApplication(int argc, char **argv)
@@ -32,6 +76,7 @@ MOApplication::MOApplication(int argc, char **argv)
{
connect(&m_StyleWatcher, SIGNAL(fileChanged(QString)), SLOT(updateStyle(QString)));
m_DefaultStyle = style()->objectName();
setStyle(new ProxyStyle(style()));
}
@@ -79,13 +124,13 @@ bool MOApplication::notify(QObject *receiver, QEvent *event)
void MOApplication::updateStyle(const QString &fileName)
{
if (fileName == "Plastique") {
setStyle(new QPlastiqueStyle);
setStyle(new ProxyStyle(new QPlastiqueStyle));
setStyleSheet("");
} else if (fileName == "Cleanlooks") {
setStyle(new QCleanlooksStyle);
setStyle(new ProxyStyle(new QCleanlooksStyle));
setStyleSheet("");
} else {
setStyle(m_DefaultStyle);
setStyle(new ProxyStyle(QStyleFactory::create(m_DefaultStyle)));
if (QFile::exists(fileName)) {
setStyleSheet(QString("file:///%1").arg(fileName));
} else {
+21 -1
View File
@@ -2,6 +2,11 @@
#include <QList>
ModInfo::EFlag ModFlagIconDelegate::m_ConflictFlags[4] = { ModInfo::FLAG_CONFLICT_MIXED
, ModInfo::FLAG_CONFLICT_OVERWRITE
, ModInfo::FLAG_CONFLICT_OVERWRITTEN
, ModInfo::FLAG_CONFLICT_REDUNDANT };
ModFlagIconDelegate::ModFlagIconDelegate(QObject *parent)
: IconDelegate(parent)
{
@@ -15,6 +20,16 @@ QList<QIcon> ModFlagIconDelegate::getIcons(const QModelIndex &index) const
ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt());
std::vector<ModInfo::EFlag> flags = info->getFlags();
{ // insert conflict icon first to provide nicer alignment
auto iter = std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4);
if (iter != flags.end()) {
result.append(getFlagIcon(*iter));
flags.erase(iter);
} else {
result.append(QIcon());
}
}
for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
result.append(getFlagIcon(*iter));
}
@@ -42,7 +57,12 @@ size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const
unsigned int modIdx = index.data(Qt::UserRole + 1).toInt();
if (modIdx < ModInfo::getNumMods()) {
ModInfo::Ptr info = ModInfo::getByIndex(modIdx);
return info->getFlags().size();
std::vector<ModInfo::EFlag> flags = info->getFlags();
int count = flags.size();
if (std::find_first_of(flags.begin(), flags.end(), m_ConflictFlags, m_ConflictFlags + 4) == flags.end()) {
++count;
}
return count;
} else {
return 0;
}
+2 -1
View File
@@ -12,7 +12,8 @@ private:
virtual size_t getNumIcons(const QModelIndex &index) const;
QIcon getFlagIcon(ModInfo::EFlag flag) const;
private:
static ModInfo::EFlag m_ConflictFlags[4];
};
#endif // MODFLAGICONDELEGATE_H
+67 -53
View File
@@ -300,48 +300,7 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
testValid();
m_CreationTime = QFileInfo(path.absolutePath()).created();
// read out the meta-file for information
QString metaFileName = path.absoluteFilePath("meta.ini");
QSettings metaFile(metaFileName, QSettings::IniFormat);
m_Notes = metaFile.value("notes", "").toString();
m_NexusID = metaFile.value("modid", -1).toInt();
m_Version.parse(metaFile.value("version", "").toString());
m_NewestVersion = metaFile.value("newestVersion", "").toString();
m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString();
m_InstallationFile = metaFile.value("installationFile", "").toString();
m_NexusDescription = metaFile.value("nexusDescription", "").toString();
m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate);
if (metaFile.contains("endorsed")) {
if (metaFile.value("endorsed").canConvert<int>()) {
switch (metaFile.value("endorsed").toInt()) {
case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break;
case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break;
case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break;
default: m_EndorsedState = ENDORSED_UNKNOWN; break;
}
} else {
m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
}
}
QString categoriesString = metaFile.value("category", "").toString();
QStringList categories = categoriesString.split(',', QString::SkipEmptyParts);
for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
bool ok = false;
int categoryID = iter->toInt(&ok);
if (categoryID < 0) {
// ignore invalid id
continue;
}
if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) {
m_Categories.insert(categoryID);
if (iter == categories.begin()) {
m_PrimaryCategory = categoryID;
}
}
}
readMeta();
connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
@@ -369,6 +328,52 @@ bool ModInfoRegular::isEmpty() const
}
void ModInfoRegular::readMeta()
{
QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat);
m_Notes = metaFile.value("notes", "").toString();
m_NexusID = metaFile.value("modid", -1).toInt();
m_Version.parse(metaFile.value("version", "").toString());
m_NewestVersion = metaFile.value("newestVersion", "").toString();
m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString();
m_InstallationFile = metaFile.value("installationFile", "").toString();
m_NexusDescription = metaFile.value("nexusDescription", "").toString();
m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate);
if (metaFile.contains("endorsed")) {
if (metaFile.value("endorsed").canConvert<int>()) {
switch (metaFile.value("endorsed").toInt()) {
case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break;
case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break;
case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break;
default: m_EndorsedState = ENDORSED_UNKNOWN; break;
}
} else {
m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
}
}
QString categoriesString = metaFile.value("category", "").toString();
QStringList categories = categoriesString.split(',', QString::SkipEmptyParts);
for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
bool ok = false;
int categoryID = iter->toInt(&ok);
if (categoryID < 0) {
// ignore invalid id
continue;
}
if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) {
m_Categories.insert(categoryID);
if (iter == categories.begin()) {
m_PrimaryCategory = categoryID;
}
}
}
m_MetaInfoChanged = false;
}
void ModInfoRegular::saveMeta()
{
// only write meta data if the mod directory exists
@@ -381,7 +386,9 @@ void ModInfoRegular::saveMeta()
metaFile.setValue("newestVersion", m_NewestVersion.canonicalString());
metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString());
metaFile.setValue("version", m_Version.canonicalString());
metaFile.setValue("modid", m_NexusID);
if (m_NexusID != -1) {
metaFile.setValue("modid", m_NexusID);
}
metaFile.setValue("notes", m_Notes);
metaFile.setValue("nexusDescription", m_NexusDescription);
metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate));
@@ -389,10 +396,15 @@ void ModInfoRegular::saveMeta()
metaFile.setValue("endorsed", m_EndorsedState);
}
metaFile.sync(); // sync needs to be called to ensure the file is created
if (metaFile.status() == QSettings::NoError) {
m_MetaInfoChanged = false;
} else {
reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status()));
}
} else {
reportError(tr("failed to write %1/meta.ini: %2").arg(absolutePath()).arg(metaFile.status()));
reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status()));
}
m_MetaInfoChanged = false;
}
}
@@ -556,6 +568,10 @@ void ModInfoRegular::setVersion(const VersionInfo &version)
m_MetaInfoChanged = true;
}
void ModInfoRegular::setNewestVersion(const VersionInfo &version) {
m_NewestVersion = version;
}
void ModInfoRegular::setNexusDescription(const QString &description)
{
m_NexusDescription = description;
@@ -621,12 +637,6 @@ void ModInfoRegular::ignoreUpdate(bool ignore)
std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
{
std::vector<ModInfo::EFlag> result;
if (!isValid()) {
result.push_back(ModInfo::FLAG_INVALID);
}
if ((m_NexusID != -1) && (endorsedState() == ENDORSED_FALSE)) {
result.push_back(ModInfo::FLAG_NOTENDORSED);
}
switch (isConflicted()) {
case CONFLICT_MIXED: {
result.push_back(ModInfo::FLAG_CONFLICT_MIXED);
@@ -642,6 +652,12 @@ std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
} break;
default: { /* NOP */ }
}
if ((m_NexusID != -1) && (endorsedState() == ENDORSED_FALSE)) {
result.push_back(ModInfo::FLAG_NOTENDORSED);
}
if (!isValid()) {
result.push_back(ModInfo::FLAG_INVALID);
}
if (m_Notes.length() != 0) {
result.push_back(ModInfo::FLAG_NOTES);
}
@@ -691,13 +707,11 @@ QString ModInfoRegular::getNexusDescription() const
return m_NexusDescription;
}
ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const
{
return m_EndorsedState;
}
ModInfoRegular::EConflictType ModInfoRegular::isConflicted() const
{
// this is costy so cache the result
+7 -1
View File
@@ -431,6 +431,11 @@ public:
*/
void testValid();
/**
* @brief reads meta information from disk
*/
virtual void readMeta() {}
/**
* @brief stores meta information back to disk
*/
@@ -592,7 +597,7 @@ public:
* @todo this function should be made obsolete. All queries for mod information should go through
* this class so no public function for this change is required
**/
void setNewestVersion(const MOBase::VersionInfo &version) { m_NewestVersion = version; }
void setNewestVersion(const MOBase::VersionInfo &version);
/**
* @brief changes/updates the nexus description text
@@ -748,6 +753,7 @@ public:
*/
virtual void saveMeta();
void readMeta();
private:
enum EConflictType {
+64 -13
View File
@@ -69,7 +69,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
ui->setupUi(this);
this->setWindowTitle(modInfo->name());
this->setWindowModality(Qt::WindowModal);
m_UTF8Codec = QTextCodec::codecForName("utf-8");
QListWidget *textFileList = findChild<QListWidget*>("textFileList");
@@ -143,7 +142,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
QTabWidget *tabWidget = findChild<QTabWidget*>("tabWidget");
tabWidget->setTabEnabled(TAB_TEXTFILES, textFileList->count() != 0);
//tabWidget->setTabEnabled(TAB_INIFILES, (iniFileList->count() != 0) || (iniTweaksList->count() != 0));
tabWidget->setTabEnabled(TAB_IMAGES, thumbnailArea->count() != 0);
tabWidget->setTabEnabled(TAB_ESPS, (inactiveESPList->count() != 0) || (activeESPList->count() != 0));
tabWidget->setTabEnabled(TAB_CONFLICTS, m_Origin != NULL);
@@ -160,14 +158,69 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
ModInfoDialog::~ModInfoDialog()
{
m_ModInfo->setNotes(ui->notesEdit->toPlainText());
saveIniTweaks();
saveCategories(ui->categoriesTree->invisibleRootItem());
saveIniTweaks(); // ini tweaks are written to the ini file directly. This is the only information not managed by ModInfo
delete ui;
delete m_Settings;
}
int ModInfoDialog::tabIndex(const QString &tabId)
{
for (int i = 0; i < ui->tabWidget->count(); ++i) {
if (ui->tabWidget->widget(i)->objectName() == tabId) {
return i;
}
}
return -1;
}
void ModInfoDialog::restoreTabState(const QByteArray &state)
{
QDataStream stream(state);
int count = 0;
stream >> count;
QStringList tabIds;
// first, only determine the new mapping
for (int newPos = 0; newPos < count; ++newPos) {
QString tabId;
stream >> tabId;
tabIds.append(tabId);
int oldPos = tabIndex(tabId);
if (oldPos != -1) {
m_RealTabPos[newPos] = oldPos;
} else {
m_RealTabPos[newPos] = newPos;
}
}
// then actually move the tabs
QTabBar *tabBar = ui->tabWidget->findChild<QTabBar*>("qt_tabwidget_tabbar"); // magic name = bad
ui->tabWidget->blockSignals(true);
for (int newPos = 0; newPos < count; ++newPos) {
QString tabId = tabIds.at(newPos);
int oldPos = tabIndex(tabId);
tabBar->moveTab(oldPos, newPos);
}
ui->tabWidget->blockSignals(false);
}
QByteArray ModInfoDialog::saveTabState() const
{
QByteArray result;
QDataStream stream(&result, QIODevice::WriteOnly);
stream << ui->tabWidget->count();
for (int i = 0; i < ui->tabWidget->count(); ++i) {
stream << ui->tabWidget->widget(i)->objectName();
}
return result;
}
void ModInfoDialog::refreshLists()
{
int numNonConflicting = 0;
@@ -331,7 +384,6 @@ void ModInfoDialog::openTab(int tab)
}
}
void ModInfoDialog::thumbnailClicked(const QString &fileName)
{
QLabel *imageLabel = findChild<QLabel*>("imageLabel");
@@ -421,18 +473,15 @@ void ModInfoDialog::openIniFile(const QString &fileName)
void ModInfoDialog::saveIniTweaks()
{
QListWidget *iniTweaksList = findChild<QListWidget*>("iniTweaksList");
m_Settings->beginWriteArray("INI Tweaks");
int countEnabled = 0;
for (int i = 0; i < iniTweaksList->count(); ++i) {
if (iniTweaksList->item(i)->checkState() == Qt::Checked) {
for (int i = 0; i < ui->iniTweaksList->count(); ++i) {
if (ui->iniTweaksList->item(i)->checkState() == Qt::Checked) {
m_Settings->setArrayIndex(countEnabled++);
m_Settings->setValue("name", iniTweaksList->item(i)->text());
m_Settings->setValue("name", ui->iniTweaksList->item(i)->text());
}
}
m_Settings->endArray();
}
@@ -784,7 +833,7 @@ void ModInfoDialog::activateNexusTab()
void ModInfoDialog::on_tabWidget_currentChanged(int index)
{
if (index == TAB_NEXUS) {
if (m_RealTabPos[index] == TAB_NEXUS) {
activateNexusTab();
}
}
@@ -1175,8 +1224,10 @@ void ModInfoDialog::createTweak()
return;
}
QListWidgetItem *newTweak = new QListWidgetItem(name);
QListWidgetItem *newTweak = new QListWidgetItem(name + ".ini");
newTweak->setData(Qt::UserRole, "INI Tweaks/" + name + ".ini");
newTweak->setFlags(newTweak->flags() | Qt::ItemIsUserCheckable);
newTweak->setCheckState(Qt::Unchecked);
ui->iniTweaksList->addItem(newTweak);
}
+8
View File
@@ -100,6 +100,10 @@ public:
**/
void openTab(int tab);
void restoreTabState(const QByteArray &state);
QByteArray saveTabState() const;
signals:
void thumbnailClickedSignal(const QString &filename);
@@ -142,6 +146,8 @@ private:
void addCheckedCategories(QTreeWidgetItem *tree);
void refreshPrimaryCategoriesBox();
int tabIndex(const QString &tabId);
private slots:
void hideConflictFile();
@@ -221,6 +227,8 @@ private:
MOShared::FilesOrigin *m_Origin;
QTextCodec *m_UTF8Codec;
std::map<int, int> m_RealTabPos;
};
#endif // MODINFODIALOG_H
+7 -4
View File
@@ -22,6 +22,9 @@
<property name="currentIndex">
<number>0</number>
</property>
<property name="movable">
<bool>true</bool>
</property>
<widget class="QWidget" name="tabText">
<attribute name="title">
<string>Textfiles</string>
@@ -209,7 +212,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>668</width>
<width>676</width>
<height>126</height>
</rect>
</property>
@@ -546,7 +549,7 @@ Most mods do not have optional esps, so chances are good you are looking at an e
</item>
</layout>
</widget>
<widget class="QWidget" name="tabNexus_2">
<widget class="QWidget" name="tabNexus">
<attribute name="icon">
<iconset resource="resources.qrc">
<normaloff>:/MO/gui/resources/internet-web-browser.png</normaloff>:/MO/gui/resources/internet-web-browser.png</iconset>
@@ -666,8 +669,8 @@ p, li { white-space: pre-wrap; }
<string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
p, li { white-space: pre-wrap; }
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="textInteractionFlags">
<set>Qt::TextBrowserInteraction</set>
+818 -634
View File
File diff suppressed because it is too large Load Diff
+814 -634
View File
File diff suppressed because it is too large Load Diff
+816 -640
View File
File diff suppressed because it is too large Load Diff
+813 -637
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More