Add desktop stuff
Loose plugins belonging to known mods will no longer be magically added to list. Rewrite how Plugins/LoadOrder interacts with model to prevent clobbering the listview on save/update. Fix 2 bugs in enabling/disabling a mod If src="file.esp" && dest="", try to do the right thing.
This commit is contained in:
parent
1b3f9e5aca
commit
734e7bf498
6 changed files with 113 additions and 9 deletions
|
|
@ -191,6 +191,28 @@ Item {
|
|||
return results;
|
||||
}
|
||||
|
||||
function getFilesEndingWith(suffixes)
|
||||
{
|
||||
if( !checkConnection ) return;
|
||||
|
||||
let qstr = "SELECT fileId, modId, relative, source, dest, priority FROM files";
|
||||
let token = ' WHERE ';
|
||||
let args = [];
|
||||
|
||||
// I has feels this is gonna get beat tf up...
|
||||
suffixes.forEach( function(d) {
|
||||
qstr += token + "dest LIKE '%' || ?";
|
||||
token = ' OR ';
|
||||
args.push(d);
|
||||
} );
|
||||
|
||||
let q = conn.query(qstr, args);
|
||||
const results = q.toArray();
|
||||
q.destroy();
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
function insertFile(modId, fileInfo)
|
||||
{
|
||||
if( !checkConnection ) return;
|
||||
|
|
|
|||
|
|
@ -131,8 +131,9 @@ Item {
|
|||
for( let a=0; a < pluginsTable.model.length; a++ )
|
||||
{
|
||||
const ent = visualModel.items.get(a);
|
||||
const modent = ent.model.modelData;
|
||||
//console.log(`Visual item ${a}: ${JSON.stringify(modent)}`);
|
||||
console.log(`Visual item ${a}: ${JSON.stringify(ent.model.index)}`);
|
||||
//const modent = ent.model.modelData;
|
||||
const modent = mmodel.get(ent.model.index);
|
||||
|
||||
if( modent['filepath'].toLowerCase().endsWith('.esp')
|
||||
|| modent['filepath'].toLowerCase().endsWith('.esl'))
|
||||
|
|
@ -155,7 +156,8 @@ Item {
|
|||
for( let a=0; a < pluginsTable.model.length; a++ )
|
||||
{
|
||||
const ent = visualModel.items.get(a);
|
||||
const modent = ent.model.modelData;
|
||||
//const modent = ent.model.modelData;
|
||||
const modent = mmodel.get(ent.model.index);
|
||||
|
||||
const nent = { 'enabled':modent['enabled'], 'filename':modent['filepath'] };
|
||||
if( modent['filepath'].toLowerCase().endsWith('.esm') )
|
||||
|
|
@ -281,10 +283,60 @@ Item {
|
|||
} // MouseArea
|
||||
} // Component:pluginRowDelegate
|
||||
|
||||
// Try to smoothly update the model to avoid our scroll position getting
|
||||
// clobbered whenever we save a change.
|
||||
onModelChanged: function() {
|
||||
// we key on the filename:
|
||||
let mnames = model.map( m => m['filepath'] );
|
||||
|
||||
let toremove = [];
|
||||
|
||||
let lmmap = {};
|
||||
for( let a=0; a < mmodel.count; a++ )
|
||||
{
|
||||
const dentry = mmodel.get(a);
|
||||
let ent = { 'index':a, 'entry':dentry };
|
||||
if( !mnames.includes(dentry['filepath']) )
|
||||
toremove.unshift(a);
|
||||
else
|
||||
lmmap[ dentry['filepath'] ] = ent;
|
||||
}
|
||||
|
||||
toremove.forEach( i => mmodel.remove(i) );
|
||||
|
||||
for( let b=0; b < mnames.length; b++ )
|
||||
{
|
||||
const n = mnames[b];
|
||||
const nent = model[b];
|
||||
if( !lmmap[ n ] )
|
||||
{
|
||||
mmodel.append( nent );
|
||||
continue;
|
||||
}
|
||||
|
||||
mmodel.set( lmmap[n]['index'], nent );
|
||||
|
||||
}
|
||||
|
||||
for( let c=0; c < mmodel.count; c++ )
|
||||
{
|
||||
const ent = visualModel.items.get(c);
|
||||
if( c === ent.model.index )
|
||||
continue;
|
||||
console.log(`Visual item ${c}: ${JSON.stringify(ent.model.index)}`);
|
||||
visualModel.items.move(c, ent.model.index);
|
||||
}
|
||||
}
|
||||
|
||||
ListModel {
|
||||
id: mmodel
|
||||
dynamicRoles: true
|
||||
}
|
||||
|
||||
DelegateModel {
|
||||
id: visualModel
|
||||
|
||||
model: pluginsTable.model
|
||||
model: mmodel
|
||||
delegate: pluginRowDelegate
|
||||
}
|
||||
|
||||
|
|
|
|||
10
qml/mods.js
10
qml/mods.js
|
|
@ -188,7 +188,6 @@ function enableMod(mod)
|
|||
let loadorder = Plugins.readLoadOrder();
|
||||
files.forEach( function(f) {
|
||||
let baseName = f['dest'];
|
||||
|
||||
let parts = f['dest'].split(/\//g);
|
||||
if( parts.length > 1 )
|
||||
baseName = parts.pop();
|
||||
|
|
@ -233,7 +232,7 @@ function removePlugin(mod)
|
|||
let loadorder = Plugins.readLoadOrder();
|
||||
files.forEach( function(f) {
|
||||
const parts = f['dest'].split(/\//g);
|
||||
if( parts.length === 1 )
|
||||
if( parts.length > 0 )
|
||||
{
|
||||
const baseName = parts.pop().toLowerCase();
|
||||
|
||||
|
|
@ -246,7 +245,7 @@ function removePlugin(mod)
|
|||
}
|
||||
|
||||
let nlo = loadorder[sec].filter( m => m.toLowerCase() !== baseName );
|
||||
if( nsec.length !== loadorder[sec].length )
|
||||
if( nlo.length !== loadorder[sec].length )
|
||||
{
|
||||
loadorder[sec] = nlo;
|
||||
updatePlugins = true;
|
||||
|
|
@ -722,6 +721,11 @@ function installBasicMod(mod)
|
|||
fdpath = parts.join('/');
|
||||
}
|
||||
|
||||
if( fdpath.length === 0 )
|
||||
fdpath = parts.pop();
|
||||
if( !fdpath )
|
||||
fdpath = f['pathname'];
|
||||
|
||||
const dpath = (sobj.gamePath + '/' + currentGameEntry['datadir'] + '/' + fdpath).replace(/\/\//g, '/');
|
||||
console.log(`Extract "${f['pathname']}" -> "${dpath}"`);
|
||||
fileMap[fpath] = dpath;
|
||||
|
|
|
|||
|
|
@ -43,10 +43,14 @@ function readLoadOrder()
|
|||
|
||||
function writeLoadOrder(loadorder)
|
||||
{
|
||||
let written = [];
|
||||
|
||||
let output = ["# Generated by Quickmod"];
|
||||
['masters', 'normal'].forEach( function(sec) {
|
||||
loadorder[sec].forEach( function(ent) {
|
||||
output.push(`${ent}`);
|
||||
if( !written.includes(ent) )
|
||||
output.push(`${ent}`);
|
||||
written.push(ent);
|
||||
} );
|
||||
});
|
||||
const res = output.join("\r\n");
|
||||
|
|
@ -169,10 +173,14 @@ function readPlugins()
|
|||
|
||||
function writePlugins(plugins)
|
||||
{
|
||||
let written = [];
|
||||
|
||||
let output = ["# Generated by Quickmod"];
|
||||
['masters', 'normal'].forEach( function(sec) {
|
||||
plugins[sec].forEach( function(ent) {
|
||||
output.push(`${ ent['enabled'] ? '*' : '' }${ent['filename']}`);
|
||||
if( !written.includes(ent['filename']) )
|
||||
output.push(`${ ent['enabled'] ? '*' : '' }${ent['filename']}`);
|
||||
written.push(ent['filename']);
|
||||
} );
|
||||
});
|
||||
const res = output.join("\r\n");
|
||||
|
|
@ -197,6 +205,9 @@ function scanForLoose(plugins)
|
|||
if( !contents )
|
||||
return plugins; // ... weird?
|
||||
|
||||
// Don't add files that belong to a mod:
|
||||
const justFiles = db.getFilesEndingWith(['.esm', '.esl', '.esp']).map( e => e['dest'].toLowerCase() );
|
||||
|
||||
const normalsLC = plugins['normal'].map( e => e['filename'].toLowerCase() );
|
||||
const mastersLC = plugins['masters'].map( e => e['filename'].toLowerCase() );
|
||||
|
||||
|
|
@ -204,6 +215,9 @@ function scanForLoose(plugins)
|
|||
{
|
||||
const ent = contents[x];
|
||||
const lcfn = ent['fileName'].toLowerCase();
|
||||
if( justFiles.includes(lcfn) )
|
||||
continue;
|
||||
|
||||
if( lcfn.endsWith('.esl') || lcfn.endsWith('.esp') )
|
||||
{
|
||||
if( !normalsLC.includes(lcfn) )
|
||||
|
|
|
|||
12
quickmod.desktop
Normal file
12
quickmod.desktop
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
[Desktop Entry]
|
||||
Name=Quickmod
|
||||
GenericName=Mod Manager
|
||||
Comment=Mod manager for Skyrim SE, Skyrim VR, Fallout 4, and Fallout 4 VR
|
||||
Keywords=mod;game;games;
|
||||
Icon=quickmod
|
||||
Type=Application
|
||||
Categories=Game;
|
||||
Exec=quickmod %u
|
||||
StartupNotify=false
|
||||
Terminal=false
|
||||
MimeType=x-scheme-handler/nxm;
|
||||
BIN
quickmod.png
Normal file
BIN
quickmod.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
Loading…
Reference in a new issue