1 /***************************************************************************
2     Copyright (C) 2001-2009 Robby Stephenson <robby@periapsis.org>
3  ***************************************************************************/
4 
5 /***************************************************************************
6  *                                                                         *
7  *   This program is free software; you can redistribute it and/or         *
8  *   modify it under the terms of the GNU General Public License as        *
9  *   published by the Free Software Foundation; either version 2 of        *
10  *   the License or (at your option) version 3 or any later version        *
11  *   accepted by the membership of KDE e.V. (or its successor approved     *
12  *   by the membership of KDE e.V.), which shall act as a proxy            *
13  *   defined in Section 14 of version 3 of the license.                    *
14  *                                                                         *
15  *   This program is distributed in the hope that it will be useful,       *
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
18  *   GNU General Public License for more details.                          *
19  *                                                                         *
20  *   You should have received a copy of the GNU General Public License     *
21  *   along with this program.  If not, see <http://www.gnu.org/licenses/>. *
22  *                                                                         *
23  ***************************************************************************/
24 
25 #ifndef TELLICO_COLLECTION_H
26 #define TELLICO_COLLECTION_H
27 
28 #include "field.h"
29 #include "entry.h"
30 #include "filter.h"
31 #include "borrower.h"
32 #include "datavectors.h"
33 
34 #include <QStringList>
35 #include <QHash>
36 #include <QObject>
37 
38 namespace Tellico {
39   namespace Data {
40     class EntryGroup;
41     typedef QHash<QString, EntryGroup*> EntryGroupDict;
42 
43 /**
44  * The Collection class is the primary data object, holding a
45  * list of fields and entries.
46  *
47  * A collection holds entries of a single type, whether it be books, CDs, or whatever.
48  * It has a list of attributes which apply for the whole collection. A unique id value
49  * identifies each collection object.
50  *
51  * @see Entry
52  * @see Field
53  *
54  * @author Robby Stephenson
55  */
56 class Collection : public QObject, public QSharedData {
57 Q_OBJECT
58 
59 public:
60   enum Type {
61     Base = 1,
62     Book = 2,
63     Video = 3,
64     Album = 4,
65     Bibtex = 5,
66     ComicBook = 6,
67     Wine = 7,
68     Coin = 8,
69     Stamp = 9,
70     Card = 10,
71     Game = 11,
72     File = 12,
73     BoardGame = 13
74     // if you want to add custom collection types, use a number sure to be unique like 101
75     // don't forget to update macros in core/tellico_config_addons.cpp
76   };
77 
78   /**
79    * The constructor is only used to create custom collections.
80    *
81    * @param addDefaultFields whether to add default fields or not
82    * @param title The title of the collection itself
83    */
84   explicit Collection(bool addDefaultFields, const QString& title=QString());
85   /**
86    */
87   virtual ~Collection();
88 
89   /**
90    * Returns the type of the collection.
91    *
92    * @return The type
93    */
type()94   virtual Type type() const { return Base; }
95   /**
96    * Returns the id of the collection.
97    *
98    * @return The id
99    */
id()100   ID id() const { return m_id; }
101   /**
102    * Returns the name of the collection.
103    *
104    * @return The name
105    */
title()106   const QString& title() const { return m_title; }
107   /**
108    * Sets the title of the collection.
109    *
110    * @param title The new collection title
111    */
setTitle(const QString & title)112   void setTitle(const QString& title) { m_title = title; }
113   /**
114    * Returns a reference to the list of all the entries in the collection.
115    *
116    * @return The list of entries
117    */
entries()118   const EntryList& entries() const { return m_entries; }
119   /**
120    * Returns a reference to the list of the collection attributes.
121    *
122    * @return The list of fields
123    */
fields()124   const FieldList& fields() const { return m_fields; }
125   EntryPtr entryById(ID id);
126   /**
127    * Returns a reference to the list of the collection's people fields.
128    *
129    * @return The list of fields
130    */
peopleFields()131   const FieldList& peopleFields() const { return m_peopleFields; }
132   /**
133    * Returns a reference to the list of the collection's image fields.
134    *
135    * @return The list of fields
136    */
imageFields()137   const FieldList& imageFields() const { return m_imageFields; }
138   /**
139    * Return the primary image field, which is used for icons for the entry.
140    * By default, the first image field is returned.
141    *
142    * @return The primary image field
143    */
144   FieldPtr primaryImageField() const;
145   /**
146    * Returns a reference to the list of field groups. This value is cached rather
147    * than generated with each call, so the method should be fairly fast.
148    *
149    * @return The list of group names
150    */
fieldCategories()151   const QStringList& fieldCategories() const { return m_fieldCategories; }
152   /**
153    * Returns the name of the field used to group the entries by default.
154    *
155    * @return The field name
156    */
defaultGroupField()157   const QString& defaultGroupField() const { return m_defaultGroupField; }
158   /**
159    * Sets the name of the default field used to group the entries.
160    *
161    * @param name The name of the field
162    */
setDefaultGroupField(const QString & name)163   void setDefaultGroupField(const QString& name) { m_defaultGroupField = name; }
164   /**
165    * Returns the number of entries in the collection.
166    *
167    * @return The number of entries
168    */
entryCount()169   int entryCount() const { return m_entries.count(); }
170   /**
171    * Adds a entry to the collection. The collection takes ownership of the entry object.
172    *
173    * @param entry A pointer to the entry
174    */
175   void addEntries(const EntryList& entries);
addEntries(EntryPtr entry)176   void addEntries(EntryPtr entry) { addEntries(EntryList() << entry); }
177   /**
178    * Updates the dicts that include the entry.
179    *
180    * @param entry A pointer to the entry
181    */
182   void updateDicts(const EntryList& entries, const QStringList& fields);
183   /**
184    * Deletes a entry from the collection.
185    *
186    * @param entry The pointer to the entry
187    * @return A boolean indicating if the entry was in the collection and was deleted
188    */
189   bool removeEntries(const EntryList& entries);
entryIdList()190   QList<int> entryIdList() const { return m_entryById.keys(); }
191   /**
192    * Adds a whole list of fields. It calls
193    * @ref addField, which is virtual.
194    *
195    * @param list List of fields to add
196    * @return A boolean indicating if the fields were successfully added or not
197    */
198   bool addFields(FieldList list);
199   /**
200    * Adds an field to the collection, unless an field with that name
201    * already exists. The collection takes ownership of the field object.
202    *
203    * @param field A pointer to the field
204    * @return A boolean indicating if the field was added or not
205    */
206   virtual bool addField(FieldPtr field);
207   virtual bool mergeField(FieldPtr field);
208   virtual bool modifyField(FieldPtr field);
209   virtual bool removeField(FieldPtr field, bool force=false);
210   virtual bool removeField(const QString& name, bool force=false);
211   void reorderFields(const FieldList& list);
212 
213   // the reason this is not static is so I can call it from a collection pointer
214   // it also gets overridden for different collection types
215   // the return values should be compared against the GOOD and PERFECT
216   // static match constants
217   virtual int sameEntry(Data::EntryPtr, Data::EntryPtr) const;
218 
219   /**
220    * Determines whether or not a certain value is allowed for an field.
221    *
222    * @param field The name of the field
223    * @param value The desired value
224    * @return A boolean indicating if the value is an allowed value for that field
225    */
226   bool isAllowed(const QString& field, const QString& value) const;
227   /**
228    * Returns a list of all the field names.
229    *
230    * @return The list of names
231    */
232   QStringList fieldNames() const;
233   /**
234    * Returns a list of all the field titles.
235    *
236    * @return The list of titles
237    */
238   QStringList fieldTitles() const;
239   /**
240    * Returns the title of an field, given its name.
241    *
242    * @param name The field name
243    * @return The field title
244    */
245   QString fieldTitleByName(const QString& name) const;
246   /**
247    * Returns the name of an field, given its title.
248    *
249    * @param title The field title
250    * @return The field name
251    */
252   QString fieldNameByTitle(const QString& title) const;
253   /**
254    * Returns a list of the values of a given field for every entry
255    * in the collection. The values in the list are not repeated. Attribute
256    * values which contain ";" are split into separate values. Since this method
257    * iterates over all the entries, for large collections, it is expensive.
258    *
259    * @param name The name of the field
260    * @return The list of values
261    */
262   QStringList valuesByFieldName(const QString& name) const;
263   /**
264    * Returns a list of all the fields in a given category.
265    *
266    * @param category The name of the category
267    * @return The field list
268    */
269   FieldList fieldsByCategory(const QString& category);
270   /**
271    * Returns a pointer to an field given its name. If none is found, a NULL pointer
272    * is returned.
273    *
274    * @param name The field name
275    * @return The field pointer
276    */
277   FieldPtr fieldByName(const QString& name) const;
278   /**
279    * Returns a pointer to an field given its title. If none is found, a NULL pointer
280    * is returned. This lookup is slower than by name.
281    *
282    * @param title The field title
283    * @return The field pointer
284    */
285   FieldPtr fieldByTitle(const QString& title) const;
286   /**
287    * Returns @p true if the collection contains a field named @ref name;
288    */
289   bool hasField(const QString& name) const;
290   /**
291    * Returns a list of all the possible entry groups. This value is cached rather
292    * than generated with each call, so the method should be fairly fast.
293    *
294    * @return The list of groups
295    */
entryGroups()296   const QStringList& entryGroups() const { return m_entryGroups; }
297   /**
298    * Returns a pointer to a dict of all the entries grouped by
299    * a certain field
300    *
301    * @param name The name of the field by which the entries are grouped
302    * @return The list of group names
303    */
304   EntryGroupDict* entryGroupDictByName(const QString& name);
305   /**
306    * Invalidates all group names in the collection.
307    */
308   void invalidateGroups();
309   /**
310    * Returns true if the collection contains at least one Image field.
311    *
312    * @return Returns true if the collection contains at least one Image field;
313    */
hasImages()314   bool hasImages() const { return !m_imageFields.isEmpty(); }
315 
setTrackGroups(bool b)316   void setTrackGroups(bool b) { m_trackGroups = b; }
317 
318   void addBorrower(Data::BorrowerPtr borrower);
borrowers()319   const BorrowerList& borrowers() const { return m_borrowers; }
320   /**
321    * Clears all vectors which contain shared ptrs
322    */
323   void clear();
324 
325   void addFilter(FilterPtr filter);
326   bool removeFilter(FilterPtr filter);
filters()327   const FilterList& filters() const { return m_filters; }
328 
329   /**
330    * Prepare text for formatting
331    *
332    * Useful only for BibtexCollection to strip bibtex strings
333    */
334   virtual QString prepareText(const QString& text) const;
335 
336   /**
337    * The string used for the people pseudo-group. This forces consistency.
338    */
339   static const QString s_peopleGroupName;
340 
341 Q_SIGNALS:
342   void signalGroupsModified(Tellico::Data::CollPtr coll, QList<Tellico::Data::EntryGroup*> groups);
343   void signalRefreshField(Tellico::Data::FieldPtr field);
344   void mergeAddedField(Tellico::Data::CollPtr coll, Tellico::Data::FieldPtr field);
345 
346 protected:
347   Collection(const QString& title);
348 
349 private:
350   QStringList entryGroupNamesByField(EntryPtr entry, const QString& fieldName);
351   void removeEntriesFromDicts(const EntryList& entries, const QStringList& fields);
352   void populateDict(EntryGroupDict* dict, const QString& fieldName, const EntryList& entries);
353   void populateCurrentDicts(const EntryList& entries, const QStringList& fields);
354   void cleanGroups();
355 
356   /*
357    * Gets the preferred ID of the collection. Currently, it just gets incremented as
358    * new collections are created.
359    */
360   static int getID();
361 
362   Q_DISABLE_COPY(Collection)
363 
364   ID m_id;
365   ID m_nextEntryId;
366   QString m_title;
367   QString m_defaultGroupField;
368   QString m_lastGroupField;
369 
370   FieldList m_fields;
371   FieldList m_peopleFields; // keep separate list of people fields
372   FieldList m_imageFields; // keep track of image fields
373   QHash<QString, Field*> m_fieldByName;
374   QHash<QString, Field*> m_fieldByTitle;
375   QStringList m_fieldCategories;
376 
377   EntryList m_entries;
378   QHash<int, Entry*> m_entryById;
379 
380   QHash<QString, EntryGroupDict*> m_entryGroupDicts;
381   QStringList m_entryGroups;
382   QList<EntryGroup*> m_groupsToDelete;
383 
384   FilterList m_filters;
385   BorrowerList m_borrowers;
386 
387   bool m_trackGroups;
388 };
389 
390   } // end namespace
391 } //end namespace
392 #endif
393