xref: /haiku/src/apps/haikudepot/packagemodel/PackageInfo.cpp (revision 592a3b6921f10ad84e44ad74e066c23466ab85cb)
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