xref: /haiku/src/apps/haikudepot/packagemodel/PackageInfo.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
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 	fVersionCreateTimestamp(0),
28 	fPublisher(),
29 	fArchitecture(),
30 	fDepotName(""),
31 
32 	fLocalizedText(),
33 	fClassificationInfo(),
34 	fScreenshotInfo(),
35 	fUserRatingInfo(),
36 	fLocalInfo(),
37 
38 	fListeners(),
39 	fIsCollatingChanges(false),
40 	fCollatedChanges(0)
41 {
42 }
43 
44 
45 PackageInfo::PackageInfo(const BPackageInfo& info)
46 	:
47 	fName(info.Name()),
48 	fVersion(info.Version()),
49 	fVersionCreateTimestamp(0),
50 	fPublisher(),
51 	fArchitecture(info.ArchitectureName()),
52 	fDepotName(""),
53 
54 	fClassificationInfo(),
55 	fScreenshotInfo(),
56 	fUserRatingInfo(),
57 
58 	fListeners(),
59 	fIsCollatingChanges(false),
60 	fCollatedChanges(0)
61 {
62 	BString publisherURL;
63 	if (info.URLList().CountStrings() > 0)
64 		publisherURL = info.URLList().StringAt(0);
65 
66 	BString publisherName = info.Vendor();
67 	const BStringList& copyrightList = info.CopyrightList();
68 	if (!copyrightList.IsEmpty()) {
69 		publisherName = "";
70 
71 		for (int32 i = 0; i < copyrightList.CountStrings(); i++) {
72 			if (!publisherName.IsEmpty())
73 				publisherName << ", ";
74 			publisherName << copyrightList.StringAt(i);
75 		}
76 	}
77 	if (!publisherName.IsEmpty())
78 		publisherName.Prepend("© ");
79 
80 	fPublisher = PublisherInfo(publisherName, publisherURL);
81 
82 	fLocalizedText = PackageLocalizedTextRef(new PackageLocalizedText(), true);
83 	fLocalizedText->SetTitle(info.Name());
84 	fLocalizedText->SetSummary(info.Summary());
85 	fLocalizedText->SetDescription(info.Description());
86 
87 	// TODO: Retrieve local file size
88 	fLocalInfo = PackageLocalInfoRef(new PackageLocalInfo(), true);
89 	fLocalInfo->SetFlags(info.Flags());
90 	fLocalInfo->SetFileName(info.FileName());
91 }
92 
93 
94 PackageInfo::PackageInfo(const PackageInfo& other)
95 	:
96 	fName(other.fName),
97 	fVersion(other.fVersion),
98 	fVersionCreateTimestamp(other.fVersionCreateTimestamp),
99 	fPublisher(other.fPublisher),
100 	fArchitecture(other.fArchitecture),
101 	fDepotName(other.fDepotName),
102 
103 	fLocalizedText(other.fLocalizedText),
104 	fClassificationInfo(other.fClassificationInfo),
105 	fScreenshotInfo(other.fScreenshotInfo),
106 	fUserRatingInfo(other.fUserRatingInfo),
107 	fLocalInfo(other.fLocalInfo),
108 
109 	fListeners(),
110 	fIsCollatingChanges(false),
111 	fCollatedChanges(0)
112 {
113 }
114 
115 
116 PackageInfo&
117 PackageInfo::operator=(const PackageInfo& other)
118 {
119 	fName = other.fName;
120 	fVersion = other.fVersion;
121 	fVersionCreateTimestamp = other.fVersionCreateTimestamp;
122 	fPublisher = other.fPublisher;
123 	fLocalizedText = other.fLocalizedText;
124 	fClassificationInfo = other.fClassificationInfo;
125 	fScreenshotInfo = other.fScreenshotInfo;
126 	fUserRatingInfo = other.fUserRatingInfo;
127 	fArchitecture = other.fArchitecture;
128 	fDepotName = other.fDepotName;
129 	fLocalInfo = other.fLocalInfo;
130 
131 	return *this;
132 }
133 
134 
135 bool
136 PackageInfo::operator==(const PackageInfo& other) const
137 {
138 	return fName == other.fName
139 		&& fLocalInfo == other.fLocalInfo
140 		&& fVersion == other.fVersion
141 		&& fPublisher == other.fPublisher
142 		&& fLocalizedText == other.fLocalizedText
143 		&& fClassificationInfo == other.fClassificationInfo
144 		&& fScreenshotInfo == other.fScreenshotInfo
145 		&& fUserRatingInfo == fUserRatingInfo
146 		&& fArchitecture == other.fArchitecture
147 		&& fVersionCreateTimestamp == other.fVersionCreateTimestamp;
148 }
149 
150 
151 bool
152 PackageInfo::operator!=(const PackageInfo& other) const
153 {
154 	return !(*this == other);
155 }
156 
157 
158 uint32
159 PackageInfo::DiffMask(const PackageInfo& other) const
160 {
161 	uint32 result = 0;
162 	if (fLocalizedText != fLocalizedText)
163 		result |= PKG_CHANGED_LOCALIZED_TEXT;
164 	if (fScreenshotInfo != other.fScreenshotInfo)
165 		result |= PKG_CHANGED_SCREENSHOTS;
166 	if (fUserRatingInfo != other.fUserRatingInfo)
167 		result |= PKG_CHANGED_RATINGS;
168 	if (fLocalInfo != other.fLocalInfo)
169 		result |= PKG_CHANGED_LOCAL_INFO;
170 	if (fClassificationInfo != other.fClassificationInfo)
171 		result |= PKG_CHANGED_CLASSIFICATION;
172 	if (fVersionCreateTimestamp != other.fVersionCreateTimestamp)
173 		result |= PKG_CHANGED_VERSION_CREATE_TIMESTAMP;
174 	return result;
175 }
176 
177 
178 PackageLocalizedTextRef
179 PackageInfo::LocalizedText() const
180 {
181 	return fLocalizedText;
182 }
183 
184 
185 void
186 PackageInfo::SetLocalizedText(PackageLocalizedTextRef value)
187 {
188 	if (fLocalizedText != value) {
189 		fLocalizedText = value;
190 		_NotifyListeners(PKG_CHANGED_LOCALIZED_TEXT);
191 			// TODO; separate out these later - they are bundled for now to keep the existing
192 			// logic working.
193 	}
194 }
195 
196 
197 UserRatingInfoRef
198 PackageInfo::UserRatingInfo() const
199 {
200 	return fUserRatingInfo;
201 }
202 
203 
204 void
205 PackageInfo::SetUserRatingInfo(UserRatingInfoRef value)
206 {
207 	if (fUserRatingInfo != value) {
208 		fUserRatingInfo = value;
209 		_NotifyListeners(PKG_CHANGED_RATINGS);
210 	}
211 }
212 
213 
214 PackageLocalInfoRef
215 PackageInfo::LocalInfo() const
216 {
217 	return fLocalInfo;
218 }
219 
220 
221 void
222 PackageInfo::SetLocalInfo(PackageLocalInfoRef& localInfo)
223 {
224 	if (fLocalInfo != localInfo) {
225 		fLocalInfo = localInfo;
226 		_NotifyListeners(PKG_CHANGED_LOCAL_INFO);
227 	}
228 }
229 
230 
231 void
232 PackageInfo::SetPackageClassificationInfo(PackageClassificationInfoRef value)
233 {
234 	if (value != fClassificationInfo) {
235 		fClassificationInfo = value;
236 		_NotifyListeners(PKG_CHANGED_CLASSIFICATION);
237 	}
238 }
239 
240 
241 void
242 PackageInfo::SetScreenshotInfo(PackageScreenshotInfoRef value)
243 {
244 	if (value != fScreenshotInfo) {
245 		fScreenshotInfo = value;
246 		_NotifyListeners(PKG_CHANGED_SCREENSHOTS);
247 	}
248 }
249 
250 
251 void
252 PackageInfo::SetVersionCreateTimestamp(uint64 value)
253 {
254 	if (fVersionCreateTimestamp != value) {
255 		fVersionCreateTimestamp = value;
256 		_NotifyListeners(PKG_CHANGED_VERSION_CREATE_TIMESTAMP);
257 	}
258 }
259 
260 
261 void
262 PackageInfo::SetDepotName(const BString& depotName)
263 {
264 	fDepotName = depotName;
265 }
266 
267 
268 bool
269 PackageInfo::AddListener(const PackageInfoListenerRef& listener)
270 {
271 	fListeners.push_back(listener);
272 	return true;
273 }
274 
275 
276 void
277 PackageInfo::RemoveListener(const PackageInfoListenerRef& listener)
278 {
279 	fListeners.erase(std::remove(fListeners.begin(), fListeners.end(),
280 		listener), fListeners.end());
281 }
282 
283 
284 void
285 PackageInfo::NotifyChangedIcon()
286 {
287 	_NotifyListeners(PKG_CHANGED_ICON);
288 }
289 
290 
291 void
292 PackageInfo::StartCollatingChanges()
293 {
294 	fIsCollatingChanges = true;
295 	fCollatedChanges = 0;
296 }
297 
298 
299 void
300 PackageInfo::EndCollatingChanges()
301 {
302 	if (fIsCollatingChanges && fCollatedChanges != 0)
303 		_NotifyListenersImmediate(fCollatedChanges);
304 	fIsCollatingChanges = false;
305 	fCollatedChanges = 0;
306 }
307 
308 
309 void
310 PackageInfo::_NotifyListeners(uint32 changes)
311 {
312 	if (fIsCollatingChanges)
313 		fCollatedChanges |= changes;
314 	else
315 		_NotifyListenersImmediate(changes);
316 }
317 
318 
319 void
320 PackageInfo::_NotifyListenersImmediate(uint32 changes)
321 {
322 	if (fListeners.empty())
323 		return;
324 
325 	// Clone list to avoid listeners detaching themselves in notifications
326 	// to screw up the list while iterating it.
327 	std::vector<PackageInfoListenerRef> listeners(fListeners);
328 	PackageInfoEvent event(PackageInfoRef(this), changes);
329 
330 	std::vector<PackageInfoListenerRef>::iterator it;
331 	for (it = listeners.begin(); it != listeners.end(); it++) {
332 		const PackageInfoListenerRef listener = *it;
333 		if (listener.IsSet())
334 			listener->PackageChanged(event);
335 	}
336 }
337