1 /* $Id: joblist.hh,v 1.10 2005/04/09 23:09:52 atterer Exp $ -*- C++ -*-
3 |_) /| Copyright (C) 2001-2003 | richard@
4 | \/¯| Richard Atterer | atterer.org
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License, version 2. See
8 the file COPYING for details.
12 Interface to the GtkTreeView of running jobs (downloads etc),
13 GUI::window.jobs, i.e. the list at the bottom of the jigdo window.
29 #include <download.hh>
34 //______________________________________________________________________
36 /** A bit like a vector<JobLine*>, but uses the GtkTreeStore for storing the
37 elements. There can be empty entries in the vector which hold null
38 pointers and which are displayed as empty lines on screen.
40 ~JobList deletes all JobLine objects in the list. */
41 class JobList : NoCopy {
44 /** Pixmap "% done" + text message ("x kB/sec" etc) */
48 /** pointer to JobLine object (not displayed on screen) */
50 /** Assumed number of columns in job display (progress bar, URL) */
53 static const int WIDTH_STATUS = 280;
55 /** Time values are in milliseconds. All values should be multiples
57 static const int TICK_INTERVAL = 250; // = progress report update interval
59 LOCAL_DEBUG_UNIT_DECL;
61 typedef unsigned size_type;
63 /** Any Jobs still in the list are deleted */
65 /** Like the dtor; later call to the dtor will not cause anything to
69 /** The GTK data structure that contains the linked list of items for this
71 inline GtkTreeStore* store() const;
72 /** The GTK data structure responsible for drawing this list on screen.
73 Currently, we cheat and always return the same static object,
74 GUI::window.jobs, rather than storing a pointer in the JobList. This
75 only works as long as only one JobList is ever created. */
76 inline GtkTreeView* view() const;
78 /** Size *includes* null pointer entries. */
79 inline size_type size() const;
80 /** Number of non-null entries (always <= size()) */
81 inline size_type entryCount() const;
82 inline bool empty() const;
84 /** Retrieve the data for a list entry */
85 inline JobLine* get(GtkTreeIter* row) const;
86 /** Simply overwrites pointer, will not delete the old entry */
87 inline void set(size_type n, JobLine* j);
88 /** Deletes row from the list. The Job object pointed to by the entry is
90 void erase(GtkTreeIter* row);
91 /** Insert new JobLine before position n. Calls j->run() so the Job can
93 inline void insert(size_type n, JobLine* j);
94 /** Add new JobLine at start of list, or as first child of parent if parent
95 != 0. Also scrolls to the top to display the new entry. You should call
96 j->run() after this so the Job can visualize itself. */
97 void prepend(JobLine* j, JobLine* parent = 0);
98 /** Append new JobLine at end of list or as last child of parent if parent
99 != 0. You should call j->run() after this so the Job can visualize
101 void append(JobLine* j, JobLine* parent = 0);
102 /** Make row blank by setting text labels to "". Sets data pointer to 0,
103 like erase() does *not* delete JobLine object of that row. */
104 void makeRowBlank(GtkTreeIter* row);
106 /** Set a static var of the JobList class to the supplied value. The Job
107 that is currently selected and is in charge of updating the main window
108 (e.g. with progress info) calls this with j==this, and subsequently
109 uses isWindowOwner(this) to check whether it is still in charge of
110 updating the window. This way, it is ensured that only one JobLine at a
111 time updates the window. Supply 0 to unset. */
112 inline void setWindowOwner(JobLine* j);
113 /** Check whether the supplied JobLine is in charge of updating the
115 inline bool isWindowOwner(JobLine* j) const;
116 /** Get the current JobLine in charge of the main window. This will be
117 called if a button is clicked in the main window, to find the JobLine
118 the click should be "forwarded" to. */
119 inline JobLine* windowOwner() const;
121 /** (De)register a JobLine whose tick() method should be called regularly.
122 As soon as there is at least one such JobLine, a GTK timeout function
123 is registered which does a freeze(), then scans through the whole list
124 calling objects' tick handler where present, then thaw()s the list. As
125 soon as the count of tick-needing JobLines reaches 0, the timeout
126 function is unregistered again. */
127 inline void registerTicks();
128 inline void unregisterTicks();
130 /** To be called sometime after gtk_init, but before any
131 JobLines/JobVectors are used. */
134 /** Perform internal integrity check, failed assertion if it fails. */
135 void assertValid() const;
137 void assertValid() const { }
141 // GTK+ timeout function: calls tick() on stored JobLine objects
142 static gint timeoutCallback(gpointer jobList);
143 // GTK+ callback function, called when a line in the list is selected
144 static gboolean selectRowCallback(GtkTreeSelection*, GtkTreeModel*,
145 GtkTreePath*, gboolean, gpointer);
146 /* Function registered with GTK+, sets up pixbuf with progress bar in the
148 static void pixbufForJobLine(GtkTreeViewColumn*, GtkCellRenderer* cell,
149 GtkTreeModel*, GtkTreeIter* iter,
151 // Load file with progress bar images, prepare it for display
152 static void pixbufForJobLine_init();
153 // Helper for prepend()
154 static gboolean progressScrollToTop(gpointer view);
155 // Set selectRowIdleId to 0
156 static gboolean selectRowIdle(gpointer data);
158 /* Used by initAfterGtk(): Nr of pixbufs to subdivide the progress XPM
159 into, filename to load from. */
160 static const unsigned PROGRESS_SUBDIV = 61;
161 static const char* const PROGRESS_IMAGE_FILE;
162 static GdkPixbuf* progressImage; // Pixel data
163 static vector<GdkPixbuf*> progressGfx; // sub-GdkPixbufs of progressImage
164 static GValue progressValue;
166 GtkTreeStore* storeVal; // GTK store of the displayed list
168 unsigned sizeVal; // Number of rows in table
169 unsigned entryCountVal; // Number of entries (= sizeVal - nr_of_empty_rows)
170 JobLine* windowOwnerValue;
172 /* Count the number of entries in the list which are in a state in which
173 they need tick() calls. */
175 int timeoutId; // as returned by gtk_timeout_add()
177 // Callback avoids mult. calls to entries' selectRow()
178 unsigned selectRowIdleId;
180 //______________________________________________________________________
182 /** Global list of running jobs */
184 extern JobList jobList;
187 //======================================================================
189 JobList::JobList() : storeVal(0), sizeVal(0), entryCountVal(0),
190 windowOwnerValue(0), needTicks(0),
192 // Mustn't access widgets here because GTK+ is not initialized yet!
195 JobList::size_type JobList::size() const { return sizeVal; }
196 bool JobList::empty() const { return sizeVal == 0; }
197 JobList::size_type JobList::entryCount() const { return entryCountVal; }
198 GtkTreeStore* JobList::store() const { return storeVal; }
199 GtkTreeView* JobList::view() const {
200 return GTK_TREE_VIEW(GUI::window.jobs);
203 JobLine* JobList::get(GtkTreeIter* row) const {
205 gtk_tree_model_get(GTK_TREE_MODEL(store()), row, COLUMN_DATA, &ptr, -1);
206 return static_cast<JobLine*>(ptr);
209 Job* JobList::get(size_type n) {
210 return static_cast<JobLine*>(gtk_clist_get_row_data(list(), n));
212 void JobList::set(size_type n, JobLine* j) {
213 gtk_clist_unselect_row(list(), n, 0);
214 gtk_clist_set_row_data(list(), n, j);
220 void JobList::insert(size_type n, JobLine* j) {
222 gtk_clist_insert(list(), n, noText); // 0 => no text initially
223 gtk_clist_set_row_data(list(), n, j);
232 void JobList::registerTicks() {
233 if (++needTicks == 1) {
234 timeoutId = g_timeout_add(TICK_INTERVAL, timeoutCallback, this);
236 debug("registerTicks: %1", needTicks);
238 /* No further action is required. The timeout function will unregister itself
239 next time it is called, by returning FALSE. */
240 void JobList::unregisterTicks() {
241 if (--needTicks == 0)
242 g_source_remove(timeoutId);
243 debug("unregisterTicks: %1", needTicks);
246 void JobList::setWindowOwner(JobLine* j) { windowOwnerValue = j; }
247 bool JobList::isWindowOwner(JobLine* j) const { return windowOwnerValue==j; }
248 JobLine* JobList::windowOwner() const { return windowOwnerValue; }