~echidnaman/software-properties/pykde4

465.3.5 by jr
implement translations
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
465.2.19 by jr
Merge with Sebastian Heinlein
3
#  Qt 4 based frontend to software-properties
4
#
5
#  Copyright (c) 2007 Canonical Ltd.
6
#
7
#  Author: Jonathan Riddell <jriddell@ubuntu.com>
8
#
9
#  This program is free software; you can redistribute it and/or
10
#  modify it under the terms of the GNU General Public License as
11
#  published by the Free Software Foundation; either version 2 of the
12
#  License, or (at your option) any later version.
13
#
14
#  This program is distributed in the hope that it will be useful,
15
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
16
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
#  GNU General Public License for more details.
18
#
19
#  You should have received a copy of the GNU General Public License
20
#  along with this program; if not, write to the Free Software
21
#  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22
#  USA
23
465.2.1 by jr
Start KDE (actually qt 4) port
24
import apt
25
import apt_pkg
26
import tempfile
27
from gettext import gettext as _
28
import os
29
import re
30
from xml.sax.saxutils import escape
31
465.3.6 by jr
Add a crash handler
32
import sys
33
import traceback
529 by Jonathan Riddell
Make KDE frontend call adept_batch update when sources need to be updated, also implement --no-update for gtk frontend
34
import subprocess
465.3.6 by jr
Add a crash handler
35
465.2.1 by jr
Start KDE (actually qt 4) port
36
from PyQt4.QtCore import *
37
from PyQt4.QtGui import *
38
from PyQt4 import uic
39
40
import softwareproperties
41
import softwareproperties.distro
42
from softwareproperties.SoftwareProperties import SoftwareProperties
43
import softwareproperties.SoftwareProperties
465.2.19 by jr
Merge with Sebastian Heinlein
44
from aptsources.sourceslist import SourceEntry
465.2.10 by jr
Edit 3rd party sources implemented
45
from DialogEdit import DialogEdit
465.3.1 by jr
Add mirror dialogue
46
from DialogMirror import DialogMirror
465.2.11 by jr
most of add CD-ROM implemented
47
from CdromProgress import CdromProgress
465.2.1 by jr
Start KDE (actually qt 4) port
48
465.3.5 by jr
implement translations
49
class SoftwarePropertiesKDEUI(QWidget):
465.2.1 by jr
Start KDE (actually qt 4) port
50
465.3.8 by jr
use datadir
51
    def __init__(self, datadir):
465.2.1 by jr
Start KDE (actually qt 4) port
52
        QWidget.__init__(self)
480 by Sebastian Heinlein
* merge with Riddell
53
        uic.loadUi("%s/designer/main.ui" % datadir, self)
465.2.1 by jr
Start KDE (actually qt 4) port
54
55
class SoftwarePropertiesKDE(SoftwareProperties):
56
  def __init__(self, datadir=None, options=None, parent=None, file=None):
57
    """ Provide a KDE (actually Qt 4) based graphical user interface to configure
58
        the used software repositories, corresponding authentication keys
59
        and update automation """
60
    SoftwareProperties.__init__(self, options=options, datadir=datadir)
61
465.2.5 by jr
show_distro()
62
    self.options = options
465.3.8 by jr
use datadir
63
    self.datadir = datadir
465.2.5 by jr
show_distro()
64
465.2.1 by jr
Start KDE (actually qt 4) port
65
    self.app = QApplication([])
66
465.3.8 by jr
use datadir
67
    self.userinterface = SoftwarePropertiesKDEUI(datadir)
465.2.16 by jr
tidying up
68
    self.userinterface.setWindowIcon(QIcon("/usr/share/icons/hicolor/128x128/apps/adept_manager.png"))
465.3.5 by jr
implement translations
69
    self.translate_widgets()
465.2.1 by jr
Start KDE (actually qt 4) port
70
    self.userinterface.show()
71
465.2.7 by jr
Implement popcon (as far as it goes)
72
    # rejected() signal from Close button
73
    self.app.connect(self.userinterface.buttonBox, SIGNAL("rejected()"), self.on_close_button)
465.2.6 by jr
implement authentication page functionality
74
482.1.22 by Sebastian Heinlein
* rename the restore defaults button in the main interface
75
    self.userinterface.buttonBox.button(QDialogButtonBox.Reset).setEnabled(False)
465.2.17 by jr
Fix some HTML
76
465.2.2 by jr
Add some functionality
77
    # Put some life into the user interface:
78
    self.init_server_chooser()
79
    self.init_popcon()
80
    self.init_auto_update()
465.2.3 by jr
show_auto_update_level
81
    self.show_auto_update_level()
465.2.2 by jr
Add some functionality
82
    # Setup the key list
465.2.3 by jr
show_auto_update_level
83
    self.init_keys()
84
    self.show_keys()
465.2.2 by jr
Add some functionality
85
    # Setup the ISV sources list
465.2.4 by jr
init and show_isv_sources
86
    self.init_isv_sources()
87
    self.show_isv_sources()
482.3.3 by Sebastian Heinlein
* support cdroms in the KDE frontend
88
    self.show_cdrom_sources()
465.2.2 by jr
Add some functionality
89
465.2.14 by jr
Implement tickbox functionality
90
    self.app.connect(self.userinterface.checkbutton_source_code, SIGNAL("clicked()"), self.on_checkbutton_source_code_toggled)
465.2.6 by jr
implement authentication page functionality
91
    self.app.connect(self.userinterface.button_auth_restore, SIGNAL("clicked()"), self.on_restore_clicked)
92
    self.app.connect(self.userinterface.button_add_auth, SIGNAL("clicked()"), self.add_key_clicked)
