1 /* 2 * Copyright 2013-2014, Stephan Aßmus <superstippi@gmx.de>. 3 * Copyright 2013, Rene Gollent <rene@gollent.com>. 4 * Copyright 2016-2024, Andrew Lindesay <apl@lindesay.co.nz>. 5 * All rights reserved. Distributed under the terms of the MIT License. 6 */ 7 8 9 #include "PackageInfo.h" 10 11 #include <algorithm> 12 13 #include <package/PackageDefs.h> 14 #include <package/PackageFlags.h> 15 16 #include "HaikuDepotConstants.h" 17 #include "Logger.h" 18 19 20 // #pragma mark - PackageInfo 21 22 23 PackageInfo::PackageInfo() 24 : 25 fName(), 26 fVersion(), 27 fPublisher(), 28 fLocalizedText(), 29 fPackageClassificationInfo(), 30 fScreenshotInfos(), 31 fUserRatingInfo(), 32 fState(NONE), 33 fDownloadProgress(0.0), 34 fFlags(0), 35 fSystemDependency(false), 36 fArchitecture(), 37 fLocalFilePath(), 38 fFileName(), 39 fSize(0), 40 fDepotName(""), 41 fViewed(false), 42 fIsCollatingChanges(false), 43 fCollatedChanges(0), 44 fVersionCreateTimestamp(0) 45 { 46 } 47 48 49 PackageInfo::PackageInfo(const BPackageInfo& info) 50 : 51 fName(info.Name()), 52 fVersion(info.Version()), 53 fPublisher(), 54 fPackageClassificationInfo(), 55 fScreenshotInfos(), 56 fUserRatingInfo(), 57 fState(NONE), 58 fDownloadProgress(0.0), 59 fFlags(info.Flags()), 60 fSystemDependency(false), 61 fArchitecture(info.ArchitectureName()), 62 fLocalFilePath(), 63 fFileName(info.FileName()), 64 fSize(0), // TODO: Retrieve local file size 65 fDepotName(""), 66 fViewed(false), 67 fIsCollatingChanges(false), 68 fCollatedChanges(0), 69 fVersionCreateTimestamp(0) 70 { 71 BString publisherURL; 72 if (info.URLList().CountStrings() > 0) 73 publisherURL = info.URLList().StringAt(0); 74 75 BString publisherName = info.Vendor(); 76 const BStringList& copyrightList = info.CopyrightList(); 77 if (!copyrightList.IsEmpty()) { 78 publisherName = ""; 79 80 for (int32 i = 0; i < copyrightList.CountStrings(); i++) { 81 if (!publisherName.IsEmpty()) 82 publisherName << ", "; 83 publisherName << copyrightList.StringAt(i); 84 } 85 } 86 if (!publisherName.IsEmpty()) 87 publisherName.Prepend("© "); 88 89 fPublisher = PublisherInfo(publisherName, publisherURL); 90 91 fLocalizedText = PackageLocalizedTextRef(new PackageLocalizedText(), true); 92 fLocalizedText->SetTitle(info.Name()); 93 fLocalizedText->SetSummary(info.Summary()); 94 fLocalizedText->SetDescription(info.Description()); 95 } 96 97 98 PackageInfo::PackageInfo(const PackageInfo& other) 99 : 100 fName(other.fName), 101 fVersion(other.fVersion), 102 fPublisher(other.fPublisher), 103 fLocalizedText(other.fLocalizedText), 104 fPackageClassificationInfo(other.fPackageClassificationInfo), 105 fScreenshotInfos(other.fScreenshotInfos), 106 fUserRatingInfo(other.fUserRatingInfo), 107 fState(other.fState), 108 fInstallationLocations(other.fInstallationLocations), 109 fDownloadProgress(other.fDownloadProgress), 110 fFlags(other.fFlags), 111 fSystemDependency(other.fSystemDependency), 112 fArchitecture(other.fArchitecture), 113 fLocalFilePath(other.fLocalFilePath), 114 fFileName(other.fFileName), 115 fSize(other.fSize), 116 fDepotName(other.fDepotName), 117 fViewed(other.fViewed), 118 fIsCollatingChanges(false), 119 fCollatedChanges(0), 120 fVersionCreateTimestamp(other.fVersionCreateTimestamp) 121 { 122 } 123 124 125 PackageInfo& 126 PackageInfo::operator=(const PackageInfo& other) 127 { 128 fName = other.fName; 129 fVersion = other.fVersion; 130 fPublisher = other.fPublisher; 131 fLocalizedText = other.fLocalizedText; 132 fPackageClassificationInfo = other.fPackageClassificationInfo; 133 fScreenshotInfos = other.fScreenshotInfos; 134 fUserRatingInfo = other.fUserRatingInfo; 135 fState = other.fState; 136 fInstallationLocations = other.fInstallationLocations; 137 fDownloadProgress = other.fDownloadProgress; 138 fFlags = other.fFlags; 139 fSystemDependency = other.fSystemDependency; 140 fArchitecture = other.fArchitecture; 141 fLocalFilePath = other.fLocalFilePath; 142 fFileName = other.fFileName; 143 fSize = other.fSize; 144 fDepotName = other.fDepotName; 145 fViewed = other.fViewed; 146 fVersionCreateTimestamp = other.fVersionCreateTimestamp; 147 148 return *this; 149 } 150 151 152 bool 153 PackageInfo::operator==(const PackageInfo& other) const 154 { 155 return fName == other.fName 156 && fVersion == other.fVersion 157 && fPublisher == other.fPublisher 158 && fLocalizedText == other.fLocalizedText 159 && fPackageClassificationInfo == other.fPackageClassificationInfo 160 && fScreenshotInfos == other.fScreenshotInfos 161 && fUserRatingInfo == fUserRatingInfo 162 && fState == other.fState 163 && fFlags == other.fFlags 164 && fDownloadProgress == other.fDownloadProgress 165 && fSystemDependency == other.fSystemDependency 166 && fArchitecture == other.fArchitecture 167 && fLocalFilePath == other.fLocalFilePath 168 && fFileName == other.fFileName 169 && fSize == other.fSize 170 && fVersionCreateTimestamp == other.fVersionCreateTimestamp; 171 } 172 173 174 bool 175 PackageInfo::operator!=(const PackageInfo& other) const 176 { 177 return !(*this == other); 178 } 179 180 181 PackageLocalizedTextRef 182 PackageInfo::LocalizedText() const 183 { 184 return fLocalizedText; 185 } 186 187 188 void 189 PackageInfo::SetLocalizedText(PackageLocalizedTextRef value) 190 { 191 if (fLocalizedText != value) { 192 fLocalizedText = value; 193 _NotifyListeners(PKG_CHANGED_LOCALIZED_TEXT); 194 _NotifyListeners(PKG_CHANGED_CHANGELOG); 195 // TODO; separate out these later - they are bundled for now to keep the existing 196 // logic working. 197 } 198 } 199 200 201 bool 202 PackageInfo::IsSystemPackage() const 203 { 204 return (fFlags & BPackageKit::B_PACKAGE_FLAG_SYSTEM_PACKAGE) != 0; 205 } 206 207 208 void 209 PackageInfo::SetPackageClassificationInfo(PackageClassificationInfoRef value) 210 { 211 if (value != fPackageClassificationInfo) { 212 fPackageClassificationInfo = value; 213 _NotifyListeners(PKG_CHANGED_CLASSIFICATION); 214 } 215 } 216 217 218 void 219 PackageInfo::SetSystemDependency(bool isDependency) 220 { 221 fSystemDependency = isDependency; 222 } 223 224 225 void 226 PackageInfo::SetState(PackageState state) 227 { 228 if (fState != state) { 229 fState = state; 230 if (fState != DOWNLOADING) 231 fDownloadProgress = 0.0; 232 _NotifyListeners(PKG_CHANGED_STATE); 233 } 234 } 235 236 237 void 238 PackageInfo::AddInstallationLocation(int32 location) 239 { 240 fInstallationLocations.insert(location); 241 SetState(ACTIVATED); 242 // TODO: determine how to differentiate between installed and active. 243 } 244 245 246 void 247 PackageInfo::ClearInstallationLocations() 248 { 249 fInstallationLocations.clear(); 250 } 251 252 253 void 254 PackageInfo::SetDownloadProgress(float progress) 255 { 256 fState = DOWNLOADING; 257 fDownloadProgress = progress; 258 _NotifyListeners(PKG_CHANGED_STATE); 259 } 260 261 262 void 263 PackageInfo::SetLocalFilePath(const char* path) 264 { 265 fLocalFilePath = path; 266 } 267 268 269 bool 270 PackageInfo::IsLocalFile() const 271 { 272 return !fLocalFilePath.IsEmpty() && fInstallationLocations.empty(); 273 } 274 275 276 UserRatingInfoRef 277 PackageInfo::UserRatingInfo() 278 { 279 return fUserRatingInfo; 280 } 281 282 283 void 284 PackageInfo::SetUserRatingInfo(UserRatingInfoRef value) 285 { 286 if (fUserRatingInfo != value) { 287 fUserRatingInfo = value; 288 _NotifyListeners(PKG_CHANGED_RATINGS); 289 } 290 } 291 292 293 void 294 PackageInfo::ClearScreenshotInfos() 295 { 296 if (!fScreenshotInfos.empty()) { 297 fScreenshotInfos.clear(); 298 _NotifyListeners(PKG_CHANGED_SCREENSHOTS); 299 } 300 } 301 302 303 int32 304 PackageInfo::CountScreenshotInfos() const 305 { 306 return fScreenshotInfos.size(); 307 } 308 309 310 ScreenshotInfoRef 311 PackageInfo::ScreenshotInfoAtIndex(int32 index) const 312 { 313 return fScreenshotInfos[index]; 314 } 315 316 317 void 318 PackageInfo::AddScreenshotInfo(const ScreenshotInfoRef& info) 319 { 320 fScreenshotInfos.push_back(info); 321 _NotifyListeners(PKG_CHANGED_SCREENSHOTS); 322 } 323 324 325 void 326 PackageInfo::SetSize(int64 size) 327 { 328 if (fSize != size) { 329 fSize = size; 330 _NotifyListeners(PKG_CHANGED_SIZE); 331 } 332 } 333 334 335 void 336 PackageInfo::SetViewed() 337 { 338 fViewed = true; 339 } 340 341 342 void 343 PackageInfo::SetVersionCreateTimestamp(uint64 value) 344 { 345 if (fVersionCreateTimestamp != value) { 346 fVersionCreateTimestamp = value; 347 _NotifyListeners(PKG_CHANGED_VERSION_CREATE_TIMESTAMP); 348 } 349 } 350 351 352 void 353 PackageInfo::SetDepotName(const BString& depotName) 354 { 355 if (fDepotName != depotName) { 356 fDepotName = depotName; 357 _NotifyListeners(PKG_CHANGED_DEPOT); 358 } 359 } 360 361 362 bool 363 PackageInfo::AddListener(const PackageInfoListenerRef& listener) 364 { 365 fListeners.push_back(listener); 366 return true; 367 } 368 369 370 void 371 PackageInfo::RemoveListener(const PackageInfoListenerRef& listener) 372 { 373 fListeners.erase(std::remove(fListeners.begin(), fListeners.end(), 374 listener), fListeners.end()); 375 } 376 377 378 void 379 PackageInfo::NotifyChangedIcon() 380 { 381 _NotifyListeners(PKG_CHANGED_ICON); 382 } 383 384 385 void 386 PackageInfo::StartCollatingChanges() 387 { 388 fIsCollatingChanges = true; 389 fCollatedChanges = 0; 390 } 391 392 393 void 394 PackageInfo::EndCollatingChanges() 395 { 396 if (fIsCollatingChanges && fCollatedChanges != 0) 397 _NotifyListenersImmediate(fCollatedChanges); 398 fIsCollatingChanges = false; 399 fCollatedChanges = 0; 400 } 401 402 403 void 404 PackageInfo::_NotifyListeners(uint32 changes) 405 { 406 if (fIsCollatingChanges) 407 fCollatedChanges |= changes; 408 else 409 _NotifyListenersImmediate(changes); 410 } 411 412 413 void 414 PackageInfo::_NotifyListenersImmediate(uint32 changes) 415 { 416 if (fListeners.empty()) 417 return; 418 419 // Clone list to avoid listeners detaching themselves in notifications 420 // to screw up the list while iterating it. 421 std::vector<PackageInfoListenerRef> listeners(fListeners); 422 PackageInfoEvent event(PackageInfoRef(this), changes); 423 424 std::vector<PackageInfoListenerRef>::iterator it; 425 for (it = listeners.begin(); it != listeners.end(); it++) { 426 const PackageInfoListenerRef listener = *it; 427 if (listener.IsSet()) 428 listener->PackageChanged(event); 429 } 430 } 431 432 433 const char* package_state_to_string(PackageState state) 434 { 435 switch (state) { 436 case NONE: 437 return "NONE"; 438 case INSTALLED: 439 return "INSTALLED"; 440 case DOWNLOADING: 441 return "DOWNLOADING"; 442 case ACTIVATED: 443 return "ACTIVATED"; 444 case UNINSTALLED: 445 return "UNINSTALLED"; 446 case PENDING: 447 return "PENDING"; 448 default: 449 debugger("unknown package state"); 450 return "???"; 451 } 452 } 453