1 /* This file is part of Cinaest.
3 * Copyright (C) 2009 Philipp Zabel
5 * Cinaest is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * Cinaest is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Cinaest. If not, see <http://www.gnu.org/licenses/>.
21 public class MovieListStore : ListStore, TreeModel {
32 private GLib.Type[] types = {
41 private GLib.Type[] base_type = {
43 typeof (string), // Markup: "Title (Year)"
44 typeof (string) // Rating
46 private Gdk.Pixbuf no_poster;
47 private MoviePoster.Factory poster_factory;
48 private MovieFilter filter;
49 public bool update_running { get; set; }
50 public string year_markup = "<span size=\"small\">[%d]</span>";
51 private Cancellable cancellable;
54 public signal void search_finished (int movies);
56 private MovieSource _source;
57 public MovieSource source {
67 set_column_types (base_type);
70 update_running = false;
72 poster_factory = MoviePoster.Factory.get_instance ();
75 public void add (Movie movie, out TreeIter iter) {
77 var markup = new StringBuilder ();
78 markup.append (Markup.escape_text (movie.title));
81 markup.append_printf (year_markup, movie.year);
84 base.insert_with_values (out iter1, -1,
87 2, rating_string (movie.rating));
89 movie.notify.connect (this.on_movie_changed);
94 private string? rating_string (int rating) {
96 return "%d.%d".printf (rating / 10,
103 public new bool remove (Movie movie) {
106 if (get_iter_from_movie (out iter, movie)) {
107 movie.notify.disconnect (this.on_movie_changed);
110 if (SourceFlags.EDITABLE in source.get_flags ()) {
111 source.delete_movie (movie);
120 private void on_movie_changed (GLib.Object source, GLib.ParamSpec spec) {
121 var movie = (Movie) source;
124 if (get_iter_from_movie (out iter, movie)) {
125 TreePath path = get_path (iter);
126 base.row_changed (path, iter);
130 public bool get_editable () {
131 return (SourceFlags.EDITABLE in source.get_flags ());
134 public bool get_iter_from_movie (out TreeIter iter, Movie movie_a) {
135 if (get_iter_first (out iter)) {
138 get (iter, Columns.MOVIE, out movie_b);
139 if (movie_a == movie_b)
141 } while (iter_next (ref iter));
146 public bool start_search (MovieFilter _filter) {
147 if (update_running) {
148 stdout.printf ("aborting search ...\n");
149 cancellable.cancel ();
150 poster_factory.clear_queue ();
153 if (cancellable == null || cancellable.is_cancelled ())
154 cancellable = new Cancellable ();
157 stdout.printf ("begin search\n");
158 search_async.begin ();
159 update_running = true;
163 // Asynchronous update method
164 private async void search_async () {
165 stdout.printf ("search started: \"%s\"\n", filter.title);
169 if (source != null) {
170 // FIXME - arbitrary limit
171 int n = yield source.get_movies (filter, receive_movie, 100, cancellable);
175 update_running = false;
176 if (cancellable.is_cancelled ()) {
177 stdout.printf ("search aborted, starting new\n");
178 cancellable.reset ();
179 if (cancellable.is_cancelled ()) {
180 stdout.printf ("OW WEY\n");
182 start_search (filter);
184 stdout.printf ("search stopped\n");
188 private void receive_movie (SList<Movie> movies) {
191 if (cancellable.is_cancelled ())
194 view.freeze_child_notify ();
195 foreach (Movie movie in movies)
196 add (movie, out iter);
197 view.thaw_child_notify ();
200 private void receive_poster_icon (Gdk.Pixbuf pixbuf, Movie movie) {
201 var poster = new Poster ();
202 poster.icon = pixbuf;
203 movie.poster = poster;
206 private void receive_poster_small (Gdk.Pixbuf pixbuf, Movie movie) {
207 var poster = new Poster ();
208 if (movie.poster != null && movie.poster.icon != null)
209 poster.icon = movie.poster.icon;
210 poster.small = pixbuf;
211 movie.poster = poster;
214 // Implement TreeModel interface
215 public virtual GLib.Type get_column_type (int index_) {
216 return_val_if_fail (index_ >= 0 && index_ < Columns.N_COLUMNS, 0);
218 return types[index_];
221 public virtual int get_n_columns () {
222 return Columns.N_COLUMNS;
225 public virtual void get_value (TreeIter iter, int column, out GLib.Value value) {
228 return_if_fail (column >= 0 && column < Columns.N_COLUMNS);
230 // Get the Movie from our parent's storage
232 base.get_value (iter, 0, out val);
233 movie = (Movie) val.get_object ();
235 value.init (get_column_type (column));
240 value.set_string (movie.title);
242 value.set_string ("");
248 value.set_int (movie.year);
255 base.get_value (iter, 2, out value);
259 if ((movie.poster != null) && (movie.poster.small != null)) {
260 value.set_object (movie.poster.small);
263 if (no_poster == null) try {
264 // var no_pic = new Gdk.Pixbuf.from_file ("/usr/share/icons/hicolor/64x64/hildon/imageviewer_no_pic.png");
265 var no_pic = new Gdk.Pixbuf.from_file ("/usr/share/icons/hicolor/64x64/hildon/general_no_thumbnail.png");
266 no_poster = new Gdk.Pixbuf (Gdk.Colorspace.RGB, true, 8, Poster.SMALL_WIDTH, Poster.SMALL_HEIGHT);
268 no_pic.copy_area (0, 0, no_pic.width, no_pic.height, no_poster,
269 (Poster.SMALL_WIDTH - no_pic.width) / 2, (Poster.SMALL_HEIGHT - no_pic.height) / 2);
271 critical ("Missing general_video icon: %s\n", e.message);
273 value.set_object (no_poster);
278 if ((movie.poster != null) && (movie.poster.icon != null)) {
279 value.set_object (movie.poster.icon);
281 value.set_object (null);
286 value.set_object (movie);
290 base.get_value (iter, 1, out value);
294 assert_not_reached ();