93
    self.app.connect(self.userinterface.button_auth_remove, SIGNAL("clicked()"), self.remove_key_clicked)
465.2.7 by jr
Implement popcon (as far as it goes)
94
    self.app.connect(self.userinterface.checkbutton_popcon, SIGNAL("toggled(bool)"), self.on_checkbutton_popcon_toggled)
465.2.8 by jr
Implement update functionality
95
    self.app.connect(self.userinterface.checkbutton_auto_update, SIGNAL("toggled(bool)"), self.on_auto_update_toggled)
96
    self.app.connect(self.userinterface.combobox_update_interval, SIGNAL("currentIndexChanged(int)"), self.on_combobox_update_interval_changed)
465.2.9 by jr
third party remove implemented
97
    self.app.connect(self.userinterface.button_remove, SIGNAL("clicked()"), self.on_remove_clicked)
465.2.10 by jr
Edit 3rd party sources implemented
98
    self.app.connect(self.userinterface.button_edit, SIGNAL("clicked()"), self.on_edit_clicked)
465.2.11 by jr
most of add CD-ROM implemented
99
    self.app.connect(self.userinterface.button_add_cdrom, SIGNAL("clicked()"), self.on_button_add_cdrom_clicked)
465.2.13 by jr
on_add_clicked for 3rd party
100
    self.app.connect(self.userinterface.button_add, SIGNAL("clicked()"), self.on_add_clicked)
465.2.16 by jr
tidying up
101
    self.app.connect(self.userinterface.treeview_sources, SIGNAL("itemChanged(QTreeWidgetItem*, int)"), self.on_isv_source_toggled)
482.3.3 by Sebastian Heinlein
* support cdroms in the KDE frontend
102
    self.app.connect(self.userinterface.treeview_cdroms, SIGNAL("itemChanged(QTreeWidgetItem*, int)"), self.on_cdrom_source_toggled)
465.2.16 by jr
tidying up
103
    self.app.connect(self.userinterface.treeview_sources, SIGNAL("itemClicked(QTreeWidgetItem*, int)"), self.on_treeview_sources_cursor_changed)
482.1.22 by Sebastian Heinlein
* rename the restore defaults button in the main interface
104
    button_revert = self.userinterface.buttonBox.button(QDialogButtonBox.Reset)
465.2.18 by jr
revert button
105
    self.app.connect(button_revert, SIGNAL("clicked()"), self.on_button_revert_clicked)
465.2.2 by jr
Add some functionality
106
510 by Jonathan Riddell
implement revert
107
    self.init_distro()
465.2.5 by jr
show_distro()
108
    self.show_distro()
465.2.2 by jr
Add some functionality
109
465.3.5 by jr
implement translations
110
  def translate_widgets(self):
111
      """translate the whole user interface"""
112
      self.translate_widget_children(self.userinterface)
113
114
  def translate_widget_children(self, parentWidget):
115
      """translate given widget and its children"""
116
      for widget in parentWidget.children():
117
          self.translate_widget(widget)
118
          self.translate_widget_children(widget)
119
120
  def translate_widget(self, widget):
121
      """translate the text on a widget"""
122
      if isinstance(widget, QLabel):
123
          text = str(widget.text())
124
          text = _(text)
125
          ##FIXME string is a str but in unicode.  PyQt thinks it isn't unicode and any non-ascii characters break, how to fix??
126
          text = unicode(text, 'utf-8')
127
          widget.setText(text)
128
      elif isinstance(widget, QPushButton):
129
          text = str(widget.text())
130
          text = _(text)
131
          text = unicode(text, 'utf-8')
132
          widget.setText(text)
133
      elif isinstance(widget, QGroupBox):
134
          text = str(widget.title())
135
          text = _(text)
136
          text = unicode(text, 'utf-8')
137
          widget.setTitle(text)
138
      elif isinstance(widget, QCheckBox):
139
          text = str(widget.text())
140
          text = _(text)
141
          text = unicode(text, 'utf-8')
142
          widget.setText(text)
143
465.2.2 by jr
Add some functionality
144
  def init_popcon(self):
145
    """ If popcon is enabled show the statistics tab and an explanation
146
        corresponding to the used distro """
147
    is_helpful = self.get_popcon_participation()
148
    if is_helpful != None:
465.2.17 by jr
Fix some HTML
149
      text = softwareproperties.distro.get_popcon_description(self.distro)
150
      text = text.replace("\n", "<br />") #silly GTK mixes HTML and normal white space
519 by Jonathan Riddell
i18n fixes, closes https://launchpad.net/bugs/102773
151
      self.userinterface.label_popcon_desc.setText(unicode(text, 'UTF-8'))
465.2.2 by jr
Add some functionality
152
      self.userinterface.checkbutton_popcon.setChecked(is_helpful)
153
    else:
154
      self.userinterface.tabWidget.removeTab(4)
155
156
  def init_server_chooser(self):
157
    """ Set up the widgets that allow to choose an alternate download site """
465.3.1 by jr
Add mirror dialogue
158
    # nothing to do here, set up signal in show_distro()
159
    pass
465.2.2 by jr
Add some functionality
160
161
  def init_auto_update(self):
162
    """ Set up the widgets that allow to configure the update automation """
163
    # this maps the key (combo-box-index) to the auto-update-interval value
164
    # where (-1) means, no key
165
    self.combobox_interval_mapping = { 0 : 1,
166
                                       1 : 2,
167
                                       2 : 7,
168
                                       3 : 14 }
169
465.3.5 by jr
implement translations
170
    self.userinterface.combobox_update_interval.insertItem(99, unicode(_("Daily"), 'utf-8'))
171
    self.userinterface.combobox_update_interval.insertItem(99, unicode(_("Every two days"), 'utf-8'))
