Compare commits

..
Author SHA1 Message Date
Tannin c95de1b3aa small stuff 2015-06-12 18:32:50 +02:00
Tannin 351fc9ca9c fixed display of installation time for mods without nexus id 2015-06-11 18:54:59 +02:00
Tannin 53f0a2bc79 bugfix: opening a foreign mod info dialog caused the content to be "forgotten" 2015-06-11 18:54:20 +02:00
Tannin 793dfb1637 added plugin interface to add/remove/list categories to/from/of mods 2015-06-10 22:09:32 +02:00
Tannin d25a81071c more generic solution to the problem fixed in changeset bb74f8eb639c, now also applied in another location 2015-06-10 21:22:54 +02:00
Tannin ef9a61886c a mod that overwrites another yet is completely overwritten by another is now displayed as "redundant" 2015-06-10 21:21:32 +02:00
Tannin 13a40b43c8 bugfix: files weren't correctly assigned to unmanaged mods. 2015-06-10 21:20:31 +02:00
Tannin d7790cd717 incorrect use of "complete" file suffixes 2015-06-09 20:40:13 +02:00
Tannin 84d632af6a fixes regarding path name generation during mod installation 2015-06-09 20:39:17 +02:00
Tannin b14b35349d post-merge cleanup 2015-06-08 19:55:00 +02:00
Tannin 83a4db2362 Merge 2015-06-08 18:29:49 +02:00
Tannin c797af8b76 increased ui responsiveness while integrated loot is running 2015-06-08 18:28:59 +02:00
Tannin ebf6ff3f76 workaround to prevent crashes when toggling mods causes the filtered list to change 2015-06-08 18:28:20 +02:00
Tannin 02b5e73c2d bugfix: potential null-pointer access when something goes wrong enabling a mod 2015-06-08 17:27:34 +02:00
Tom Tanner b0b2f1d3a9 Make the about dialog come up on the first tab 2015-06-07 13:37:41 +01:00
Tom Tanner d8e406daa0 Merge 2015-06-06 15:58:51 +01:00
Tom Tanner 50dcc4c1d4 Addition of FileNameString clase which ignores case during compares.
Affects rather a lot of stuff.
2015-06-06 15:56:44 +01:00
Tannin e21db0eaea bugfix: moving an executable in the executable list caused that executable
to disappear
2015-06-04 12:50:35 +02:00
Tannin 859332e18d a little more logging during startup 2015-06-04 12:50:11 +02:00
Tannin 1fd8f44960 bugfix: selecting an image in the modinfo dialog caused the image label
to grow slightly each time
2015-06-04 12:49:47 +02:00
Tannin e0c655330d Added tag release v1.3.6 for changeset 7bed8faa975a 2015-05-31 00:36:58 +02:00
Tannin a0999cd42b Removed tag release v1.3.6 2015-05-31 00:36:56 +02:00
Tannin eb47d4d0bb small stuff in preparation of release 2015-05-31 00:36:16 +02:00
Tannin 59476e38ec Added tag release v1.3.6 for changeset 11b2864c40c9 2015-05-30 17:34:11 +02:00
Tannin c5d36af06d Added tag release v1.3.5 for changeset 3f7672859c79 2015-05-30 16:12:14 +02:00
Tannin 8d1931bc6b - fix to the look of save game tooltip in dracula theme 2015-05-27 20:10:55 +02:00
Tannin c05be9f5c3 small stuff 2015-05-26 20:42:15 +02:00
Tannin 75714907d9 closing the categories context menu no longer completely resets the mod list 2015-05-25 15:29:58 +02:00
Tannin 02471a3da1 cleaned up warning messages from the download manager in case of download problems 2015-05-25 14:58:34 +02:00
Tannin afab0cec7e compact download view now uses icons instead of colors to distinguish state 2015-05-25 14:57:58 +02:00
Tannin 02cc97a58d - bugfix: bsa order wasn't correctly restored. 2015-05-24 18:51:03 +02:00
Tannin ffd94e72b4 - bugfix: immediately after creating the first profile, the directory structure
didn't correctly assign files to unhandled.
2015-05-23 17:25:58 +02:00
Tannin 6435e1ab8a - bugfix: couldn't change from "qt" styles back to regular style 2015-05-23 17:18:04 +02:00
Tannin dbfa9b89d1 some fixes to the dracula qss 2015-05-18 20:42:07 +02:00
Tannin fe5c4255c8 bugfix: previous fix for download name filter didn't work 2015-05-18 20:41:46 +02:00
38 changed files with 332 additions and 597 deletions
+10
View File
@@ -183,6 +183,11 @@
<string>Ren (Korean)</string>
</property>
</item>
<item>
<property name="text">
<string>... more (Can't track)</string>
</property>
</item>
</widget>
</item>
</layout>
@@ -249,6 +254,11 @@
<string notr="true">z929669</string>
</property>
</item>
<item>
<property name="text">
<string>thosrtanner</string>
</property>
</item>
</widget>
</item>
</layout>
+27 -5
View File
@@ -166,22 +166,32 @@ void CategoryFactory::saveCategories()
unsigned int CategoryFactory::countCategories(std::tr1::function<bool (const Category &category)> filter)
{
unsigned int result = 0;
for (auto iter = m_Categories.begin(); iter != m_Categories.end(); ++iter) {
if (filter(*iter)) {
for (const Category &cat : m_Categories) {
if (filter(cat)) {
++result;
}
}
return result;
}
int CategoryFactory::addCategory(const QString &name, const std::vector<int> &nexusIDs, int parentID)
{
int id = 1;
while (m_IDMap.find(id) != m_IDMap.end()) {
++id;
}
addCategory(id, name, nexusIDs, parentID);
saveCategories();
return id;
}
void CategoryFactory::addCategory(int id, const QString &name, const std::vector<int> &nexusIDs, int parentID)
{
int index = m_Categories.size();
m_Categories.push_back(Category(index, id, name, nexusIDs, parentID));
for (std::vector<int>::const_iterator iter = nexusIDs.begin();
iter != nexusIDs.end(); ++iter) {
m_NexusMap[*iter] = index;
for (int nexusID : nexusIDs) {
m_NexusMap[nexusID] = index;
}
m_IDMap[id] = index;
}
@@ -305,6 +315,18 @@ int CategoryFactory::getCategoryIndex(int ID) const
}
int CategoryFactory::getCategoryID(const QString &name) const
{
auto iter = std::find_if(m_Categories.begin(), m_Categories.end(), [name] (const Category &cat) -> bool {
return cat.m_Name == name;
});
if (iter != m_Categories.end()) {
return iter->m_ID;
} else {
return -1;
}
}
unsigned int CategoryFactory::resolveNexusID(int nexusID) const
{
+8
View File
@@ -80,6 +80,8 @@ public:
**/
void saveCategories();
int addCategory(const QString &name, const std::vector<int> &nexusIDs, int parentID);
/**
* @brief retrieve the number of available categories
*
@@ -142,6 +144,12 @@ public:
**/
int getCategoryID(unsigned int index) const;
/**
* @brief look up the id of a category by its name
* @note O(n)
*/
int getCategoryID(const QString &name) const;
/**
* @brief look up the index of a category by its id
*
+6 -3
View File
@@ -100,16 +100,19 @@ void DirectoryRefresher::addModFilesToStructure(DirectoryEntry *directoryStructu
if (stealFiles.length() > 0) {
// instead of adding all the files of the target directory, we just change the root of the specified
// files to this mod
FilesOrigin origin = directoryStructure->createOrigin(ToWString(modName), directoryW, priority);
foreach (const QString &filename, stealFiles) {
FilesOrigin &origin = directoryStructure->createOrigin(ToWString(modName), directoryW, priority);
for (const QString &filename : stealFiles) {
QFileInfo fileInfo(filename);
FileEntry::Ptr file = directoryStructure->findFile(ToWString(fileInfo.fileName()));
if (file.get() != nullptr) {
if (file->getOrigin() == 0) {
// replace data as the origin on this bsa
file->removeOrigin(0);
file->addOrigin(origin.getID(), file->getFileTime(), L"");
}
origin.addFile(file->getIndex());
file->addOrigin(origin.getID(), file->getFileTime(), L"");
} else {
qWarning("%s not found", qPrintable(fileInfo.fileName()));
}
}
} else {
+9 -3
View File
@@ -20,6 +20,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "downloadlistsortproxy.h"
#include "downloadlist.h"
#include "downloadmanager.h"
#include "settings.h"
DownloadListSortProxy::DownloadListSortProxy(const DownloadManager *manager, QObject *parent)
: QSortFilterProxyModel(parent), m_Manager(manager), m_CurrentFilter()
@@ -55,12 +56,17 @@ bool DownloadListSortProxy::lessThan(const QModelIndex &left,
}
bool DownloadListSortProxy::filterAcceptsRow(int source_row, const QModelIndex&) const
bool DownloadListSortProxy::filterAcceptsRow(int sourceRow, const QModelIndex&) const
{
if (m_CurrentFilter.length() == 0) {
return true;
} else if (source_row < m_Manager->numTotalDownloads()) {
return sourceModel()->index(source_row, 0).data().toString().contains(m_CurrentFilter, Qt::CaseInsensitive);
} else if (sourceRow < m_Manager->numTotalDownloads()) {
int downloadIndex = sourceModel()->index(sourceRow, 0).data().toInt();
QString displayedName = Settings::instance().metaDownloads()
? m_Manager->getDisplayName(downloadIndex)
: m_Manager->getFileName(downloadIndex);
return displayedName.contains(m_CurrentFilter, Qt::CaseInsensitive);
} else {
return false;
}
+1 -1
View File
@@ -41,7 +41,7 @@ public slots:
protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
bool filterAcceptsRow(int sourceRow, const QModelIndex &source_parent) const;
signals:
+8 -11
View File
@@ -53,7 +53,8 @@ DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadMan
m_DoneLabel->setVisible(false);
connect(manager, SIGNAL(stateChanged(int,DownloadManager::DownloadState)), this, SLOT(stateChanged(int,DownloadManager::DownloadState)));
connect(manager, SIGNAL(stateChanged(int,DownloadManager::DownloadState)),
this, SLOT(stateChanged(int,DownloadManager::DownloadState)));
connect(manager, SIGNAL(downloadRemoved(int)), this, SLOT(resetCache(int)));
}
@@ -116,24 +117,20 @@ void DownloadListWidgetCompactDelegate::paintRegularDownload(int downloadIndex)
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
m_DoneLabel->setText(tr("Paused"));
m_DoneLabel->setForegroundRole(QPalette::Link);
m_DoneLabel->setText(QString("%1<img src=\":/MO/gui/inactive\">").arg(tr("Paused")));
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_DoneLabel->setText(tr("Fetching Info 1"));
m_DoneLabel->setText(QString("%1").arg(tr("Fetching Info 1")));
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_DoneLabel->setText(tr("Fetching Info 2"));
m_DoneLabel->setText(QString("%1").arg(tr("Fetching Info 2")));
} else if (state >= DownloadManager::STATE_READY) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
m_DoneLabel->setText(tr("Installed"));
m_DoneLabel->setForegroundRole(QPalette::Mid);
m_DoneLabel->setText(QString("%1<img src=\":/MO/gui/check\">").arg(tr("Installed")));
} else if (state == DownloadManager::STATE_UNINSTALLED) {
m_DoneLabel->setText(tr("Uninstalled"));
m_DoneLabel->setForegroundRole(QPalette::Dark);
m_DoneLabel->setText(QString("%1<img src=\":/MO/gui/awaiting\">").arg(tr("Uninstalled")));
} else {
m_DoneLabel->setText(tr("Done"));
m_DoneLabel->setForegroundRole(QPalette::WindowText);
m_DoneLabel->setText(QString("%1<img src=\":/MO/gui/active\">").arg(tr("Done")));
}
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\"/> " + m_NameLabel->text());
+7 -2
View File
@@ -1354,7 +1354,9 @@ void DownloadManager::downloadFinished()
if (info->m_State == STATE_CANCELING) {
setState(info, STATE_CANCELED);
} else if (info->m_State == STATE_PAUSING) {
info->m_Output.write(info->m_Reply->readAll());
if (info->m_Output.isOpen()) {
info->m_Output.write(info->m_Reply->readAll());
}
if (error) {
setState(info, STATE_ERROR);
@@ -1426,7 +1428,10 @@ void DownloadManager::downloadFinished()
void DownloadManager::downloadError(QNetworkReply::NetworkError error)
{
if (error != QNetworkReply::OperationCanceledError) {
qWarning("Download error occured: %d", error);
QNetworkReply *reply = qobject_cast<QNetworkReply*>(sender());
qWarning("%s (%d)", reply != nullptr ? qPrintable(reply->errorString())
: "Download error occured",
error);
}
}
+1 -1
View File
@@ -26,7 +26,7 @@
<enum>QAbstractItemView::InternalMove</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
<enum>Qt::TargetMoveAction</enum>
</property>
<property name="selectionMode">
<enum>QAbstractItemView::ExtendedSelection</enum>
+14 -8
View File
@@ -114,22 +114,28 @@ void InstallationManager::queryPassword(LPSTR password)
void InstallationManager::mapToArchive(const DirectoryTree::Node *node, std::wstring path, FileData * const *data)
{
if (path.length() > 0) {
path.append(L"\\");
// when using a long windows path (starting with \\?\) we apparently can have redundant
// . components in the path. This wasn't a problem with "regular" path names.
if (path == L".") {
path.clear();
} else {
path.append(L"\\");
}
}
for (DirectoryTree::const_leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) {
data[iter->getIndex()]->setSkip(false);
std::wstring temp = path.substr().append(ToWString(iter->getName()));
std::wstring temp = path + iter->getName().toStdWString();
data[iter->getIndex()]->setOutputFileName(temp.c_str());
}
for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) {
if ((*iter)->getData().index != -1) {
data[(*iter)->getData().index]->setSkip(false);
std::wstring temp = path.substr().append(ToWString((*iter)->getData().name));
std::wstring temp = path + (*iter)->getData().name.toStdWString();
data[(*iter)->getData().index]->setOutputFileName(temp.c_str());
}
mapToArchive(*iter, path.substr().append(ToWString((*iter)->getData().name)), data);
mapToArchive(*iter, path + (*iter)->getData().name.toStdWString(), data);
}
}
@@ -535,8 +541,8 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
return false;
}
QString targetDirectoryNative = m_ModsDirectory + "\\" + modName;
QString targetDirectory = QDir::fromNativeSeparators(targetDirectoryNative);
QString targetDirectory = QDir(m_ModsDirectory + "/" + modName).canonicalPath();
QString targetDirectoryNative = QDir::toNativeSeparators(targetDirectory);
qDebug("installing to \"%s\"", targetDirectoryNative.toUtf8().constData());
@@ -545,7 +551,7 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID,
m_InstallationProgress.setValue(0);
m_InstallationProgress.setWindowModality(Qt::WindowModal);
m_InstallationProgress.show();
if (!m_CurrentArchive->extract(ToWString("\\\\?\\" + QDir::toNativeSeparators(targetDirectory)).c_str(),
if (!m_CurrentArchive->extract(ToWString("\\\\?\\" + targetDirectoryNative).c_str(),
new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress),
new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::updateProgressFile),
new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) {
@@ -629,7 +635,7 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString>
{
QFileInfo fileInfo(fileName);
if (m_SupportedExtensions.find(fileInfo.suffix()) == m_SupportedExtensions.end()) {
reportError(tr("File format \"%1\" not supported").arg(fileInfo.completeSuffix()));
reportError(tr("File format \"%1\" not supported").arg(fileInfo.suffix()));
return false;
}
+1 -1
View File
@@ -129,7 +129,7 @@ char LogBuffer::msgTypeID(QtMsgType type)
void LogBuffer::log(QtMsgType type, const QMessageLogContext &context, const QString &message)
{
// QMutexLocker doesn't support timeout...
if (!s_Mutex.tryLock(50)) {
if (!s_Mutex.tryLock(100)) {
fprintf(stderr, "failed to log: %s", qPrintable(message));
return;
}
+8 -5
View File
@@ -170,6 +170,8 @@ void cleanupDir()
"proxy.dll"
};
qDebug("removing obsolete files");
for (const QString &fileName : fileNames) {
QString fullPath = qApp->applicationDirPath() + "/" + fileName;
if (QFile::exists(fullPath)
@@ -430,9 +432,9 @@ int main(int argc, char *argv[])
} // we continue for the primary instance OR if MO has been called with parameters
QSettings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()), QSettings::IniFormat);
qDebug("initializing core");
OrganizerCore organizer(settings);
qDebug("initialize plugins");
PluginContainer pluginContainer(&organizer);
pluginContainer.loadPlugins();
@@ -516,7 +518,8 @@ int main(int argc, char *argv[])
// if we have a command line parameter, it is either a nxm link or
// a binary to start
if ((arguments.size() > 1) && (!isNxmLink(arguments.at(1)))) {
if ((arguments.size() > 1)
&& !isNxmLink(arguments.at(1))) {
QString exeName = arguments.at(1);
qDebug("starting %s from command line", qPrintable(exeName));
arguments.removeFirst(); // remove application name (ModOrganizer.exe)
@@ -553,8 +556,8 @@ int main(int argc, char *argv[])
qDebug("displaying main window");
mainWindow.show();
if ((arguments.size() > 1) &&
(isNxmLink(arguments.at(1)))) {
if ((arguments.size() > 1)
&& isNxmLink(arguments.at(1))) {
qDebug("starting download from command line: %s", qPrintable(arguments.at(1)));
organizer.externalMessage(arguments.at(1));
}
+49 -37
View File
@@ -1301,6 +1301,7 @@ static QStringList toStringList(InputIterator current, InputIterator end)
}
return result;
}
void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives)
{
m_DefaultArchives = defaultArchives;
@@ -1311,33 +1312,31 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
ui->bsaList->header()->setResizeMode(QHeaderView::ResizeToContents);
#endif
std::vector<std::pair<UINT32, QTreeWidgetItem*> > items;
std::vector<std::pair<UINT32, QTreeWidgetItem*>> items;
std::vector<FileEntry::Ptr> files = m_OrganizerCore.directoryStructure()->getFiles();
for (auto iter = files.begin(); iter != files.end(); ++iter) {
FileEntry::Ptr current = *iter;
for (FileEntry::Ptr current : m_OrganizerCore.directoryStructure()->getFiles()) {
QFileInfo fileInfo(ToQString(current->getName().c_str()));
QString filename = ToQString(current->getName().c_str());
QString extension = filename.right(3).toLower();
if (extension == "bsa") {
int index = activeArchives.indexOf(filename);
if (fileInfo.suffix().toLower() == "bsa") {
int index = activeArchives.indexOf(fileInfo.fileName());
if (index == -1) {
index = 0xFFFF;
}
QString basename = filename.left(filename.indexOf("."));
QStringList strings(filename);
bool isArchive = false;
int origin = current->getOrigin(isArchive);
strings.append(ToQString(m_OrganizerCore.directoryStructure()->getOriginByID(origin).getName()));
QTreeWidgetItem *newItem = new QTreeWidgetItem(strings);
QString basename = fileInfo.baseName();
int originId = current->getOrigin();
FilesOrigin &origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId);
QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList()
<< fileInfo.fileName()
<< ToQString(origin.getName()));
newItem->setData(0, Qt::UserRole, index);
newItem->setData(1, Qt::UserRole, origin);
newItem->setData(1, Qt::UserRole, originId);
newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable);
newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
newItem->setData(0, Qt::UserRole, false);
if (m_OrganizerCore.settings().forceEnableCoreFiles()
&& defaultArchives.contains(filename)) {
&& defaultArchives.contains(fileInfo.fileName())) {
newItem->setCheckState(0, Qt::Checked);
newItem->setDisabled(true);
newItem->setData(0, Qt::UserRole, true);
@@ -1356,7 +1355,7 @@ void MainWindow::updateBSAList(const QStringList &defaultArchives, const QString
if (index < 0) index = 0;
UINT32 sortValue = ((m_OrganizerCore.directoryStructure()->getOriginByID(origin).getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
UINT32 sortValue = ((origin.getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
items.push_back(std::make_pair(sortValue, newItem));
}
}
@@ -2061,7 +2060,7 @@ void MainWindow::refreshFilters()
ui->modList->setCurrentIndex(QModelIndex());
QStringList selectedItems;
foreach (QTreeWidgetItem *item, ui->categoriesList->selectedItems()) {
for (QTreeWidgetItem *item : ui->categoriesList->selectedItems()) {
selectedItems.append(item->text(0));
}
@@ -2091,7 +2090,7 @@ void MainWindow::refreshFilters()
addCategoryFilters(nullptr, categoriesUsed, 0);
foreach (const QString &item, selectedItems) {
for (const QString &item : selectedItems) {
QList<QTreeWidgetItem*> matches = ui->categoriesList->findItems(item, Qt::MatchFixedString | Qt::MatchRecursive);
if (matches.size() > 0) {
matches.at(0)->setSelected(true);
@@ -2246,8 +2245,9 @@ void MainWindow::resumeDownload(int downloadIndex)
} else {
QString username, password;
if (m_OrganizerCore.settings().getNexusLogin(username, password)) {
//m_PostLoginTasks.push_back(boost::bind(&MainWindow::resumeDownload, _1, downloadIndex));
m_OrganizerCore.doAfterLogin([this, downloadIndex] () { this->resumeDownload(downloadIndex); });
m_OrganizerCore.doAfterLogin([this, downloadIndex] () {
this->resumeDownload(downloadIndex);
});
NexusInterface::instance()->getAccessManager()->login(username, password);
} else {
MessageDialog::showMessage(tr("You need to be logged in with Nexus to resume a download"), this);
@@ -2363,7 +2363,8 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
m_OrganizerCore.modList()->modInfoChanged(modInfo);
}
if (m_OrganizerCore.currentProfile()->modEnabled(index)) {
if (m_OrganizerCore.currentProfile()->modEnabled(index)
&& !modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) {
FilesOrigin& origin = m_OrganizerCore.directoryStructure()->getOriginByName(ToWString(modInfo->name()));
origin.enable(false);
@@ -2618,7 +2619,7 @@ void MainWindow::addRemoveCategoriesFromMenu(QMenu *menu, int modRow, int refere
{
if (referenceRow != -1 && referenceRow != modRow) {
ModInfo::Ptr editedModInfo = ModInfo::getByIndex(referenceRow);
foreach (QAction* action, menu->actions()) {
for (QAction* action : menu->actions()) {
if (action->menu() != nullptr) {
addRemoveCategoriesFromMenu(action->menu(), modRow, referenceRow);
} else {
@@ -2648,25 +2649,29 @@ void MainWindow::addRemoveCategories_MenuHandler() {
return;
}
QModelIndexList selectedTemp = ui->modList->selectionModel()->selectedRows();
QList<QPersistentModelIndex> selected;
foreach (const QModelIndex &idx, selectedTemp) {
for (const QModelIndex &idx : ui->modList->selectionModel()->selectedRows()) {
selected.append(QPersistentModelIndex(idx));
}
if (selected.size() > 0) {
foreach (const QPersistentModelIndex &idx, selected) {
qDebug("change categories on: %s (ref: %s)", qPrintable(idx.data().toString()), qPrintable(m_ContextIdx.data().toString()));
int minRow = INT_MAX;
int maxRow = -1;
for (const QPersistentModelIndex &idx : selected) {
qDebug("change categories on: %s", qPrintable(idx.data().toString()));
QModelIndex modIdx = mapToModel(m_OrganizerCore.modList(), idx);
if (modIdx.row() != m_ContextIdx.row()) {
addRemoveCategoriesFromMenu(menu, modIdx.row(), m_ContextIdx.row());
}
if (idx.row() < minRow) minRow = idx.row();
if (idx.row() > maxRow) maxRow = idx.row();
}
replaceCategoriesFromMenu(menu, m_ContextIdx.row());
m_OrganizerCore.modList()->notifyChange(-1);
m_OrganizerCore.modList()->notifyChange(minRow, maxRow + 1);
foreach (const QPersistentModelIndex &idx, selected) {
for (const QPersistentModelIndex &idx : selected) {
ui->modList->selectionModel()->select(idx, QItemSelectionModel::Select | QItemSelectionModel::Rows);
}
} else {
@@ -2685,21 +2690,28 @@ void MainWindow::replaceCategories_MenuHandler() {
return;
}
QModelIndexList selected = ui->modList->selectionModel()->selectedRows();
QList<QPersistentModelIndex> selected;
for (const QModelIndex &idx : ui->modList->selectionModel()->selectedRows()) {
selected.append(QPersistentModelIndex(idx));
}
if (selected.size() > 0) {
QStringList selectedMods;
int minRow = INT_MAX;
int maxRow = -1;
for (int i = 0; i < selected.size(); ++i) {
QModelIndex temp = mapToModel(m_OrganizerCore.modList(), selected.at(i));
selectedMods.append(temp.data().toString());
replaceCategoriesFromMenu(menu, mapToModel(m_OrganizerCore.modList(), selected.at(i)).row());
if (temp.row() < minRow) minRow = temp.row();
if (temp.row() > maxRow) maxRow = temp.row();
}
m_OrganizerCore.modList()->notifyChange(-1);
m_OrganizerCore.modList()->notifyChange(minRow, maxRow + 1);
// find mods by their name because indices are invalidated
QAbstractItemModel *model = ui->modList->model();
Q_FOREACH(const QString &mod, selectedMods) {
for (const QString &mod : selectedMods) {
QModelIndexList matches = model->match(model->index(0, 0), Qt::DisplayRole, mod, 1,
Qt::MatchFixedString | Qt::MatchCaseSensitive | Qt::MatchRecursive);
if (matches.size() > 0) {
@@ -3457,7 +3469,7 @@ void MainWindow::writeDataToFile()
int MainWindow::getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments)
{
QString extension = targetInfo.completeSuffix();
QString extension = targetInfo.suffix();
if ((extension.compare("cmd", Qt::CaseInsensitive) == 0) ||
(extension.compare("com", Qt::CaseInsensitive) == 0) ||
(extension.compare("bat", Qt::CaseInsensitive) == 0)) {
@@ -3712,7 +3724,7 @@ void MainWindow::on_dataTree_customContextMenuRequested(const QPoint &pos)
menu.addAction(tr("Add as Executable"), this, SLOT(addAsExecutable()));
QString fileName = m_ContextItem->text(0);
if (m_PluginContainer.previewGenerator().previewSupported(QFileInfo(fileName).completeSuffix())) {
if (m_PluginContainer.previewGenerator().previewSupported(QFileInfo(fileName).suffix())) {
menu.addAction(tr("Preview"), this, SLOT(previewDataFile()));
}
@@ -4350,7 +4362,7 @@ void MainWindow::on_bossButton_clicked()
if (loot != INVALID_HANDLE_VALUE) {
bool isJobHandle = true;
ULONG lastProcessID;
DWORD res = ::MsgWaitForMultipleObjects(1, &loot, false, 1000, QS_KEY | QS_MOUSE);
DWORD res = ::MsgWaitForMultipleObjects(1, &loot, false, 100, QS_KEY | QS_MOUSE);
while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) {
if (isJobHandle) {
if (::QueryInformationJobObject(loot, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) {
@@ -4390,7 +4402,7 @@ void MainWindow::on_bossButton_clicked()
std::string lootOut = readFromPipe(stdOutRead);
processLOOTOut(lootOut, errorMessages, dialog);
res = ::MsgWaitForMultipleObjects(1, &loot, false, 1000, QS_KEY | QS_MOUSE);
res = ::MsgWaitForMultipleObjects(1, &loot, false, 100, QS_KEY | QS_MOUSE);
}
std::string remainder = readFromPipe(stdOutRead).c_str();
+1
View File
@@ -102,6 +102,7 @@ bool MOApplication::setStyleFile(const QString &styleName)
updateStyle(styleName);
}
} else {
setStyle(new ProxyStyle(QStyleFactory::create(m_DefaultStyle)));
setStyleSheet("");
}
return true;
+55 -19
View File
@@ -18,6 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "modinfo.h"
#include "utility.h"
#include "installationtester.h"
#include "categories.h"
@@ -26,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "overwriteinfodialog.h"
#include "json.h"
#include "messagedialog.h"
#include "filenamestring.h"
#include <gameinfo.h>
#include <iplugingame.h>
@@ -301,6 +303,40 @@ void ModInfo::setVersion(const VersionInfo &version)
m_Version = version;
}
void ModInfo::addCategory(const QString &categoryName)
{
int id = CategoryFactory::instance().getCategoryID(categoryName);
if (id == -1) {
id = CategoryFactory::instance().addCategory(categoryName, std::vector<int>(), 0);
}
setCategory(id, true);
}
bool ModInfo::removeCategory(const QString &categoryName)
{
int id = CategoryFactory::instance().getCategoryID(categoryName);
if (id == -1) {
return false;
}
if (!categorySet(id)) {
return false;
}
setCategory(id, false);
return true;
}
QStringList ModInfo::categories()
{
QStringList result;
CategoryFactory &catFac = CategoryFactory::instance();
for (int id : m_Categories) {
result.append(catFac.getCategoryName(catFac.getCategoryIndex(id)));
}
return result;
}
bool ModInfo::hasFlag(ModInfo::EFlag flag) const
{
std::vector<EFlag> flags = getFlags();
@@ -386,7 +422,8 @@ void ModInfoWithConflictInfo::doConflictCheck() const
{
m_OverwriteList.clear();
m_OverwrittenList.clear();
bool regular = false;
bool providesAnything = false;
int dataID = 0;
if ((*m_DirectoryStructure)->originExists(L"data")) {
@@ -398,22 +435,24 @@ void ModInfoWithConflictInfo::doConflictCheck() const
FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name);
std::vector<FileEntry::Ptr> files = origin.getFiles();
// for all files in this origin
for (auto iter = files.begin(); iter != files.end(); ++iter) {
const std::vector<int> &alternatives = (*iter)->getAlternatives();
if ((alternatives.size() == 0)
|| (alternatives[0] == dataID)) {
for (FileEntry::Ptr file : files) {
const std::vector<int> &alternatives = file->getAlternatives();
if ((alternatives.size() == 0) || (alternatives[0] == dataID)) {
// no alternatives -> no conflict
regular = true;
providesAnything = true;
} else {
if ((*iter)->getOrigin() != origin.getID()) {
FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID((*iter)->getOrigin());
if (file->getOrigin() != origin.getID()) {
FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(file->getOrigin());
unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName()));
m_OverwrittenList.insert(altIndex);
} else {
providesAnything = true;
}
// for all non-providing alternative origins
for (auto altIter = alternatives.begin(); altIter != alternatives.end(); ++altIter) {
if ((*altIter != dataID) && (*altIter != origin.getID())) {
FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(*altIter);
for (int altId : alternatives) {
if ((altId != dataID) && (altId != origin.getID())) {
FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altId);
unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName()));
if (origin.getPriority() > altOrigin.getPriority()) {
m_OverwriteList.insert(altIndex);
@@ -428,16 +467,14 @@ void ModInfoWithConflictInfo::doConflictCheck() const
m_LastConflictCheck = QTime::currentTime();
if (!m_OverwriteList.empty() && !m_OverwrittenList.empty())
if (!providesAnything)
m_CurrentConflictState = CONFLICT_REDUNDANT;
else if (!m_OverwriteList.empty() && !m_OverwrittenList.empty())
m_CurrentConflictState = CONFLICT_MIXED;
else if (!m_OverwriteList.empty())
m_CurrentConflictState = CONFLICT_OVERWRITE;
else if (!m_OverwrittenList.empty()) {
if (!regular) {
m_CurrentConflictState = CONFLICT_REDUNDANT;
} else {
m_CurrentConflictState = CONFLICT_OVERWRITTEN;
}
m_CurrentConflictState = CONFLICT_OVERWRITTEN;
}
else m_CurrentConflictState = CONFLICT_NONE;
}
@@ -1027,7 +1064,6 @@ ModInfoBackup::ModInfoBackup(const QDir &path, DirectoryEntry **directoryStructu
ModInfoOverwrite::ModInfoOverwrite()
: m_StartupTime(QDateTime::currentDateTime())
{
testValid();
}
@@ -1069,7 +1105,7 @@ QStringList ModInfoOverwrite::archives() const
{
QStringList result;
QDir dir(this->absolutePath());
foreach (const QString &archive, dir.entryList(QStringList("*.bsa"))) {
for (const QString &archive : dir.entryList(QStringList("*.bsa"))) {
result.append(this->absolutePath() + "/" + archive);
}
return result;
+5 -5
View File
@@ -300,6 +300,10 @@ public:
*/
virtual void addNexusCategory(int categoryID) = 0;
virtual void addCategory(const QString &categoryName) override;
virtual bool removeCategory(const QString &categoryName) override;
virtual QStringList categories() override;
/**
* update the endorsement state for the mod. This only changes the
* buffered state, it does not sync with Nexus
@@ -1041,7 +1045,7 @@ public:
virtual bool isEmpty() const;
virtual QString name() const { return "Overwrite"; }
virtual QString notes() const { return ""; }
virtual QDateTime creationTime() const { return m_StartupTime; }
virtual QDateTime creationTime() const { return QDateTime(); }
virtual QString absolutePath() const;
virtual MOBase::VersionInfo getNewestVersion() const { return ""; }
virtual QString getInstallationFile() const { return ""; }
@@ -1060,10 +1064,6 @@ private:
ModInfoOverwrite();
private:
QDateTime m_StartupTime;
};
+3 -4
View File
@@ -395,7 +395,6 @@ const int ModInfoDialog::getModID() const
return m_Settings->value("modid", 0).toInt();
}
void ModInfoDialog::openTab(int tab)
{
QTabWidget *tabWidget = findChild<QTabWidget*>("tabWidget");
@@ -407,16 +406,16 @@ void ModInfoDialog::openTab(int tab)
void ModInfoDialog::thumbnailClicked(const QString &fileName)
{
QLabel *imageLabel = findChild<QLabel*>("imageLabel");
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
QImage image(fileName);
if (static_cast<float>(image.width()) / static_cast<float>(image.height()) > 1.34) {
image = image.scaledToWidth(imageLabel->width());
image = image.scaledToWidth(imageLabel->geometry().width());
} else {
image = image.scaledToHeight(imageLabel->height());
image = image.scaledToHeight(imageLabel->geometry().height());
}
imageLabel->setPixmap(QPixmap::fromImage(image));
}
bool ModInfoDialog::allowNavigateFromTXT()
{
if (ui->saveTXTButton->isEnabled()) {
+21 -6
View File
@@ -23,6 +23,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "installationtester.h"
#include "qtgroupingproxy.h"
#include "viewmarkingscrollbar.h"
#include "modlistsortproxy.h"
#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
@@ -83,6 +84,7 @@ void ModList::setProfile(Profile *profile)
{
m_Profile = profile;
}
int ModList::rowCount(const QModelIndex &parent) const
{
if (!parent.isValid()) {
@@ -245,7 +247,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
} else if (column == COL_INSTALLTIME) {
// display installation time for mods that can be updated
if (modInfo->canBeUpdated()) {
if (modInfo->creationTime().isValid()) {
return modInfo->creationTime();
} else {
return QVariant();
@@ -451,6 +453,8 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
bool result = false;
emit aboutToChangeData();
if (role == Qt::CheckStateRole) {
bool enabled = value.toInt() == Qt::Checked;
if (m_Profile->modEnabled(modID) != enabled) {
@@ -510,6 +514,8 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
}
}
emit postDataChanged();
IModList::ModStates newState = state(modID);
if (oldState != newState) {
try {
@@ -654,6 +660,7 @@ void ModList::modInfoChanged(ModInfo::Ptr info)
if (m_ChangeInfo.state != newState) {
m_ModStateChanged(info->name(), newState);
}
int row = ModInfo::getIndex(info->name());
info->testValid();
emit dataChanged(index(row, 0), index(row, columnCount()));
@@ -1089,15 +1096,23 @@ bool ModList::deleteSelection(QAbstractItemView *itemView)
bool ModList::toggleSelection(QAbstractItemView *itemView)
{
QAbstractItemModel *model = itemView->model();
emit aboutToChangeData();
QItemSelectionModel *selectionModel = itemView->selectionModel();
for (QModelIndex idx : selectionModel->selectedRows()) {
int oldState = idx.data(Qt::CheckStateRole).toInt();
model->setData(idx, oldState == Qt::Unchecked ? Qt::Checked
: Qt::Unchecked,
Qt::CheckStateRole);
int modId = idx.data(Qt::UserRole + 1).toInt();
m_Profile->setModEnabled(modId, !m_Profile->modEnabled(modId));
emit modlist_changed(idx, 0);
}
m_Modified = true;
m_LastCheck.restart();
emit dataChanged(index(0, 0), index(rowCount() - 1, columnCount() - 1));
emit postDataChanged();
return true;
}
+4
View File
@@ -237,6 +237,10 @@ signals:
*/
void fileMoved(const QString &relativePath, const QString &oldOriginName, const QString &newOriginName);
void aboutToChangeData();
void postDataChanged();
protected:
// event filter, handles event from the header and the tree view itself
+23
View File
@@ -376,3 +376,26 @@ bool ModListSortProxy::dropMimeData(const QMimeData *data, Qt::DropAction action
return this->sourceModel()->dropMimeData(data, action, sourceIndex.row(), sourceIndex.column(),
sourceIndex.parent());
}
void ModListSortProxy::setSourceModel(QAbstractItemModel *sourceModel)
{
QSortFilterProxyModel::setSourceModel(sourceModel);
connect(sourceModel, SIGNAL(aboutToChangeData()), this, SLOT(aboutToChangeData()));
connect(sourceModel, SIGNAL(postDataChanged()), this, SLOT(postDataChanged()));
}
void ModListSortProxy::aboutToChangeData()
{
// having a filter active when dataChanged is called caused a crash
// (at least with some Qt versions)
m_PreChangeFilters = categoryFilter();
setCategoryFilter(std::vector<int>());
}
void ModListSortProxy::postDataChanged()
{
setCategoryFilter(m_PreChangeFilters);
m_PreChangeFilters.clear();
}

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