summaryrefslogtreecommitdiff
path: root/mg_selection.h
diff options
context:
space:
mode:
Diffstat (limited to 'mg_selection.h')
-rw-r--r--mg_selection.h468
1 files changed, 468 insertions, 0 deletions
diff --git a/mg_selection.h b/mg_selection.h
new file mode 100644
index 0000000..af897e0
--- /dev/null
+++ b/mg_selection.h
@@ -0,0 +1,468 @@
+/*!
+ * \file mg_selection.h
+ * \brief A general interface to data items, currently only GiantDisc
+ *
+ * \version $Revision: 1.0 $
+ * \date $Date: 2004-12-07 10:10:35 +0200 (Tue, 07 Dec 2004) $
+ * \author Wolfgang Rohdewald
+ * \author Responsible author: $Author: wr $
+ *
+ */
+
+#ifndef _MG_SELECTION_H
+#define _MG_SELECTION_H
+#include <stdlib.h>
+#include <string>
+#include <list>
+#include <vector>
+#include <map>
+using namespace std;
+
+#include "mg_tools.h"
+#include "mg_valmap.h"
+#include "mg_order.h"
+#include "mg_content.h"
+
+typedef vector<string> strvector;
+
+
+/*!
+ * \brief the only interface to the database.
+ * Some member functions are declared const although they can modify the inner state of mgSelection.
+ * But they only modify variables used for caching. With const, we want to express
+ * the logical constness. E.g. the selected tracks can change without breaking constness:
+ * The selection never defines concrete tracks but only how to choose them.
+ */
+class mgSelection
+{
+ private:
+ class mgSelStrings
+ {
+ friend class mgSelection;
+ private:
+ strvector strings;
+ mgSelection* m_sel;
+ void setOwner(mgSelection* sel);
+ public:
+ string& operator[](unsigned int idx);
+ bool operator==(const mgSelStrings&x) const;
+ size_t size() const;
+ };
+ public:
+//! \brief defines an order to be used
+ void setOrder(mgOrder *o);
+
+ mgOrder& getOrder() { return order; }
+
+/*! \brief define various ways to play music in random order
+ * \todo Party mode is not implemented, does same as SM_NORMAL
+ */
+ enum ShuffleMode
+ {
+ SM_NONE, //!< \brief play normal sequence
+ SM_NORMAL, //!< \brief a shuffle with a fair distribution
+ SM_PARTY //!< \brief select the next few songs randomly, continue forever
+ };
+
+//! \brief define various ways to play music in a neverending loop
+ enum LoopMode
+ {
+ LM_NONE, //!< \brief do not loop
+ LM_SINGLE, //!< \brief loop a single track
+ LM_FULL //!< \brief loop the whole track list
+ };
+
+/*! \brief the main constructor
+ * \param fall_through if TRUE: If enter() returns a choice
+ * containing only one item, that item is automatically entered.
+ * The analog happens with leave()
+ */
+ mgSelection ( const bool fall_through = false);
+
+/*! \brief a copy constructor. Does a deep copy.
+ * Some of the data base content will only be retrieved by the
+ * new mgSelection as needed, so some data base
+ * overhead is involved
+ */
+ mgSelection (const mgSelection& s);
+/*! \brief a copy constructor. Does a deep copy.
+ * Some of the data base content will only be retrieved by the
+ * new mgSelection as needed, so some data base
+ * overhead is involved
+ */
+ mgSelection (const mgSelection* s);
+
+
+//! \brief initializes from a map.
+ void InitFrom(mgValmap& nv);
+
+//! \brief the normal destructor
+ ~mgSelection ();
+
+/*! \brief represents all values for the current level. The result
+ * is cached in values, subsequent accesses to values only incur a
+ * small overhead for building the SQL WHERE command. The values will
+ * be reloaded when the SQL command changes
+ */
+ mutable mgSelStrings values;
+
+/*! \brief returns the name of a key
+ */
+ mgKeyTypes getKeyType (const unsigned int level) const;
+
+//! \brief return the current value of this key
+ string getKeyValue (const unsigned int level) const;
+ unsigned int getKeyIndex(const unsigned int level) const;
+
+/*! \brief returns the current item from the value() list
+ */
+ string getCurrentValue();
+
+//! \brief returns a map (new allocated) for all used key fields and their values
+ map<mgKeyTypes,string> UsedKeyValues();
+
+//! \brief the number of key fields used for the query
+ unsigned int ordersize ();
+
+//! \brief the number of music items currently selected
+ unsigned int count () const;
+
+//! \brief the current position
+ unsigned int getPosition ()const;
+
+ //! \brief go to the current position. If it does not exist,
+ // go to the nearest.
+ unsigned int gotoPosition ();
+
+
+//! \brief the current position in the tracks list
+ unsigned int getTrackPosition () const;
+
+ //! \brief go to the current track position. If it does not exist,
+ // go to the nearest.
+ unsigned int gotoTrackPosition ();
+
+/*! \brief enter the the next higher level, go one up in the tree.
+ * If fall_through (see constructor) is set to true, and the
+ * level entered by enter() contains only one item, automatically
+ * goes down further until a level with more than one item is reached.
+ * \param position is the position in the current level that is to be expanded
+ * \return returns false if there is no further level
+ */
+ bool enter (unsigned int position);
+
+ /*! \brief like enter but if we are at the leaf level simply select
+ * the entry at position
+ */
+ bool select (unsigned int position);
+
+/*! \brief enter the next higher level, expanding the current position.
+ * See also enter(unsigned int position)
+ */
+ bool enter ()
+ {
+ return enter (gotoPosition ());
+ }
+
+ /*! \brief like enter but if we are at the leaf level simply select
+ * the current entry
+ */
+ bool select ()
+ {
+ return select (gotoPosition ());
+ }
+
+/*! \brief enter the next higher level, expanding the position holding a certain value
+ * \param value the position holding value will be expanded.
+ */
+ bool enter (const string value)
+ {
+ return enter (valindex (value));
+ }
+
+ /*! \brief like enter but if we are at the leaf level simply select
+ * the current entry
+ */
+ bool select (const string value)
+ {
+ return select (valindex(value));
+ }
+
+ bool selectid (const string id)
+ {
+ return select(idindex(id));
+ }
+
+ void selectfrom(mgOrder& oldorder,mgContentItem* o);
+
+/*! \brief leave the current level, go one up in the tree.
+ * If fall_through (see constructor) is set to true, and the
+ * level entered by leave() contains only one item, automatically
+ * goes up further until a level with more than one item is reached.
+ * \return returns false if there is no further upper level
+ */
+ bool leave ();
+
+/*! \brief leave the current level, go up in the tree until
+ * target level is reached.
+ * If fall_through (see constructor) is set to true, and the
+ * level entered by leave() contains only one item, automatically
+ * goes up further until a level with more than one item is reached.
+ * \return returns false if there is no further upper level
+ */
+ void leave_all ();
+
+//! \brief the current level in the tree
+ unsigned int level () const
+ {
+ return m_level;
+ }
+
+ //! \brief true if the selection holds no items
+ bool empty();
+
+/*! \brief returns detailed info about all selected tracks.
+ * The ordering is done only by the keyfield of the current level.
+ * This might have to be changed - suborder by keyfields of detail
+ * levels. This list is cached so several consequent calls mean no
+ * loss of performance. See value(), the same warning applies.
+ * \todo call this more seldom. See getNumTracks()
+ */
+ const vector < mgContentItem > &tracks () const;
+
+/*! \brief returns an item from the tracks() list
+ * \param position the position in the tracks() list
+ * \return returns NULL if position is out of range
+ */
+ mgContentItem* getTrack (unsigned int position);
+
+/*! \brief returns the current item from the tracks() list
+ */
+ mgContentItem* getCurrentTrack ()
+ {
+ return getTrack (gotoTrackPosition());
+ }
+
+/*! \brief toggles the shuffle mode thru all possible values.
+ * When a shuffle modus SM_NORMAL or SM_PARTY is selected, the
+ * order of the tracks in the track list will be randomly changed.
+ */
+ ShuffleMode toggleShuffleMode ();
+
+//! \brief toggles the loop mode thru all possible values
+ LoopMode toggleLoopMode ();
+
+//! \brief returns the current shuffle mode
+ ShuffleMode getShuffleMode () const
+ {
+ return m_shuffle_mode;
+ }
+
+//! \brief sets the current shuffle mode
+ void setShuffleMode (const ShuffleMode shuffle_mode);
+
+//! \brief returns the current loop mode
+ LoopMode getLoopMode () const
+ {
+ return m_loop_mode;
+ }
+
+//! \brief sets the current loop mode
+ void setLoopMode (const LoopMode loop_mode)
+ {
+ m_loop_mode = loop_mode;
+ }
+
+/*! \brief adds the whole current track list to a collection
+ * \param Name the name of the collection. If it does not yet exist,
+ * it will be created.
+ */
+ unsigned int AddToCollection (const string Name);
+
+/*! \brief removes the whole current track from a the collection
+ * Remember - this selection can be configured to hold exactly
+ * one list, so this command can be used to clear a selected list.
+ * \param Name the name of the collection
+ */
+ unsigned int RemoveFromCollection (const string Name);
+//! \brief delete a collection
+ bool DeleteCollection (const string Name);
+/*! \brief create a collection only if it does not yet exist.
+ * \return true only if it has been created. false if it already existed.
+ */
+ bool CreateCollection(const string Name);
+
+//! \brief remove all items from the collection
+ void ClearCollection (const string Name);
+
+/*! generates an m3u file containing all tracks. The directory
+ * can be indicated by SetDirectory().
+ * The file name will be built from the list name, slashes
+ * and spaces converted
+ */
+ string exportM3U ();
+
+
+/*! \brief go to a position in the current level. If we are at the
+ * most detailled level this also sets the track position since
+ * they are identical.
+ * \param position the wanted position. If it is too big, go to the
+ * last existing position
+ * \return only if no position exists, false will be returned
+ */
+ void setPosition (unsigned int position);
+
+/*! \brief go to the position with value in the current level
+ * \param value the value of the wanted position
+ */
+ void setPosition (const string value)
+ {
+ setPosition (valindex (value));
+ }
+
+/*! \brief go to a position in the track list
+ * \param position the wanted position. If it is too big, go to the
+ * last existing position
+ * \return only if no position exists, false will be returned
+ */
+ void setTrackPosition (unsigned int position) const;
+
+/*! \brief skip some tracks in the track list
+ * \return false if new position does not exist
+ */
+ bool skipTracks (int step=1);
+
+/*! \brief skip forward by 1 in the track list
+ * \return false if new position does not exist
+ */
+ bool skipFwd ()
+ {
+ return skipTracks (+1);
+ }
+
+/*! \brief skip back by 1 in the track list
+ * \return false if new position does not exist
+ */
+ bool skipBack ()
+ {
+ return skipTracks (-1);
+ }
+
+//! \brief returns the sum of the durations of all tracks
+ unsigned long getLength ();
+
+/*! \brief returns the sum of the durations of completed tracks
+ * those are tracks before the current track position
+ */
+ unsigned long getCompletedLength () const;
+
+/*! returns the number of tracks in the track list
+ * \todo should not call tracks () which loads all track info.
+ * instead, only count the tracks. If the size differs from
+ * m_tracks.size(), invalidate m_tracks
+ */
+ unsigned int getNumTracks () const
+ {
+ return tracks ().size ();
+ }
+
+//! sets the directory for the storage of m3u file
+ void SetDirectory (const string directory)
+ {
+ m_Directory = directory;
+ }
+
+/*! returns the name of the current play list. If no play list is active,
+ * the name is built from the name of the key fields.
+ */
+ string getListname () const;
+
+/*! \brief true if this selection currently selects a list of collections
+ */
+ bool isCollectionlist () const;
+
+/*! \brief true if this selection currently selects a list of languages
+ */
+ bool isLanguagelist () const;
+
+ //! \brief true if we have entered a collection
+ bool inCollection(const string Name="") const;
+
+ /*! \brief dumps the entire state of this selection into a map,
+ * \param nv the values will be entered into this map
+ */
+ void DumpState(mgValmap& nv) const;
+
+ /*! \brief creates a new selection using saved definitions
+ * \param nv this map contains the saved definitions
+ */
+ mgSelection(mgValmap& nv);
+
+ //! \brief clear the cache, next access will reload from data base
+ void clearCache() const;
+
+ void refreshValues() const;
+
+ //! \brief true if values and tracks need to be reloaded
+ bool cacheIsEmpty() const
+ {
+ return (m_current_values=="" && m_current_tracks=="");
+ }
+ string value(mgKeyTypes kt, string id) const;
+ string value(mgKey* k, string id) const;
+ string value(mgKey* k) const;
+ string id(mgKeyTypes kt, string val) const;
+ string id(mgKey* k, string val) const;
+ string id(mgKey* k) const;
+ unsigned int keycount(mgKeyTypes kt);
+ vector <const char *> choices(mgOrder *o,unsigned int level, unsigned int *current);
+ unsigned int valcount (string val);
+ bool Connected() { return m_db.Connected(); }
+
+ private:
+ mutable map <mgKeyTypes, map<string,string> > map_values;
+ mutable map <mgKeyTypes, map<string,string> > map_ids;
+ mutable string m_current_values;
+ mutable string m_current_tracks;
+//! \brief be careful when accessing this, see mgSelection::tracks()
+ mutable vector < mgContentItem > m_tracks;
+ mutable strvector m_ids;
+ mutable vector < unsigned int > m_counts;
+ //! \brief initializes maps for id/value mapping in both direction
+ bool loadvalues (mgKeyTypes kt) const;
+ bool m_fall_through;
+ unsigned int m_position;
+ mutable unsigned int m_tracks_position;
+ ShuffleMode m_shuffle_mode;
+ void Shuffle() const;
+ LoopMode m_loop_mode;
+ mutable mgmySql m_db;
+ unsigned int m_level;
+ long m_trackid;
+
+ mgOrder order;
+ bool UsedBefore (mgOrder *o,const mgKeyTypes kt, unsigned int level) const;
+ void InitSelection ();
+ /*! \brief returns the SQL command for getting all values.
+ * For the leaf level, all values are returned. For upper
+ * levels, every distinct value is returned only once.
+ * This must be so for the leaf level because otherwise
+ * the value() entries do not correspond to the track()
+ * entries and the wrong tracks might be played.
+ */
+ string sql_values ();
+ unsigned int valindex (const string val,const bool second_try=false) const;
+ unsigned int idindex (const string val,const bool second_try=false) const;
+ string ListFilename ();
+ string m_Directory;
+ void loadgenres ();
+
+ void InitFrom(const mgSelection* s);
+
+};
+
+
+unsigned int randrange (const unsigned int high);
+
+
+#endif // _DB_H