172
    self.userinterface.combobox_update_interval.insertItem(99, unicode(_("Weekly"), 'utf-8'))
173
    self.userinterface.combobox_update_interval.insertItem(99, unicode(_("Every two weeks"), 'utf-8'))
465.2.2 by jr
Add some functionality
174
175
    update_days = self.get_update_interval()
176
177
    # If a custom period is defined add a corresponding entry
178
    if not update_days in self.combobox_interval_mapping.values():
179
        if update_days > 0:
465.3.5 by jr
implement translations
180
            self.userinterface.combobox_update_interval.insertItem(99, unicode(_("Every %s days"), 'utf-8') % update_days)
465.2.2 by jr
Add some functionality
181
            self.combobox_interval_mapping[4] = update_days
182
183
    for key in self.combobox_interval_mapping:
184
      if self.combobox_interval_mapping[key] == update_days:
185
        self.userinterface.combobox_update_interval.setCurrentIndex(key)
186
        break
187
188
    if update_days >= 1:
189
      self.userinterface.checkbutton_auto_update.setChecked(True)
190
      self.userinterface.combobox_update_interval.setEnabled(True)
465.2.8 by jr
Implement update functionality
191
      self.userinterface.radiobutton_updates_inst_sec.setEnabled(True)
192
      self.userinterface.radiobutton_updates_download.setEnabled(True)
193
      self.userinterface.radiobutton_updates_notify.setEnabled(True)
465.2.2 by jr
Add some functionality
194
    else:
195
      self.userinterface.checkbutton_auto_update.setChecked(False)
196
      self.userinterface.combobox_update_interval.setEnabled(False)
465.2.8 by jr
Implement update functionality
197
      self.userinterface.radiobutton_updates_inst_sec.setEnabled(False)
198
      self.userinterface.radiobutton_updates_download.setEnabled(False)
199
      self.userinterface.radiobutton_updates_notify.setEnabled(False)
465.2.2 by jr
Add some functionality
200
201
    self.app.connect(self.userinterface.radiobutton_updates_download, SIGNAL("toggled(bool)"), self.set_update_automation_level)
202
    self.app.connect(self.userinterface.radiobutton_updates_inst_sec, SIGNAL("toggled(bool)"), self.set_update_automation_level)
203
    self.app.connect(self.userinterface.radiobutton_updates_notify, SIGNAL("toggled(bool)"), self.set_update_automation_level)
204
465.2.3 by jr
show_auto_update_level
205
  def show_auto_update_level(self):
206
    """Represent the level of update automation in the user interface"""
207
    level = self.get_update_automation_level()
208
    if level == None:
209
        self.userinterface.radiobutton_updates_inst_sec.setChecked(False)
210
        self.userinterface.radiobutton_updates_download.setChecked(False)
211
        self.userinterface.radiobutton_updates_notify.setChecked(False)
482.1.13 by Sebastian Heinlein
* also handle the notify state in the kde frontend
212
    if level == softwareproperties.UPDATE_MANUAL or\
213
       level == softwareproperties.UPDATE_NOTIFY:
465.2.3 by jr
show_auto_update_level
214
        self.userinterface.radiobutton_updates_notify.setChecked(True)
215
    elif level == softwareproperties.UPDATE_DOWNLOAD:
216
        self.userinterface.radiobutton_updates_download.setChecked(True)
217
    elif level == softwareproperties.UPDATE_INST_SEC:
218
        self.userinterface.radiobutton_updates_inst_sec.setChecked(True)
465.2.5 by jr
show_distro()
219
510 by Jonathan Riddell
implement revert
220
  def init_distro(self):
465.2.5 by jr
show_distro()
221
    # TRANS: %s stands for the distribution name e.g. Debian or Ubuntu
465.3.5 by jr
implement translations
222
    text = "<b>%s</b>" % (_("%s updates") % self.distro.id)
510 by Jonathan Riddell
implement revert
223
    text = text.replace("Ubuntu", "Kubuntu")
519 by Jonathan Riddell
i18n fixes, closes https://launchpad.net/bugs/102773
224
    self.userinterface.label_updates.setText(unicode(text, 'UTF-8'))
465.2.5 by jr
show_distro()
225
    # TRANS: %s stands for the distribution name e.g. Debian or Ubuntu
465.3.5 by jr
implement translations
226
    text = _("%s Software") % self.distro.id
227
    text = unicode(text, 'utf-8')
510 by Jonathan Riddell
implement revert
228
    text = text.replace("Ubuntu", "Kubuntu")
229
    self.userinterface.tabWidget.setTabText(0, text)
465.2.5 by jr
show_distro()
230
231
    # Setup the checkbuttons for the components
232
    for child in self.userinterface.vbox_dist_comps_frame.children():
233
        if isinstance(child, QGridLayout):
234
            self.vbox_dist_comps = child
235
        else:
510 by Jonathan Riddell
implement revert
236
            child.hide()
465.2.5 by jr
show_distro()
237
            del child
510 by Jonathan Riddell
implement revert
238
    self.checkboxComps = {}
465.2.5 by jr
show_distro()
239
    for comp in self.distro.source_template.components:
240
        # TRANSLATORS: Label for the components in the Internet section
241
        #              first %s is the description of the component
242
        #              second %s is the code name of the comp, eg main, universe
243
        label = _("%s (%s)") % (comp.get_description(), comp.name)
465.3.5 by jr
implement translations
244
        checkbox = QCheckBox(unicode(label, 'utf-8'), self.userinterface.vbox_dist_comps_frame)
465.2.14 by jr
Implement tickbox functionality
245
        checkbox.setObjectName(comp.name)
510 by Jonathan Riddell
implement revert
246
        self.checkboxComps[checkbox] = comp
