~ubuntu-branches/ubuntu/wily/me-tv/wily-proposed

« back to all changes in this revision

Viewing changes to src/scan_window.cc

  • Committer: Bazaar Package Importer
  • Author(s): Scott Evans
  • Date: 2009-06-27 00:46:22 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20090627004622-q0zvsie6ioa60vh3
Tags: 0.9.4-0ubuntu1
* New upstream release (LP: #379706)
  - Fix to stop EPG update crashing the application
    after faulty save (LP: #72872)
  - Fixed spin buttons from GtkBuilder conversion (LP: #382197) 
  - Fixed icon on application popup menu (LP: #379685)
  - Fixed compiling of me-tv-0.8.12 fails on Fedora 11 (LP: #377020)
  - Fixed Failed to lock to channel at boot (LP: #377050)
  - Increased timeout to 5 seconds again (LP: #371165)
  - Fixed me-tv unusually slow, often freezes (LP: #351510)
  - Fixed channel persistence (LP: #361514)
  - Fix for forward slashes in description (LP: #359710)
  - Fixed Must create .me-tv directory manually (LP: #353796)
  - Fixed audio stream can't be changed (LP: #350402)
* debian/control:
  - Removed dependency libxine1-ffmpeg, libxine1-x
  - Removed libglademm-2.4-dev Build-Depends.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (C) 2009 Michael Lamothe
3
 
 *
4
 
 * This file is part of Me TV
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 * 
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 
 * GNU Library General Public License for more details.
15
 
 * 
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 51 Franklin Street, Fifth Floor Boston, MA 02110-1301,  USA
19
 
 */
20
 
 
21
 
#include "scan_window.h"
22
 
#include "dvb_scanner.h"
23
 
#include "thread.h"
24
 
#include "application.h"
25
 
#include "channels_conf_line.h"
26
 
#include "profile.h"
27
 
 
28
 
ScanWindow* ScanWindow::create(Glib::RefPtr<Gnome::Glade::Xml> glade)
29
 
{
30
 
        ScanWindow* scan_window = NULL;
31
 
        glade->get_widget_derived("window_scan_wizard", scan_window);
32
 
        return scan_window;
33
 
}
34
 
 
35
 
Glib::ustring ScanWindow::get_initial_tuning_dir()
36
 
{
37
 
        Glib::ustring result;
38
 
        gboolean done = false;
39
 
        guint i = 0;
40
 
        
41
 
        StringSplitter splitter(SCAN_DIRECTORIES, ":", 100);
42
 
 
43
 
        while (!done)
44
 
        {
45
 
                if (i >= splitter.get_count())
46
 
                {
47
 
                        done = true;
48
 
                }
49
 
                else
50
 
                {
51
 
                        Glib::ustring scan_directory = splitter.get_value(i);
52
 
                        
53
 
                        g_debug("Checking '%s'", scan_directory.c_str());
54
 
                
55
 
                        if (Gio::File::create_for_path(scan_directory)->query_exists())
56
 
                        {
57
 
                                done = true;
58
 
                                result = scan_directory;
59
 
 
60
 
                                switch(frontend.get_frontend_info().type)
61
 
                                {
62
 
                                case FE_OFDM:   result += "/dvb-t";       break;
63
 
                                case FE_QAM:    result += "/dvb-c";       break;
64
 
                                case FE_QPSK:   result += "/dvb-s";       break;
65
 
                                case FE_ATSC:   result += "/atsc";        break;
66
 
                                default:                throw Exception(_("Unknown frontend type"));
67
 
                                }
68
 
 
69
 
                                g_debug("Found '%s'", result.c_str());
70
 
                        }
71
 
 
72
 
                        i++;
73
 
                }
74
 
        }
75
 
        
76
 
        return result;
77
 
}
78
 
 
79
 
bool compare_countries (const Country& a, const Country& b)
80
 
{
81
 
        return a.name < b.name;
82
 
}
83
 
 
84
 
ScanWindow::ScanWindow(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& glade_xml) :
85
 
        Gtk::Window(cobject), glade(glade_xml), frontend(get_application().get_device_manager().get_frontend())
86
 
{
87
 
        scan_thread = NULL;
88
 
 
89
 
        notebook_scan_wizard = dynamic_cast<Gtk::Notebook*>(glade->get_widget("notebook_scan_wizard"));
90
 
        label_scan_information = dynamic_cast<Gtk::Label*>(glade->get_widget("label_scan_information"));
91
 
        glade->connect_clicked("button_scan_wizard_add", sigc::mem_fun(*this, &ScanWindow::on_button_scan_wizard_add_clicked));
92
 
        glade->connect_clicked("button_scan_wizard_next", sigc::mem_fun(*this, &ScanWindow::on_button_scan_wizard_next_clicked));
93
 
        glade->connect_clicked("button_scan_wizard_cancel", sigc::mem_fun(*this, &ScanWindow::on_button_scan_wizard_cancel_clicked));
94
 
 
95
 
        notebook_scan_wizard->set_show_tabs(false);
96
 
                
97
 
        Glib::ustring device_name = frontend.get_frontend_info().name;
98
 
        dynamic_cast<Gtk::Label*>(glade->get_widget("label_scan_device"))->set_label(device_name);
99
 
                
100
 
        progress_bar_scan = dynamic_cast<Gtk::ProgressBar*>(glade->get_widget("progress_bar_scan"));
101
 
        tree_view_scanned_channels = dynamic_cast<Gtk::TreeView*>(glade->get_widget("tree_view_scanned_channels"));
102
 
        
103
 
        list_store = Gtk::ListStore::create(columns);
104
 
        tree_view_scanned_channels->set_model(list_store);
105
 
        tree_view_scanned_channels->append_column(_("Service Name"), columns.column_name);
106
 
        
107
 
        Glib::RefPtr<Gtk::TreeSelection> selection = tree_view_scanned_channels->get_selection();
108
 
        selection->set_mode(Gtk::SELECTION_MULTIPLE);
109
 
        
110
 
        combo_box_select_country = NULL;
111
 
        glade->get_widget_derived("combo_box_select_country", combo_box_select_country);
112
 
 
113
 
        combo_box_select_region = NULL;
114
 
        glade->get_widget_derived("combo_box_select_region", combo_box_select_region);
115
 
        
116
 
        scan_directory_path = get_initial_tuning_dir();
117
 
 
118
 
        if (scan_directory_path.size() > 0)
119
 
        {
120
 
                Glib::RefPtr<Gio::File> scan_directory = Gio::File::create_for_path(scan_directory_path);
121
 
                g_debug("Scanning directory: %s", scan_directory_path.c_str());
122
 
                        
123
 
                // This is a hack because I can't get scan_directory->enumerate_children() to work
124
 
                GFileEnumerator* children = g_file_enumerate_children(scan_directory->gobj(),
125
 
                        "*", G_FILE_QUERY_INFO_NONE, NULL, NULL);
126
 
                if (children != NULL)
127
 
                {
128
 
                        GFileInfo* file_info = g_file_enumerator_next_file(children, NULL, NULL);
129
 
                        while (file_info != NULL)
130
 
                        {
131
 
                                Glib::ustring name = g_file_info_get_name(file_info);
132
 
                                if (name.substr(2,1) == "-")
133
 
                                {
134
 
                                        Glib::ustring country_name = name.substr(0,2);
135
 
                                        Glib::ustring region_name = name.substr(3);
136
 
                                        Country& country = get_country(country_name);
137
 
                                        country.regions.push_back(region_name);
138
 
                                }
139
 
                                file_info = g_file_enumerator_next_file(children, NULL, NULL);
140
 
                        }
141
 
 
142
 
                        // Populate controls
143
 
                        countries.sort(compare_countries);
144
 
                        CountryList::iterator country_iterator = countries.begin();
145
 
                        while (country_iterator != countries.end())
146
 
                        {
147
 
                                Country& country = *country_iterator;
148
 
                                country.regions.sort();
149
 
                                combo_box_select_country->append_text(country.name);
150
 
                                country_iterator++;
151
 
                        }
152
 
                        combo_box_select_country->signal_changed().connect(sigc::mem_fun(*this, &ScanWindow::on_combo_box_select_country_changed));
153
 
                        combo_box_select_country->set_active(0);
154
 
                }
155
 
        }
156
 
}
157
 
 
158
 
ScanWindow::~ScanWindow()
159
 
{
160
 
        stop_scan();
161
 
}
162
 
 
163
 
void ScanWindow::on_show()
164
 
{
165
 
        channel_count = 0;
166
 
        update_channel_count();
167
 
        progress_bar_scan->set_fraction(0);
168
 
        glade->get_widget("button_scan_wizard_add")->hide();
169
 
        glade->get_widget("button_scan_wizard_next")->show();
170
 
        notebook_scan_wizard->set_current_page(0);
171
 
        Window::on_show();
172
 
}
173
 
 
174
 
void ScanWindow::on_hide()
175
 
{
176
 
        stop_scan();
177
 
        Window::on_hide();
178
 
}
179
 
 
180
 
void ScanWindow::on_combo_box_select_country_changed()
181
 
{
182
 
        combo_box_select_region->clear_items();
183
 
        Country& country = get_country(combo_box_select_country->get_active_text());
184
 
        StringList::iterator region_iterator = country.regions.begin();
185
 
        while (region_iterator != country.regions.end())
186
 
        {
187
 
                combo_box_select_region->append_text(*region_iterator);
188
 
                region_iterator++;
189
 
        }
190
 
        combo_box_select_region->set_active(0);
191
 
}
192
 
 
193
 
void ScanWindow::stop_scan()
194
 
{
195
 
        if (scan_thread != NULL)
196
 
        {
197
 
                g_debug("Stopping scan");
198
 
                scan_thread->stop();
199
 
                scan_thread->join(true);
200
 
                delete scan_thread;
201
 
                scan_thread = NULL;
202
 
        }
203
 
}
204
 
 
205
 
void ScanWindow::on_button_scan_wizard_cancel_clicked()
206
 
{
207
 
        hide();
208
 
}
209
 
 
210
 
void ScanWindow::import_channels_conf(const Glib::ustring& channels_conf_path)
211
 
{
212
 
        Profile& current_profile = get_application().get_profile_manager().get_current_profile();
213
 
        Glib::RefPtr<Glib::IOChannel> file = Glib::IOChannel::create_from_file(channels_conf_path, "r");
214
 
        Glib::ustring line;
215
 
        guint line_count = 0;
216
 
        
217
 
        while (file->read_line(line) == Glib::IO_STATUS_NORMAL)
218
 
        {
219
 
                ChannelsConfLine channels_conf_line(line);
220
 
                guint parameter_count = channels_conf_line.get_parameter_count();
221
 
 
222
 
                line_count++;
223
 
                
224
 
                g_debug("Line %d (%d parameters): '%s'", line_count, parameter_count, line.c_str());
225
 
        
226
 
                if (parameter_count > 1)
227
 
                {
228
 
                        switch(frontend.get_frontend_info().type)
229
 
                        {
230
 
                                case FE_OFDM:
231
 
                                        if (parameter_count != 13)
232
 
                                        {
233
 
                                                Glib::ustring message = Glib::ustring::compose(_("Invalid parameter count on line %1"), line_count);
234
 
                                                throw Exception(message);
235
 
                                        }
236
 
 
237
 
                                        {
238
 
                                                Channel channel;
239
 
 
240
 
                                                channel.name = channels_conf_line.get_name(0);
241
 
                                                channel.sort_order = line_count;
242
 
                                                channel.flags = CHANNEL_FLAG_DVB_T;
243
 
                                
244
 
                                                channel.frontend_parameters.frequency                                           = channels_conf_line.get_frequency(1);
245
 
                                                channel.frontend_parameters.inversion                                           = channels_conf_line.get_inversion(2);
246
 
                                                channel.frontend_parameters.u.ofdm.bandwidth                            = channels_conf_line.get_bandwidth(3);
247
 
                                                channel.frontend_parameters.u.ofdm.code_rate_HP                         = channels_conf_line.get_fec(4);
248
 
                                                channel.frontend_parameters.u.ofdm.code_rate_LP                         = channels_conf_line.get_fec(5);
249
 
                                                channel.frontend_parameters.u.ofdm.constellation                        = channels_conf_line.get_modulation(6);
250
 
                                                channel.frontend_parameters.u.ofdm.transmission_mode            = channels_conf_line.get_transmit_mode(7);
251
 
                                                channel.frontend_parameters.u.ofdm.guard_interval                       = channels_conf_line.get_guard_interval(8);
252
 
                                                channel.frontend_parameters.u.ofdm.hierarchy_information        = channels_conf_line.get_hierarchy(9);
253
 
                                                channel.service_id                                                                                      = channels_conf_line.get_service_id(12);
254
 
                                
255
 
                                                current_profile.add_channel(channel);
256
 
                                        }
257
 
                                        break;
258
 
                                
259
 
                                case FE_QAM:
260
 
                                        if (parameter_count != 9)
261
 
                                        {
262
 
                                                Glib::ustring message = Glib::ustring::compose(_("Invalid parameter count on line %1"), line_count);
263
 
                                                throw Exception(message);
264
 
                                        }
265
 
 
266
 
                                        {
267
 
                                                Channel channel;
268
 
 
269
 
                                                channel.name = channels_conf_line.get_name(0);
270
 
                                                channel.sort_order = line_count;
271
 
                                                channel.flags = CHANNEL_FLAG_DVB_C;
272
 
                                
273
 
                                                channel.frontend_parameters.frequency                   = channels_conf_line.get_frequency(1);
274
 
                                                channel.frontend_parameters.inversion                   = channels_conf_line.get_inversion(2);
275
 
                                                channel.frontend_parameters.u.qam.symbol_rate   = channels_conf_line.get_symbol_rate(3);
276
 
                                                channel.frontend_parameters.u.qam.fec_inner             = channels_conf_line.get_fec(4);
277
 
                                                channel.frontend_parameters.u.qam.modulation    = channels_conf_line.get_modulation(5);
278
 
                                                channel.service_id                                                              = channels_conf_line.get_service_id(8);
279
 
                                
280
 
                                                current_profile.add_channel(channel);
281
 
                                        }
282
 
                                        break;
283
 
 
284
 
                                case FE_ATSC:
285
 
                                        if (parameter_count != 6)
286
 
                                        {
287
 
                                                Glib::ustring message = Glib::ustring::compose(_("Invalid parameter count on line %1"), line_count);
288
 
                                                throw Exception(message);
289
 
                                        }
290
 
 
291
 
                                        {
292
 
                                                Channel channel;
293
 
 
294
 
                                                channel.name = channels_conf_line.get_name(0);
295
 
                                                channel.sort_order = line_count;
296
 
                                                channel.flags = CHANNEL_FLAG_ATSC;
297
 
                                
298
 
                                                channel.frontend_parameters.frequency                                           = channels_conf_line.get_frequency(1);
299
 
                                                channel.frontend_parameters.inversion                                           = INVERSION_AUTO;
300
 
                                                channel.frontend_parameters.u.vsb.modulation                            = channels_conf_line.get_modulation(2);
301
 
                                                channel.service_id                                                                                      = channels_conf_line.get_service_id(5);
302
 
                                
303
 
                                                current_profile.add_channel(channel);
304
 
                                        }
305
 
                                        break;
306
 
                                
307
 
                                default:
308
 
                                        throw Exception(_("Failed to import: importing a channels.conf is only supported with DVB-T, DVB-C and ATSC"));
309
 
                                        break;
310
 
                        }
311
 
                }               
312
 
        }
313
 
        g_debug("Finished importing channels");
314
 
        
315
 
        Data data;
316
 
        data.replace_profile(current_profile);
317
 
        hide();
318
 
}
319
 
 
320
 
void ScanWindow::on_button_scan_wizard_next_clicked()
321
 
{
322
 
        TRY
323
 
        gboolean do_scan = true;
324
 
        
325
 
        stop_scan();
326
 
 
327
 
        list_store->clear();
328
 
 
329
 
        Glib::ustring initial_tuning_file;
330
 
        
331
 
        Gtk::RadioButton* radio_button_scan_by_location = dynamic_cast<Gtk::RadioButton*>(glade->get_widget("radio_button_scan_by_location"));
332
 
        Gtk::RadioButton* radio_button_scan_by_file = dynamic_cast<Gtk::RadioButton*>(glade->get_widget("radio_button_scan_by_file"));
333
 
        Gtk::RadioButton* radio_button_scan_import_channels_conf = dynamic_cast<Gtk::RadioButton*>(glade->get_widget("radio_button_scan_import_channels_conf"));
334
 
                
335
 
        if (radio_button_scan_by_location->get_active())
336
 
        {
337
 
                Glib::ustring country_name = combo_box_select_country->get_active_text();
338
 
                Glib::ustring region_name = combo_box_select_region->get_active_text();
339
 
                initial_tuning_file = scan_directory_path + "/" + country_name + "-" + region_name;
340
 
        }
341
 
        else if (radio_button_scan_by_file->get_active())
342
 
        {
343
 
                Gtk::FileChooserButton* file_chooser = dynamic_cast<Gtk::FileChooserButton*>(glade->get_widget("file_chooser_button_select_file_to_scan"));
344
 
                initial_tuning_file = file_chooser->get_filename();
345
 
        }
346
 
        else if (radio_button_scan_import_channels_conf->get_active())
347
 
        {
348
 
                Gtk::FileChooserButton* file_chooser = dynamic_cast<Gtk::FileChooserButton*>(glade->get_widget("file_chooser_button_channels_conf"));
349
 
                Glib::ustring channels_conf_path = file_chooser->get_filename();
350
 
                import_channels_conf(channels_conf_path);
351
 
                do_scan = false;
352
 
        }
353
 
        else
354
 
        {
355
 
                throw Exception(_("No scan/import option specified"));
356
 
        }
357
 
        
358
 
        if (do_scan)
359
 
        {
360
 
                switch(frontend.get_frontend_info().type)
361
 
                {
362
 
                        case FE_OFDM:
363
 
                        case FE_QAM:
364
 
                                break;
365
 
                        default:
366
 
                                throw Exception(_("Failed to scan: scanning is only supported for DVB-T and DVB-C devices"));
367
 
                }
368
 
 
369
 
                if (initial_tuning_file.empty())
370
 
                {
371
 
                        Gtk::MessageDialog dialog(*this, _("No tuning file has been selected"));
372
 
                        dialog.run();
373
 
                }
374
 
                else
375
 
                {
376
 
                        glade->get_widget("button_scan_wizard_next")->hide();
377
 
                        notebook_scan_wizard->next_page();
378
 
 
379
 
                        g_debug("Initial tuning file: '%s'", initial_tuning_file.c_str());
380
 
                        scan_thread = new ScanThread(frontend, initial_tuning_file);
381
 
                        Dvb::Scanner& scanner = scan_thread->get_scanner();
382
 
                        scanner.signal_service.connect(sigc::mem_fun(*this, &ScanWindow::on_signal_service));
383
 
                        scanner.signal_progress.connect(sigc::mem_fun(*this, &ScanWindow::on_signal_progress));
384
 
                        get_application().stop_stream_thread();
385
 
                        scan_thread->start();
386
 
                }
387
 
        }
388
 
        CATCH
389
 
}
390
 
 
391
 
void ScanWindow::on_button_scan_wizard_add_clicked()
392
 
{
393
 
        Profile& current_profile = get_application().get_profile_manager().get_current_profile();
394
 
 
395
 
        std::list<Gtk::TreeModel::Path> selected_services = tree_view_scanned_channels->get_selection()->get_selected_rows();           
396
 
        std::list<Gtk::TreeModel::Path>::iterator iterator = selected_services.begin();
397
 
        while (iterator != selected_services.end())
398
 
        {
399
 
                Gtk::TreeModel::Row row(*list_store->get_iter(*iterator));
400
 
 
401
 
                Channel channel;
402
 
 
403
 
                channel.service_id                      = row.get_value(columns.column_id);
404
 
                channel.name                            = row.get_value(columns.column_name);
405
 
                channel.frontend_parameters = row.get_value(columns.column_frontend_parameters);
406
 
 
407
 
                switch(frontend.get_frontend_info().type)
408
 
                {
409
 
                        case FE_OFDM:
410
 
                                channel.flags = CHANNEL_FLAG_DVB_T;
411
 
                                break;
412
 
                                
413
 
                        case FE_QAM:
414
 
                                channel.flags = CHANNEL_FLAG_DVB_C;
415
 
                                break;
416
 
                                
417
 
                        case FE_ATSC:
418
 
                                channel.flags = CHANNEL_FLAG_ATSC;
419
 
                                break;
420
 
 
421
 
                        default:
422
 
                                throw Exception(_("Invalid frontend type"));
423
 
                                break;
424
 
                }
425
 
                
426
 
                current_profile.add_channel(channel);
427
 
                
428
 
                iterator++;
429
 
        }
430
 
 
431
 
        Data data;
432
 
        data.replace_profile(current_profile);
433
 
        hide();
434
 
}
435
 
 
436
 
void ScanWindow::on_signal_service(struct dvb_frontend_parameters& frontend_parameters, guint id, const Glib::ustring& name)
437
 
{
438
 
        GdkLock gdk_lock;
439
 
        Gtk::TreeModel::iterator iterator = list_store->append();
440
 
        Gtk::TreeModel::Row row = *iterator;
441
 
        row[columns.column_id] = id;
442
 
        row[columns.column_name] = name;
443
 
        row[columns.column_frontend_parameters] = frontend_parameters;
444
 
        tree_view_scanned_channels->get_selection()->select(row);
445
 
 
446
 
        channel_count++;
447
 
        update_channel_count();
448
 
}
449
 
 
450
 
void ScanWindow::update_channel_count()
451
 
{
452
 
        label_scan_information->set_text(Glib::ustring::compose(ngettext("Found 1 channel", "Found %1 channels", channel_count), channel_count));
453
 
}
454
 
 
455
 
void ScanWindow::on_signal_progress(guint step, gsize total)
456
 
{
457
 
        GdkLock gdk_lock;
458
 
        gdouble fraction = total == 0 ? 0 : step/(gdouble)total;
459
 
        progress_bar_scan->set_fraction(fraction);
460
 
        if (step == total)
461
 
        {
462
 
                glade->get_widget("button_scan_wizard_add")->show();
463
 
                notebook_scan_wizard->next_page();
464
 
        }
465
 
}
466
 
 
467
 
Country& ScanWindow::get_country(const Glib::ustring& country_name)
468
 
{
469
 
        Country* result = find_country(country_name);
470
 
 
471
 
        // If we don't have the country already then create one
472
 
        if (result == NULL)
473
 
        {
474
 
                Country country;
475
 
                country.name = country_name;
476
 
                countries.push_back(country);
477
 
                result = find_country(country_name);
478
 
        }
479
 
        
480
 
        return *result;
481
 
}
482
 
 
483
 
Country* ScanWindow::find_country(const Glib::ustring& country_name)
484
 
{
485
 
        Country* result = NULL;
486
 
        
487
 
        CountryList::iterator country_iterator = countries.begin();
488
 
        while (country_iterator != countries.end() && result == NULL)
489
 
        {
490
 
                Country& country = *country_iterator;
491
 
                if (country.name == country_name)
492
 
                {
493
 
                        result = &(*country_iterator);
494
 
                }
495
 
                country_iterator++;
496
 
        }
497
 
        
498
 
        return result;
499
 
}