159
161
APP_ICON_SIZE = Gtk.IconSize.DIALOG
161
163
def __init__(self, datadir, xapian_base_path, options, args=None):
162
# setup dbus and exit if there is another instance already
164
self.dbusControler = None
165
# setup dbus and exit if there is another instance already running
164
166
self.setup_dbus_or_bring_other_instance_to_front(args)
166
168
self.datadir = datadir
167
SimpleGtkbuilderApp.__init__(self,
169
super(SoftwareCenterAppGtk3, self).__init__(
168
170
datadir + "/ui/gtk3/SoftwareCenter.ui",
169
171
"software-center")
170
172
gettext.bindtextdomain("software-center", "/usr/share/locale")
517
519
def on_review_stats_loaded(self, reviews):
518
520
LOG.debug("on_review_stats_loaded: '%s'" % len(reviews))
523
"""Destroy this instance and every used resource."""
524
self.window_main.destroy()
526
# remove global instances of Managers
527
self.app_manager.destroy()
528
self.view_manager.destroy()
530
if self.dbusControler is not None:
531
# ensure that the dbus controller is really gone
532
self.dbusControler.stop()
520
534
def close_app(self):
521
535
""" perform tasks like save-state etc when the application is
531
545
if hasattr(self, "glaunchpad"):
532
546
self.glaunchpad.shutdown()
533
547
self.save_state()
534
550
# this will not throw exceptions in pygi but "only" log via g_critical
535
551
# to the terminal but it might in the future so we add a handler here
539
555
LOG.exception("Gtk.main_quit failed")
540
# ensure that the dbus controller is really gone, just for good
542
self.dbusControler.stop()
543
557
# exit here explictely to ensure that no further gtk event loops or
544
558
# threads run and cause havoc on exit (LP: #914393)
1209
1223
bus_name = dbus.service.BusName('com.ubuntu.Softwarecenter', bus)
1210
1224
self.dbusControler = SoftwarecenterDbusController(self, bus_name)
1212
def show_available_packages(self, packages):
1226
@wait_for_apt_cache_ready
1227
def show_app(self, app):
1228
"""Show 'app' in the installed pane if is installed.
1230
If 'app' is not installed, show it in the available pane.
1233
print '\n\n\n=============================== show_available_packages (app installed?)', (app.pkgname in self.cache and self.cache[app.pkgname].installed)
1234
if (app.pkgname in self.cache and self.cache[app.pkgname].installed):
1235
with ExecutionTime("installed_pane.init_view()"):
1236
self.installed_pane.init_view()
1237
with ExecutionTime("installed_pane.show_app()"):
1238
self.installed_pane.show_app(app)
1240
self.available_pane.init_view()
1241
self.available_pane.show_app(app)
1243
def show_search_text(self, text):
1244
"""Set 'text' to be the search text in the available pane."""
1245
self.available_pane.init_view()
1246
self.available_pane.searchentry.set_text(search_text)
1248
def _show_available_packages(self, packages):
1213
1249
""" Show packages given as arguments in the available_pane
1214
1250
If the list of packages is only one element long show that,
1215
1251
otherwise turn it into a comma seperated search
1235
1272
_packages[0] = _packages[0].partition(prefix)[2]
1237
1274
# allow s-c to be called with a search term
1238
if packages[0].startswith("search:"):
1239
packages[0] = packages[0].partition("search:")[2]
1240
self.available_pane.init_view()
1241
self.available_pane.searchentry.set_text(" ".join(packages))
1275
if _packages[0].startswith("search:"):
1276
_packages[0] = _packages[0].partition("search:")[2]
1277
self.show_search_text(" ".join(_packages))
1244
1280
print '\n-> show_available_packages len is', len(_packages)
1245
1281
print '\n-> show_available_packages content is', repr(_packages)
1247
1284
if len(_packages) == 1:
1248
1285
request = _packages[0]
1286
print '\n-> exactly one package! ', request
1288
# are we dealing with a path?
1289
if os.path.exists(request) and not os.path.isdir(request):
1290
if not request.startswith(os.path.sep):
1291
# we may have been given a relative path
1292
request = os.path.join(os.getcwd(), request)
1293
app = DebFileApplication(request)
1295
# package from archive
1296
# if there is a "/" in the string consider it as tuple
1297
# of (pkgname, appname) for exact matching (used by
1299
(pkgname, sep, appname) = request.partition("/")
1300
if pkgname or appname:
1301
app = Application(appname, pkgname)
1303
LOG.warning('show_available_packages: received %r but '
1304
'can\'t build an Application from it.', request)
1305
elif len(_packages) > 1:
1306
print '\n-> more than one package! ', _packages
1307
search_text = ",".join(_packages)
1308
# turn multiple packages into a search with ","
1309
self.show_search_text(",".join(_packages))
1312
print '\n-> app is None? ', app is None
1318
print '\n-> setting self.view_manager.set_active_view to ', ViewPages.AVAILABLE
1320
# normal startup, show the lobby (it will have a spinner when
1321
# its not ready yet) - it will also initialize the view
1322
self.view_manager.set_active_view(ViewPages.AVAILABLE)
1324
def show_available_packages(self, packages):
1325
""" Show packages given as arguments in the available_pane
1326
If the list of packages is only one element long show that,
1327
otherwise turn it into a comma seperated search
1330
print '\n\n\n=============================== show_available_packages', packages
1332
# strip away the apt: prefix
1333
if packages and packages[0].startswith("apt:///"):
1334
# this is for 'apt:pkgname' in alt+F2 in gnome
1335
packages[0] = packages[0].partition("apt:///")[2]
1336
elif packages and packages[0].startswith("apt://"):
1337
packages[0] = packages[0].partition("apt://")[2]
1338
elif packages and packages[0].startswith("apt:"):
1339
packages[0] = packages[0].partition("apt:")[2]
1341
# allow s-c to be called with a search term
1342
if packages and packages[0].startswith("search:"):
1343
packages[0] = packages[0].partition("search:")[2]
1344
self.available_pane.init_view()
1345
self.available_pane.searchentry.set_text(" ".join(packages))
1348
if len(packages) == 1:
1349
request = packages[0]
1350
print '\n\n\n=============================== show_available_packages (request)', request
1250
1352
# are we dealing with a path?
1251
1353
if os.path.exists(request) and not os.path.isdir(request):
1258
1360
# if there is a "/" in the string consider it as tuple
1259
1361
# of (pkgname, appname) for exact matching (used by
1262
# when passing [''] to bringToFront, this triggers:
1263
# org.freedesktop.DBus.Python.ValueError: Traceback (most recent call last):
1264
# File "/usr/lib/python2.7/dist-packages/dbus/service.py", line 707, in _message_cb
1265
# retval = candidate_method(self, *args, **keywords)
1266
# File "/home/nessita/canonical/software-store/fix-977931/softwarecenter/ui/gtk3/app.py", line 144, in bringToFront
1267
# self.parent.show_available_packages(args)
1268
# File "/home/nessita/canonical/software-store/fix-977931/softwarecenter/ui/gtk3/app.py", line 1250, in show_available_packages
1269
# app = Application(appname, pkgname)
1270
# File "/home/nessita/canonical/software-store/fix-977931/softwarecenter/db/application.py", line 52, in __init__
1271
# raise ValueError("Need either appname or pkgname or request")
1272
# ValueError: Need either appname or pkgname or request
1274
(pkgname, sep, appname) = _packages[0].partition("/")
1275
# pkgname and/or appname can be ''
1276
print '\n\n***** creating an Application with %r and %r' % (appname, pkgname)
1363
(pkgname, sep, appname) = packages[0].partition("/")
1277
1364
app = Application(appname, pkgname)
1366
print '\n\n\n=============================== show_available_packages (app?)', repr(app)
1279
1368
@wait_for_apt_cache_ready
1280
1369
def show_app(self, app):
1281
1370
# if the pkg is installed, show it in the installed pane
1289
1378
self.available_pane.init_view()
1290
1379
self.available_pane.show_app(app)
1293
elif len(_packages) > 1:
1383
elif len(packages) > 1:
1294
1384
# turn multiple packages into a search with ","
1295
1385
self.available_pane.init_view()
1296
self.available_pane.searchentry.set_text(",".join(_packages))
1386
self.available_pane.searchentry.set_text(",".join(packages))
1299
print '\n-> setting self.view_manager.set_active_view to ', ViewPages.AVAILABLE
1301
1388
# normal startup, show the lobby (it will have a spinner when
1302
1389
# its not ready yet) - it will also initialize the view
1303
1390
self.view_manager.set_active_view(ViewPages.AVAILABLE)
1327
1414
# initial default state is to add to launcher, per spec
1328
1415
self.available_pane.add_to_launcher_enabled = True
1417
def restore_state(self):
1418
if self.config.has_option("general", "size"):
1419
(x, y) = self.config.get("general", "size").split(",")
1420
self.window_main.set_default_size(int(x), int(y))
1422
# on first launch, specify the default window size to take
1423
# advantage of the available screen real estate (but set a
1424
# reasonable limit in case of a crazy-huge monitor)
1425
screen_height = Gdk.Screen.height()
1426
screen_width = Gdk.Screen.width()
1427
self.window_main.set_default_size(
1428
min(int(.85 * screen_width), 1200),
1429
min(int(.85 * screen_height), 800))
1430
if (self.config.has_option("general", "maximized") and
1431
self.config.getboolean("general", "maximized")):
1432
self.window_main.maximize()
1433
if self.config.has_option("general", "add_to_launcher"):
1434
self.available_pane.add_to_launcher_enabled = (
1435
self.config.getboolean(
1439
# initial default state is to add to launcher, per spec
1440
self.available_pane.add_to_launcher_enabled = True
1330
1442
def save_state(self):
1331
1443
LOG.debug("save_state")
1332
1444
# this happens on a delete event, we explicitely save_state() there