465.2.5 by jr
show_distro()
247
248
        # setup the callback and show the checkbutton
465.2.14 by jr
Implement tickbox functionality
249
        self.app.connect(checkbox, SIGNAL("clicked()"), self.on_component_toggled)
465.2.5 by jr
show_distro()
250
        self.vbox_dist_comps.addWidget(checkbox)
251
252
    # Setup the checkbuttons for the child repos / updates
253
    for child in self.userinterface.vbox_updates_frame.children():
254
        if isinstance(child, QGridLayout):
255
            self.vbox_updates = child
256
        else:
257
            del child
258
    if len(self.distro.source_template.children) < 1:
259
        self.userinterface.vbox_updates_frame.hide()
510 by Jonathan Riddell
implement revert
260
    self.checkboxTemplates = {}
465.2.5 by jr
show_distro()
261
    for template in self.distro.source_template.children:
465.3.5 by jr
implement translations
262
        checkbox = QCheckBox(unicode(template.description, 'utf-8'), self.userinterface.vbox_updates_frame)
465.2.14 by jr
Implement tickbox functionality
263
        checkbox.setObjectName(template.name)
510 by Jonathan Riddell
implement revert
264
        self.checkboxTemplates[checkbox] = template
465.2.5 by jr
show_distro()
265
        # setup the callback and show the checkbutton
465.2.14 by jr
Implement tickbox functionality
266
        self.app.connect(checkbox, SIGNAL("clicked()"), self.on_checkbutton_child_toggled)
465.2.5 by jr
show_distro()
267
        self.vbox_updates.addWidget(checkbox)
268
269
    # If no components are enabled there will be no need for updates
270
    if len(self.distro.enabled_comps) < 1:
465.2.14 by jr
Implement tickbox functionality
271
        self.userinterface.vbox_updates_frame.setEnabled(False)
465.2.5 by jr
show_distro()
272
    else:
465.2.14 by jr
Implement tickbox functionality
273
        self.userinterface.vbox_updates_frame.setEnabled(True)
465.2.5 by jr
show_distro()
274
275
    # Intiate the combobox which allows the user to specify a server for all
276
    # distro related sources
277
    seen_server_new = []
465.3.1 by jr
Add mirror dialogue
278
    self.mirror_urls = []
465.2.5 by jr
show_distro()
279
    for (name, uri, active) in self.distro.get_server_list():
280
        ##server_store.append([name, uri, False])
465.3.1 by jr
Add mirror dialogue
281
        self.userinterface.combobox_server.addItem(name)
282
        self.mirror_urls.append(uri)
465.2.5 by jr
show_distro()
283
        if [name, uri] in self.seen_server:
284
            self.seen_server.remove([name, uri])
285
        elif uri != None:
286
            seen_server_new.append([name, uri])
287
        if active == True:
288
            self.active_server = self.userinterface.combobox_server.count() - 1
289
            self.userinterface.combobox_server.setCurrentIndex(self.userinterface.combobox_server.count() - 1)
290
    for [name, uri] in self.seen_server:
465.3.1 by jr
Add mirror dialogue
291
        self.userinterface.combobox_server.addItem(name)
465.2.5 by jr
show_distro()
292
    self.seen_server = seen_server_new
293
    # add a separator and the option to choose another mirror from the list
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
294
    ##FIXME server_store.append(["sep", None, True])
465.3.5 by jr
implement translations
295
    self.userinterface.combobox_server.addItem(unicode(_("Other..."), 'utf-8'))
465.3.1 by jr
Add mirror dialogue
296
    self.mirror_urls.append("")
297
298
    self.app.connect(self.userinterface.combobox_server, SIGNAL("currentIndexChanged(int)"), self.on_combobox_server_changed)
465.2.5 by jr
show_distro()
299
510 by Jonathan Riddell
implement revert
300
  def show_distro(self):
301
    """
302
    Represent the distro information in the user interface
303
    """
304
    # Enable or disable the child source checkbuttons
305
    for child in self.userinterface.vbox_updates_frame.children():
306
        if isinstance(child, QCheckBox):
307
            template = self.checkboxTemplates[child]
308
            (active, inconsistent) = self.get_comp_child_state(template)
309
            if inconsistent:
310
                child.setCheckState(Qt.PartiallyChecked)
311
            elif active:
312
                child.setCheckState(Qt.Checked)
313
            else:
314
                child.setCheckState(Qt.Unchecked)
315
316
    # Enable or disable the component checkbuttons
317
    for child in self.userinterface.vbox_dist_comps_frame.children():
318
        if isinstance(child, QCheckBox):
319
            template = self.checkboxComps[child]
320
            (active, inconsistent) = self.get_comp_download_state(template)
321
            if inconsistent:
322
                child.setCheckState(Qt.PartiallyChecked)
323
            elif active:
324
                child.setCheckState(Qt.Checked)
325
            else:
326
                child.setCheckState(Qt.Unchecked)
327
328
    # If no components are enabled there will be no need for updates
329
    # and source code
330
    if len(self.distro.enabled_comps) < 1:
331
        self.userinterface.vbox_updates_frame.setEnabled(False)
332
        self.userinterface.checkbutton_source_code.setEnabled(False)
333
    else:
334
        self.userinterface.vbox_updates_frame.setEnabled(True)
335
        self.userinterface.checkbutton_source_code.setEnabled(True)
336
465.2.5 by jr
show_distro()
337
    # Check for source code sources
338
    source_code_state = self.get_source_code_state()
465.2.14 by jr
Implement tickbox functionality
339
    if source_code_state == True:
340
        self.userinterface.checkbutton_source_code.setCheckState(Qt.Checked)
341
    elif source_code_state == None:
