+
+ // notify that a catalog is being removed
+ d->firePackagesChanged();
+
+ return ok;
+}
+
+void Root::requestThumbnailData(const std::string& aUrl)
+{
+ MemThumbnailCache::iterator it = d->thumbnailCache.find(aUrl);
+ if (it == d->thumbnailCache.end()) {
+ // insert into cache to mark as pending
+ d->pendingThumbnails.push_front(aUrl);
+ d->thumbnailCache[aUrl] = std::string();
+ d->downloadNextPendingThumbnail();
+ } else if (!it->second.empty()) {
+ // already loaded, fire data synchronously
+ d->fireDataForThumbnail(aUrl, it->second);
+ } else {
+ // in cache but empty data, still fetching
+ }
+}
+
+InstallRef Root::existingInstallForPackage(PackageRef p) const
+{
+ RootPrivate::InstallCache::const_iterator it =
+ d->m_installs.find(p);
+ if (it == d->m_installs.end()) {
+ // check if it exists on disk, create
+ SGPath path(p->pathOnDisk());
+ if (path.exists()) {
+ // this will add to our cache, and hence, modify m_installs
+ return Install::createFromPath(path, p->catalog());
+ }
+
+ // insert a null reference into the dictionary, so we don't call
+ // the pathOnDisk -> exists codepath repeatedley
+ d->m_installs[p] = InstallRef();
+ return InstallRef();
+ }
+
+ return it->second;
+}
+
+void Root::registerInstall(InstallRef ins)
+{
+ if (!ins.valid()) {
+ return;
+ }
+
+ d->m_installs[ins->package()] = ins;
+}
+
+void Root::unregisterInstall(InstallRef ins)
+{
+ if (!ins .valid()) {
+ return;
+ }
+
+ d->m_installs.erase(ins->package());