<feed xmlns='http://www.w3.org/2005/Atom'>
<title>ariadne.git/src/downloadstab.cpp, branch master</title>
<subtitle>Linux port of mod organizer</subtitle>
<id>http://git.schererleander.de/ariadne.git/atom/src/downloadstab.cpp?h=master</id>
<link rel='self' href='http://git.schererleander.de/ariadne.git/atom/src/downloadstab.cpp?h=master'/>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/'/>
<updated>2026-05-07T15:38:51Z</updated>
<entry>
<title>Stable DownloadId refactor (#2375)</title>
<updated>2026-05-07T15:38:51Z</updated>
<author>
<name>Al</name>
<email>26797547+Al12rs@users.noreply.github.com</email>
</author>
<published>2026-05-07T15:38:51Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=9c6f48a4409626b7c9ff04cabeb6a4542e1df736'/>
<id>urn:sha1:9c6f48a4409626b7c9ff04cabeb6a4542e1df736</id>
<content type='text'>
* Encapsulate the downloads directory watcher in DirWatcherManager

QFileSystemWatcher suppression currently relies on public static start/end
methods and a static counter. Seven call sites pair them raw, one of them
outside the class. Any exception between a pair permanently disables the
watcher, and the static counter implies a singleton DownloadManager.

A new DirWatcherManager owns the watcher, the counter (now an instance
member), and the filtering. The only way to suspend is an RAII Guard
obtained via a scopedGuard() factory. All raw pairs migrate to guards. A
TODO flags the existing processEvents() in the dtor as a known reentrancy
hazard worth replacing later.

* Replace aboutToUpdate/update(int) with ModelResetGuard

Replace the fragile two-signal protocol with a refcounted RAII
ModelResetGuard. Split update(int) into aboutToResetModel/modelReset
(guard only) and rowChanged(int); notifyRowChanged() is suppressed while
a reset is active.

Fixes "beginResetModel without endResetModel" warnings from three sites
in downloadFinished/removeDownload that were pairing reset with a row
update. removePending only opens a guard when an actual match is removed.

* Centralize row notifications in setState and fix missed emits

setState emits notifyRowChanged itself, uses indexByInfo (-1 when
untracked), and re-looks up the row at each use so reply-&gt;abort() and
plugin callbacks that re-enter and erase info don't produce stale
signals.

Remove the trailing emit loop from createMetaFile and the now-redundant
notifyRowChanged calls scattered after setState. Add the two missing
emits in restoreDownload (after m_Hidden) and metaDataChanged (after
rename). Guard downloadFinished with a top-level DirWatcherGuard to
prevent filesystem events from its writes racing with model updates.

* Fix comma operator in addNXMDownload pending-dedup check

The game-name comparison result was discarded by the comma operator,
so the dedup only matched modId/fileId across all games.

* Fix lost finished() signal on fast downloads

Hoist the file-exists prompt out of startDownload so setup is straight-line.
Connect finished() last and dispatch manually if the reply already finished.

* Fix memory leak in DownloadInfo::createFromMeta

Move the allocation past the early-return checks so path-mismatch and
hidden-skip paths no longer leak a fresh DownloadInfo.

* Sanitize suffix path in getDownloadFileName

The collision-avoidance branch was using the raw baseName, so invalid
characters sanitized out of the initial path leaked into the suffixed one.

* [pre-commit.ci] Auto fixes from pre-commit.com hooks.

* Remove unused alphabetical translation vector

m_AlphabeticalTranslation was written but never read; drop it along with
refreshAlphabeticalTranslation, ByName, and the LessThanWrapper helper.

* Address PR feedback: fix redundant check and move refresh outside try catch.

* Coalesce the removeDownload reset with the following refreshList

Moves the ModelResetGuard out of the try-catch so it also wraps the
refreshList() call below. Without this, one reset fires when the guard
destructs at the end of the try block and another fires from
refreshList's own guard, producing two resets where one is sufficient.

* Guard the .meta creation in openMetaFile against the directory watcher

openMetaFile creates the .meta file via QSettings when one does not
exist; the disk write fires directoryChanged and triggers a spurious
refreshList. Wrap it in a DirWatcherManager::Guard like the other
meta-file editing paths.

* Extract getValidGameShortName method in download manager (#2380)

* Add stable download id index and PendingDownload struct

Replace the (game, mod, file) tuple backing m_PendingDownloads with a
named struct, and add m_ByID as an O(1) m_DownloadID-to-info index kept
in sync with every m_ActiveDownloads mutation. Encapsulate the id
counter behind DownloadInfo::newDownloadID(), the only supported way to
consume from s_NextDownloadID.

Infrastructure only; external behaviour is unchanged.

* Return stable ids from the plugin-facing download API

startDownloadURLs / startDownloadNexusFile / addNXMDownload now reserve
and return m_DownloadID instead of a stale index. Plugin callbacks fire
with m_DownloadID; downloadPath looks up via m_ByID. nxmDownloadURLsAvailable
threads the reserved id into the materializing DownloadInfo, and Nexus
API failures wake waiting plugins via notifyPendingDownloadFailed.

Incidental: startDownload now returns bool and frees newDownload on
output-open failure; createMetaFile is deferred past that check so
failed starts no longer leave an orphan .meta.

* Split downloadFinished into onReplyFinished slot and finishDownload

The old dual-use downloadFinished(int = 0) took either an explicit index
or relied on sender() when called as a slot. Split into a sender-resolved
slot and an id-based direct call, removing the ambiguous index-zero path.

* Introduce DownloadID alias and row/id accessors

Add a DownloadID type alias for the stable per-download handle and two
public accessors (downloadIDAtRow, rowForDownloadID) so callers can
translate between the view's row vocabulary and the model's id
vocabulary without reaching into the manager's internals. DownloadList
now embeds the DownloadID in QModelIndex::internalId() so any code
holding an index can identify the download directly.

* Convert cancel/pause/resume action methods to take DownloadID

The four methods (cancel, pause, resume, resumeDownloadInt) now accept
a DownloadID, resolve through m_ByID, and no longer care about row
positions. Internal callers iterate DownloadInfo* or look up via id;
DownloadsTab translates row -&gt; id at the connect boundary so the
view's int-shaped signals keep working unchanged.

Also switches the remaining unsigned int signatures that refer to the
download id (finishDownload, downloadInfoByID, PendingDownload::reservedID,
m_ByID, newDownloadID, s_NextDownloadID) to the DownloadID alias.

Drive-by fix: finishDownload's retry branch could read info-&gt;m_Tries
after info had been deleted in the CANCELED/retries-exhausted branch
above; now re-resolves via m_ByID.value(id) before touching any fields.

* [pre-commit.ci] Auto fixes from pre-commit.com hooks.

* fix warnings about unused variables and size_t types

* cleanup dead code

* avoid calling processEvents when releasing the DirWatcherGuard

* [pre-commit.ci] Auto fixes from pre-commit.com hooks.

* use QEventLoop instead of manual ProcessEvents

* don't call processEvents in download started and defer handling finish state in event loop

* Cleanup pending download in case of failure.

* Add missing notifyPendingDownloadFailed if user cancels

* [pre-commit.ci] Auto fixes from pre-commit.com hooks.

* Refactor pending download failure handling and cover rename failures

* fix rebase bug, addNXMDownload not returning the correct type

---------

Co-authored-by: pre-commit-ci[bot] &lt;66853113+pre-commit-ci[bot]@users.noreply.github.com&gt;
Co-authored-by: Jonathan Feenstra &lt;26406078+JonathanFeenstra@users.noreply.github.com&gt;</content>
</entry>
<entry>
<title>Add author and uploader columns to mod list (#2269)</title>
<updated>2025-08-18T05:55:52Z</updated>
<author>
<name>Jonathan Feenstra</name>
<email>26406078+JonathanFeenstra@users.noreply.github.com</email>
</author>
<published>2025-08-18T05:55:52Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=d52fcccb831b63dc1add068084369543d0a45246'/>
<id>urn:sha1:d52fcccb831b63dc1add068084369543d0a45246</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Mass Metadata Parsing: Prevent re-querying and manual prompts to enter missing data (#2135)</title>
<updated>2025-05-23T07:24:23Z</updated>
<author>
<name>Jonathan Feenstra</name>
<email>26406078+JonathanFeenstra@users.noreply.github.com</email>
</author>
<published>2025-05-23T07:24:23Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=5d766e94a7a3b3fa861d57d3ad6ae619d98dd5d8'/>
<id>urn:sha1:5d766e94a7a3b3fa861d57d3ad6ae619d98dd5d8</id>
<content type='text'>
* Add a button to "Query Info" of every download in the list

---------

Co-authored-by: Deewens &lt;dudonadrien@gmail.com&gt;
Co-authored-by: KenJyn76 &lt;liambonilla@gmail.com&gt;
Co-authored-by: Al &lt;26797547+Al12rs@users.noreply.github.com&gt;</content>
</entry>
<entry>
<title>Apply clang-format.</title>
<updated>2023-07-09T15:20:40Z</updated>
<author>
<name>Mikaël Capelle</name>
<email>capelle.mikael@gmail.com</email>
</author>
<published>2022-05-17T09:47:01Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=d13f6bb870cdda71257f665367be8ef9fca86255'/>
<id>urn:sha1:d13f6bb870cdda71257f665367be8ef9fca86255</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Fix download of meta-information in download tab.</title>
<updated>2021-01-31T17:59:52Z</updated>
<author>
<name>Mikaël Capelle</name>
<email>capelle.mikael@gmail.com</email>
</author>
<published>2021-01-31T17:59:52Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=ab0e050c466f1f69d8f3c8aa366e471c29a26cb2'/>
<id>urn:sha1:ab0e050c466f1f69d8f3c8aa366e471c29a26cb2</id>
<content type='text'>
</content>
</entry>
<entry>
<title>Rename DownloadListWidget -&gt; DownloadListView. Clean context menu.</title>
<updated>2021-01-15T19:12:19Z</updated>
<author>
<name>Mikaël Capelle</name>
<email>capelle.mikael@gmail.com</email>
</author>
<published>2021-01-15T19:12:19Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=ff3f24ff9e0e6e0785fdb29cef0d58f232abfc1e'/>
<id>urn:sha1:ff3f24ff9e0e6e0785fdb29cef0d58f232abfc1e</id>
<content type='text'>
</content>
</entry>
<entry>
<title>renamed DownloadList::lessThan to lessThanPredicate and added a comment that it's used with the filter widget</title>
<updated>2020-12-28T11:01:43Z</updated>
<author>
<name>isanae</name>
<email>14251494+isanae@users.noreply.github.com</email>
</author>
<published>2020-12-28T11:01:43Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=9b3e91b53e769aec2622eb79509945c09fca8897'/>
<id>urn:sha1:9b3e91b53e769aec2622eb79509945c09fca8897</id>
<content type='text'>
</content>
</entry>
<entry>
<title>removed setUpdateDelay(false) calls, it's the default</title>
<updated>2020-12-27T01:58:06Z</updated>
<author>
<name>isanae</name>
<email>14251494+isanae@users.noreply.github.com</email>
</author>
<published>2020-12-27T01:58:06Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=106ed49baecc60dbdf4844ed684df750e5caf3aa'/>
<id>urn:sha1:106ed49baecc60dbdf4844ed684df750e5caf3aa</id>
<content type='text'>
FilterWidget for downloads tab
</content>
</entry>
<entry>
<title>split downloads tab</title>
<updated>2020-12-27T00:51:47Z</updated>
<author>
<name>isanae</name>
<email>14251494+isanae@users.noreply.github.com</email>
</author>
<published>2020-12-27T00:51:47Z</published>
<link rel='alternate' type='text/html' href='http://git.schererleander.de/ariadne.git/commit/?id=3eb64c32e8643a34ce2de07bdb0f2fae2869b69a'/>
<id>urn:sha1:3eb64c32e8643a34ce2de07bdb0f2fae2869b69a</id>
<content type='text'>
</content>
</entry>
</feed>