465.2.5 by jr
show_distro()
342
        self.userinterface.checkbutton_source_code.setCheckState(Qt.PartiallyChecked)
343
    else:
344
        self.userinterface.checkbutton_source_code.setCheckState(Qt.Unchecked)
345
346
    # Will show a short explanation if no CDROMs are used
482.3.3 by Sebastian Heinlein
* support cdroms in the KDE frontend
347
    if len(self.get_cdrom_sources()) == 0:
465.2.5 by jr
show_distro()
348
        self.userinterface.treeview_cdroms.hide()
349
        self.userinterface.textview_no_cd.show()
465.2.16 by jr
tidying up
350
        self.userinterface.groupBox_cdrom.hide()
465.2.5 by jr
show_distro()
351
    else:
352
        self.userinterface.treeview_cdroms.show()
353
        self.userinterface.textview_no_cd.hide()
465.2.16 by jr
tidying up
354
        self.userinterface.groupBox_cdrom.show()
465.2.5 by jr
show_distro()
355
356
    # Output a lot of debug stuff
357
    if self.options.debug == True or self.options.massive_debug == True:
358
        print "ENABLED COMPS: %s" % self.distro.enabled_comps
359
        print "INTERNET COMPS: %s" % self.distro.download_comps
360
        print "MAIN SOURCES"
361
        for source in self.distro.main_sources:
362
            self.print_source_entry(source)
363
        print "CHILD SOURCES"
364
        for source in self.distro.child_sources:
365
            self.print_source_entry(source)
366
        print "CDROM SOURCES"
367
        for source in self.distro.cdrom_sources:
368
            self.print_source_entry(source)
369
        print "SOURCE CODE SOURCES"
370
        for source in self.distro.source_code_sources:
371
            self.print_source_entry(source)
372
        print "DISABLED SOURCES"
373
        for source in self.distro.disabled_sources:
374
            self.print_source_entry(source)
375
        print "ISV"
376
        for source in self.sourceslist_visible:
377
            self.print_source_entry(source)
378
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
379
  def set_update_automation_level(self, selected):
380
    """Call the backend to set the update automation level to the given 
381
       value"""
382
    if self.userinterface.radiobutton_updates_download.isChecked():
383
        SoftwareProperties.set_update_automation_level(self, softwareproperties.UPDATE_DOWNLOAD)
384
    elif self.userinterface.radiobutton_updates_inst_sec.isChecked():
385
        SoftwareProperties.set_update_automation_level(self, softwareproperties.UPDATE_INST_SEC)
386
    elif self.userinterface.radiobutton_updates_notify.isChecked():
387
        SoftwareProperties.set_update_automation_level(self, softwareproperties.UPDATE_NOTIFY)
510 by Jonathan Riddell
implement revert
388
    self.set_modified_config()
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
389
465.3.1 by jr
Add mirror dialogue
390
  def on_combobox_server_changed(self, combobox):
391
    """
392
    Replace the servers used by the main and update sources with
393
    the selected one
394
    """
395
    combobox = self.userinterface.combobox_server
396
    if combobox.currentIndex() == self.active_server:
397
        return
398
    uri = self.mirror_urls[combobox.currentIndex()]
399
    name = unicode(combobox.currentText())
465.3.5 by jr
implement translations
400
    if name == unicode(_("Other..."), 'utf-8'):
465.3.8 by jr
use datadir
401
        dialogue = DialogMirror(self.userinterface, self.datadir, self.distro, self.custom_mirrors)
465.3.5 by jr
implement translations
402
        self.translate_widget_children(dialogue)
465.3.1 by jr
Add mirror dialogue
403
        res = dialogue.run()
404
        if res != None:
405
            self.distro.change_server(res)
482.1.8 by Sebastian Heinlein
* KDE frontend:
406
            self.set_modified_sourceslist()
465.3.2 by jr
mirror dialogue and combo box all working
407
            ##FIXME insert new URL into combo box
465.3.1 by jr
Add mirror dialogue
408
        else:
465.3.2 by jr
mirror dialogue and combo box all working
409
            combobox.setCurrentIndex(self.active_server)
465.3.1 by jr
Add mirror dialogue
410
    elif uri != None and len(self.distro.used_servers) > 0:
411
        self.active_server = combobox.currentIndex()
412
        self.distro.change_server(uri)
482.1.8 by Sebastian Heinlein
* KDE frontend:
413
        self.set_modified_sourceslist()
465.3.1 by jr
Add mirror dialogue
414
    else:
415
        self.distro.default_server = uri
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
416
465.2.14 by jr
Implement tickbox functionality
417
  def on_component_toggled(self):
465.2.5 by jr
show_distro()
418
    """
419
    Sync the components of all main sources (excluding cdroms),
420
    child sources and source code sources
421
    """
465.2.14 by jr
Implement tickbox functionality
422
    tickBox = self.app.sender()
423
    if tickBox.checkState() == Qt.Checked:
424
        self.enable_component(str(tickBox.objectName()))
425
    elif tickBox.checkState() == Qt.Unchecked:
426
        self.disable_component(str(tickBox.objectName()))
482.1.8 by Sebastian Heinlein
* KDE frontend:
427
    self.set_modified_sourceslist()
465.2.14 by jr
Implement tickbox functionality
428
465.2.16 by jr
tidying up
429
    # no way to set back to mixed state so turn off tristate
430
    tickBox.setTristate(False)
465.2.14 by jr
Implement tickbox functionality
431
432
  def on_checkbutton_child_toggled(self):
433
    """
434
    Enable or disable a child repo of the distribution main repository
435
    """
436
    tickBox = self.app.sender()
437
    name = str(tickBox.objectName())
438
    for template in self.distro.source_template.children:
439
        if name == template.name:
440
            aptTemplate = template
441
442
    if tickBox.checkState() == Qt.Checked:
443
        self.enable_child_source(aptTemplate)
444
    elif tickBox.checkState() == Qt.Unchecked:
445
        self.disable_child_source(aptTemplate)
465.2.16 by jr
tidying up
446
    # no way to set back to mixed state so turn off tristate
447
    tickBox.setTristate(False)
465.2.6 by jr
implement authentication page functionality
448
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
449
  def on_checkbutton_source_code_toggled(self):
450
    """ Disable or enable the source code for all sources """
451
    if self.userinterface.checkbutton_source_code.checkState() == Qt.Checked:
452
        self.enable_source_code_sources()
453
    elif self.userinterface.checkbutton_source_code.checkState() == Qt.Unchecked:
454
        self.disable_source_code_sources()
455
    self.userinterface.checkbutton_source_code.setTristate(False)
456
457
  def on_checkbutton_popcon_toggled(self, state):
458
    """ The user clicked on the popcon paritipcation button """
459
    self.set_popcon_pariticipation(state)
460
461
  def init_isv_sources(self):
462
    """Read all valid sources into our ListStore"""
482.3.1 by Sebastian Heinlein
* Remove references to the deprecated term software channel
463
    self.userinterface.treeview_cdroms.setHeaderLabel(unicode(_("Software Sources"), 'utf-8'))
464
    self.userinterface.treeview_sources.setHeaderLabel(unicode(_("Software Sources"), 'utf-8'))
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
465
466
    """##FIXME
467
    # drag and drop support for sources.list
468
    self.treeview_sources.drag_dest_set(gtk.DEST_DEFAULT_ALL, \
469
                                        [('text/uri-list',0, 0)], \
470
                                        gtk.gdk.ACTION_COPY)
471
    self.treeview_sources.connect("drag_data_received",\
472
                                  self.on_sources_drag_data_received)
473
    """
474
475
  def on_isv_source_activate(self, treeview, path, column):
476
    """Open the edit dialog if a channel was double clicked"""
477
    ##FIXME TODO
478
    ##self.on_edit_clicked(treeview)
479
480
  def on_treeview_sources_cursor_changed(self, item, column):
481
    """set the sensitiveness of the edit and remove button
482
       corresponding to the selected channel"""
483
    # allow to remove the selected channel
484
    self.userinterface.button_remove.setEnabled(True)
485
    # disable editing of cdrom sources
486
    index = self.userinterface.treeview_sources.indexOfTopLevelItem(item)
487
    source_entry = self.isv_sources[index]
488
    if source_entry.uri.startswith("cdrom:"):
489
        self.userinterface.button_edit.setEnabled(False)
490
    else:
491
        self.userinterface.button_edit.setEnabled(True)
492
482.3.3 by Sebastian Heinlein
* support cdroms in the KDE frontend
493
  def on_cdrom_source_toggled(self, item):
494
    """Enable or disable the selected channel"""
495
    index = self.userinterface.treeview_cdroms.indexOfTopLevelItem(item)
496
    source_entry = self.cdrom_sources[index]
497
    self.toggle_source_use(source_entry)
498
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
499
  def on_isv_source_toggled(self, item):
500
    """Enable or disable the selected channel"""
501
    index = self.userinterface.treeview_sources.indexOfTopLevelItem(item)
502
    source_entry = self.isv_sources[index]
503
    self.toggle_source_use(source_entry)
504
505
  def init_keys(self):
506
    """Setup the user interface parts needed for the key handling"""
507
    self.userinterface.treeview2.setColumnCount(1)
465.3.5 by jr
implement translations
508
    self.userinterface.treeview2.setHeaderLabels([unicode(_("Key"), 'utf-8')])
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
509
510 by Jonathan Riddell
implement revert
510
  #FIXME revert automation settings too
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
511
  def on_button_revert_clicked(self):
512
    """Restore the source list from the startup of the dialog"""
510 by Jonathan Riddell
implement revert
513
    SoftwareProperties.revert(self)
514
    self.set_modified_sourceslist()
515
    self.show_auto_update_level()
482.1.22 by Sebastian Heinlein
* rename the restore defaults button in the main interface
516
    self.userinterface.buttonBox.button(QDialogButtonBox.Reset).setEnabled(False)
510 by Jonathan Riddell
implement revert
517
    self.modified_sourceslist = False
518
519
  def set_modified_config(self):
520
    """The config was changed and now needs to be saved and reloaded"""
521
    SoftwareProperties.set_modified_config(self)
522
    self.userinterface.buttonBox.button(QDialogButtonBox.Reset).setEnabled(True)
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
523
482.1.8 by Sebastian Heinlein
* KDE frontend:
524
  def set_modified_sourceslist(self):
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
525
    """The sources list was changed and now needs to be saved and reloaded"""
482.1.8 by Sebastian Heinlein
* KDE frontend:
526
    SoftwareProperties.set_modified_sourceslist(self)
510 by Jonathan Riddell
implement revert
527
    self.show_distro()
528
    self.show_isv_sources()
482.3.3 by Sebastian Heinlein
* support cdroms in the KDE frontend
529
    self.show_cdrom_sources()
482.1.22 by Sebastian Heinlein
* rename the restore defaults button in the main interface
530
    self.userinterface.buttonBox.button(QDialogButtonBox.Reset).setEnabled(True)
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
531
532
  def show_isv_sources(self):
533
    """ Show the repositories of independent software vendors in the
534
        third-party software tree view """
535
    self.userinterface.treeview_sources.clear()
536
    self.isv_sources = []
537
538
    for source in self.get_isv_sources():
539
        contents = self.render_source(source)
540
        contents = contents.replace("<b>", "")
541
        contents = contents.replace("</b>", "")
542
        item = QTreeWidgetItem([contents])
543
        if not source.disabled:
544
            item.setCheckState(0, Qt.Checked)
545
        else:
546
            item.setCheckState(0, Qt.Unchecked)
547
        self.userinterface.treeview_sources.addTopLevelItem(item)
548
        self.isv_sources.append(source)
549
550
    if self.userinterface.treeview_sources.topLevelItemCount() < 1:
551
        self.userinterface.button_remove.setEnabled(False)
552
        self.userinterface.button_edit.setEnabled(False)
553
554
  def show_cdrom_sources(self):
555
    """ Show CD-ROM/DVD based repositories of the currently used distro in
556
        the CDROM based sources list """
482.3.3 by Sebastian Heinlein
* support cdroms in the KDE frontend
557
    self.userinterface.treeview_cdroms.clear()
558
    self.cdrom_sources = []
559
560
    for source in self.get_cdrom_sources():
561
        contents = self.render_source(source)
562
        contents = contents.replace("<b>", "")
563
        contents = contents.replace("</b>", "")
564
        item = QTreeWidgetItem([contents])
565
        if not source.disabled:
566
            item.setCheckState(0, Qt.Checked)
567
        else:
568
            item.setCheckState(0, Qt.Unchecked)
569
        self.userinterface.treeview_cdroms.addTopLevelItem(item)
570
        self.cdrom_sources.append(source)
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
571
    
572
  def show_keys(self):
573
    self.userinterface.treeview2.clear()
574
    for key in self.apt_key.list():
511 by Jonathan Riddell
i18n fix
575
      self.userinterface.treeview2.addTopLevelItem(QTreeWidgetItem([unicode(key, 'UTF-8')]))
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
576
577
  def on_combobox_update_interval_changed(self, index):
578
    #FIXME! move to backend
579
    if index != -1:
580
        value = self.combobox_interval_mapping[index]
581
        # Only write the key if it has changed
582
        if not value == apt_pkg.Config.FindI(softwareproperties.CONF_MAP["autoupdate"]):
583
            apt_pkg.Config.Set(softwareproperties.CONF_MAP["autoupdate"], str(value))
584
            self.write_config()
585
586
  def on_auto_update_toggled(self):
587
    """Enable or disable automatic updates and modify the user interface
588
       accordingly"""
589
    if self.userinterface.checkbutton_auto_update.checkState() == Qt.Checked:
590
      self.userinterface.combobox_update_interval.setEnabled(True)
591
      self.userinterface.radiobutton_updates_inst_sec.setEnabled(True)
592
      self.userinterface.radiobutton_updates_download.setEnabled(True)
593
      self.userinterface.radiobutton_updates_notify.setEnabled(True)
594
      # if no frequency was specified use daily
595
      i = self.userinterface.combobox_update_interval.currentIndex()
596
      if i == -1:
597
          i = 0
598
          self.userinterface.combobox_update_interval.setCurrentIndex(i)
599
      value = self.combobox_interval_mapping[i]
600
    else:
601
      self.userinterface.combobox_update_interval.setEnabled(False)
602
      self.userinterface.radiobutton_updates_inst_sec.setEnabled(False)
603
      self.userinterface.radiobutton_updates_download.setEnabled(False)
604
      self.userinterface.radiobutton_updates_notify.setEnabled(False)
605
      SoftwareProperties.set_update_automation_level(self, None)
606
      value = 0
607
    self.set_update_interval(str(value))
608
609
  def on_add_clicked(self):
610
    """Show a dialog that allows to enter the apt line of a to be used repo"""
482.2.2 by Sebastian Heinlein
* also create the exmaple line on runtime in the KDE frontend
611
    if self.distro:
612
        example = "%s %s %s %s" % (self.distro.binary_type,
613
                                   self.distro.source_template.base_uri,
614
                                   self.distro.codename,
615
                                   self.distro.source_template.components[0].name)
616
    else:
617
        example = "deb http://ftp.debian.org sarge main"
618
    # L10N: the example is of the format: deb http://ftp.debian.org sarge main
619
    text = _('<p><b>Enter the complete APT line of the<br /> repository that you want to add as source</b></p><p>The APT line includes the type, location and components of a repository,<br /> for example <i>"%s"</i>.</p>' % example)
465.3.5 by jr
implement translations
620
    (line, valid) = QInputDialog.getText(self.userinterface, unicode(_("Add APT repository"), 'utf-8'), text)
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
621
    uline = unicode(line)
622
    if valid:
623
        self.add_source_from_line(uline)
624
        self.show_isv_sources()
625
626
  def on_edit_clicked(self):
627
    """Show a dialog to edit an ISV source"""
628
    item = self.userinterface.treeview_sources.currentItem()
629
    if item is not None:
630
        index = self.userinterface.treeview_sources.indexOfTopLevelItem(item)
631
        dialogue = DialogEdit(self.userinterface, self.sourceslist, self.isv_sources[index], self.datadir)
465.3.5 by jr
implement translations
632
        self.translate_widget_children(dialogue)
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
633
        result = dialogue.run()
634
        if result == QDialog.Accepted:
482.1.8 by Sebastian Heinlein
* KDE frontend:
635
            self.set_modified_sourceslist()
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
636
            self.show_isv_sources()
637
638
  # FIXME:outstanding from merge
639
  def on_isv_source_activated(self, treeview, path, column):
640
     """Open the edit dialog if a channel was double clicked"""
641
     ##FIXME TODO
642
     # check if the channel can be edited
643
     if self.button_edit.get_property("sensitive") == True:
644
         self.on_edit_clicked(treeview)
645
646
  def on_remove_clicked(self):
647
    """Remove the selected source"""
648
    item = self.userinterface.treeview_sources.currentItem()
649
    if item is not None:
650
        index = self.userinterface.treeview_sources.indexOfTopLevelItem(item)
651
        self.remove_source(self.isv_sources[index])
652
        self.show_isv_sources()
653
465.2.6 by jr
implement authentication page functionality
654
  def add_key_clicked(self):
655
    """Provide a file chooser that allows to add the gnupg of a trusted
656
       software vendor"""
465.3.5 by jr
implement translations
657
    filename = QFileDialog.getOpenFileName(self.userinterface, unicode(_("Import key"), 'utf-8'))
465.2.6 by jr
implement authentication page functionality
658
    if filename is not None:
659
      if not self.add_key(filename):
465.3.5 by jr
implement translations
660
        title = _("Error importing selected file")
661
        text = _("The selected file may not be a GPG key file " \
662
                "or it might be corrupt.")
465.2.6 by jr
implement authentication page functionality
663
        QMessageBox.warning(self.userinterface,
465.3.5 by jr
implement translations
664
              unicode(title, 'utf-8'),
665
              unicode(text, 'utf-8'))
465.2.6 by jr
implement authentication page functionality
666
      self.show_keys()
667
668
  def remove_key_clicked(self):
669
    """Remove a trusted software vendor key"""
670
    item = self.userinterface.treeview2.currentItem()
671
    if item == None:
672
        return
673
    key = item.text(0)
674
    if self.remove_key(key[:8]):
465.3.5 by jr
implement translations
675
      title = _("Error removing the key")
676
      text = _("The key you selected could not be removed. "
677
               "Please report this as a bug.")
678
      QMessageBox.warning(self.userinterface, unicode(title, 'utf-8'), unicode(text, 'utf-8'))
465.2.6 by jr
implement authentication page functionality
679
    self.show_keys()
680
681
  def on_restore_clicked(self):
682
    """Restore the original keys"""
683
    self.apt_key.update()
684
    self.show_keys()
685
686
  def on_close_button(self):
687
    """Show a dialog that a reload of the channel information is required
688
       only if there is no parent defined"""
529 by Jonathan Riddell
Make KDE frontend call adept_batch update when sources need to be updated, also implement --no-update for gtk frontend
689
    if self.modified_sourceslist == True and self.options.no_update == False:
465.2.6 by jr
implement authentication page functionality
690
        messageBox = QMessageBox(self.userinterface)
691
        messageBox.setIcon(QMessageBox.Information)
529 by Jonathan Riddell
Make KDE frontend call adept_batch update when sources need to be updated, also implement --no-update for gtk frontend
692
        reloadButton = messageBox.addButton(unicode(_("Reload"), 'utf-8'), QMessageBox.AcceptRole)
693
        messageBox.addButton(QMessageBox.Close)
465.3.5 by jr
implement translations
694
        text = _("<b><big>The information about available software is out-of-date</big></b>\n"
695
               "\n"
696
               "To install software and updates from newly added or changed sources, you "
697
               "have to reload the information about available software.\n"
698
               "\n"
699
               "You need a working internet connection to continue.")
700
        text = text.replace("\n", "<br />")
701
        messageBox.setText(unicode(text, 'utf-8'))
465.2.6 by jr
implement authentication page functionality
702
        messageBox.exec_()
529 by Jonathan Riddell
Make KDE frontend call adept_batch update when sources need to be updated, also implement --no-update for gtk frontend
703
        if (messageBox.clickedButton() == reloadButton):
704
                cmd = ["/usr/bin/adept_batch", "update"]
705
                subprocess.call(cmd)
465.2.6 by jr
implement authentication page functionality
706
    self.app.quit()
465.2.7 by jr
Implement popcon (as far as it goes)
707
465.2.11 by jr
most of add CD-ROM implemented
708
  def on_button_add_cdrom_clicked(self):
709
    '''Show a dialog that allows to add a repository located on a CDROM
710
       or DVD'''
711
    # testing
712
    #apt_pkg.Config.Set("APT::CDROM::Rename","true")
713
714
    saved_entry = apt_pkg.Config.Find("Dir::Etc::sourcelist")
715
    tmp = tempfile.NamedTemporaryFile()
716
    apt_pkg.Config.Set("Dir::Etc::sourcelist",tmp.name)
717
    progress = CdromProgress(self.datadir, self)
718
    cdrom = apt_pkg.GetCdrom()
719
    # if nothing was found just return
720
    try:
721
      res = cdrom.Add(progress)
722
    except SystemError, msg:
723
      progress.close()
465.3.5 by jr
implement translations
724
      title = _("CD Error")
725
      text = _("<big><b>Error scanning the CD</b></big>\n\n%s")%msg
726
      QMessageBox.warning(self.userinterface, unicode(title, 'utf-8'), unicode(text, 'utf-8'))
465.2.11 by jr
most of add CD-ROM implemented
727
      return
728
    apt_pkg.Config.Set("Dir::Etc::sourcelist",saved_entry)
729
    if res == False:
730
      progress.close()
731
      return
732
    # read tmp file with source name (read only last line)
733
    line = ""
734
    for x in open(tmp.name):
735
      line = x
736
    if line != "":
737
      full_path = "%s%s" % (apt_pkg.Config.FindDir("Dir::Etc"),saved_entry)
465.2.19 by jr
Merge with Sebastian Heinlein
738
      self.sourceslist.list.append(SourceEntry(line,full_path))
482.1.8 by Sebastian Heinlein
* KDE frontend:
739
      self.set_modified_sourceslist()
465.2.22 by jr
reorder methods in SoftwarePropertiesKDE.py to be same order as in SoftwarePropertiesGtk.py
740
741
  def run(self):
742
    self.app.exec_()