Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

# -*- coding: utf-8 -*- 

# 

# Copyright (C) 2008 Marcos Pinto ('markybob') <markybob@gmail.com> 

# 

# This file is part of Deluge and is licensed under GNU General Public License 3.0, or later, with 

# the additional special exception to link portions of this program with the OpenSSL library. 

# See LICENSE for more details. 

# 

"""Common functions for various parts of gtkui to use.""" 

 

import cPickle 

import logging 

import os 

import shutil 

import sys 

 

import gtk 

import pygtk 

from gobject import GError 

 

import deluge.common 

 

pygtk.require('2.0') 

 

 

log = logging.getLogger(__name__) 

 

 

def get_logo(size): 

    """A Deluge logo. 

 

    Params: 

        size (int): Size of logo in pixels 

 

    Returns: 

        gtk.gdk.Pixbuf: deluge logo 

    """ 

    filename = "deluge.svg" 

    if deluge.common.windows_check() or deluge.common.osx_check(): 

        filename = "deluge.png" 

    try: 

        return gtk.gdk.pixbuf_new_from_file_at_size(deluge.common.get_pixmap(filename), size, size) 

    except GError as ex: 

        log.warning(ex) 

 

 

def build_menu_radio_list(value_list, callback, pref_value=None, suffix=None, show_notset=False, 

                          notset_label="∞", notset_lessthan=0, show_other=False): 

    """Build a menu with radio menu items from a list and connect them to the callback. 

 

    Params: 

    value_list [list]: List of values to build into a menu. 

    callback (function): The function to call when menu item is clicked. 

    pref_value (int): A preferred value to insert into value_list 

    suffix (str): Append a suffix the the menu items in value_list. 

    show_notset (bool): Show the unlimited menu item. 

    notset_label (str): The text for the unlimited menu item. 

    notset_lessthan (int): Activates the unlimited menu item if pref_value is less than this. 

    show_other (bool): Show the `Other` menu item. 

 

    The pref_value is what you would like to test for the default active radio item. 

 

    Returns: 

        gtk.Menu: The menu radio 

    """ 

    menu = gtk.Menu() 

    group = None 

 

    if pref_value > -1 and pref_value not in value_list: 

        value_list.pop() 

        value_list.append(pref_value) 

 

    for value in sorted(value_list): 

        item_text = str(value) 

        if suffix: 

            item_text += " " + suffix 

        menuitem = gtk.RadioMenuItem(group, item_text) 

        group = menuitem 

        if pref_value and value == pref_value: 

            menuitem.set_active(True) 

        if callback: 

            menuitem.connect("toggled", callback) 

        menu.append(menuitem) 

 

    if show_notset: 

        menuitem = gtk.RadioMenuItem(group, notset_label) 

        menuitem.set_name("unlimited") 

        if pref_value and pref_value < notset_lessthan: 

            menuitem.set_active(True) 

        menuitem.connect("toggled", callback) 

        menu.append(menuitem) 

 

    if show_other: 

        menuitem = gtk.SeparatorMenuItem() 

        menu.append(menuitem) 

        menuitem = gtk.MenuItem(_("Other...")) 

        menuitem.set_name("other") 

        menuitem.connect("activate", callback) 

        menu.append(menuitem) 

 

    return menu 

 

 

def reparent_iter(treestore, itr, parent, move_siblings=False): 

    """ 

    This effectively moves itr plus it's children to be a child of parent in treestore 

 

    Params: 

        treestore (gtkTreeStore): the treestore 

        itr (gtkTreeIter): the iter to move 

        parent (gtkTreeIter): the new parent for itr 

        move_siblings (bool): if True, it will move all itr's siblings to parent 

    """ 

    src = itr 

 

    def move_children(i, dest): 

        while i: 

            n_cols = treestore.append(dest, treestore.get(i, *xrange(treestore.get_n_columns()))) 

            to_remove = i 

            if treestore.iter_children(i): 

                move_children(treestore.iter_children(i), n_cols) 

            if i != src: 

                i = treestore.iter_next(i) 

            else: 

                # This is the source iter, we don't want other iters in it's level 

                if not move_siblings: 

                    i = None 

            treestore.remove(to_remove) 

 

    move_children(itr, parent) 

 

 

def get_deluge_icon(): 

    """The deluge icon for use in dialogs. 

 

    It will first attempt to get the icon from the theme and will fallback to using an image 

    that is distributed with the package. 

 

    Returns: 

        gtk.gdk.Pixbuf: the deluge icon 

    """ 

    if deluge.common.windows_check(): 

        return get_logo(32) 

    else: 

        try: 

            icon_theme = gtk.icon_theme_get_default() 

            return icon_theme.load_icon("deluge", 64, 0) 

        except GError: 

            return get_logo(64) 

 

 

def associate_magnet_links(overwrite=False): 

    """ 

    Associates magnet links to Deluge. 

 

    Params: 

        overwrite (bool): if this is True, the current setting will be overwritten 

 

    Returns: 

        bool: True if association was set 

    """ 

 

    if deluge.common.windows_check(): 

        import _winreg 

 

        try: 

            hkey = _winreg.OpenKey(_winreg.HKEY_CLASSES_ROOT, "Magnet") 

        except WindowsError: 

            overwrite = True 

        else: 

            _winreg.CloseKey(hkey) 

 

        if overwrite: 

            deluge_exe = os.path.join(os.path.dirname(sys.executable), "deluge.exe") 

            magnet_key = _winreg.CreateKey(_winreg.HKEY_CLASSES_ROOT, "Magnet") 

            _winreg.SetValue(magnet_key, "", _winreg.REG_SZ, "URL:Magnet Protocol") 

            _winreg.SetValueEx(magnet_key, "URL Protocol", 0, _winreg.REG_SZ, "") 

            _winreg.SetValueEx(magnet_key, "BrowserFlags", 0, _winreg.REG_DWORD, 0x8) 

            _winreg.SetValue(magnet_key, "DefaultIcon", _winreg.REG_SZ, "{},0".format(deluge_exe)) 

            _winreg.SetValue(magnet_key, r"shell\open\command", _winreg.REG_SZ, '"{}" "%1"'.format(deluge_exe)) 

            _winreg.CloseKey(magnet_key) 

 

    # Don't try associate magnet on OSX see: #2420 

    elif not deluge.common.osx_check(): 

        # gconf method is only available in a GNOME environment 

        try: 

            import gconf 

        except ImportError: 

            log.debug("gconf not available, so will not attempt to register magnet uri handler") 

            return False 

        else: 

            key = "/desktop/gnome/url-handlers/magnet/command" 

            gconf_client = gconf.client_get_default() 

            if (gconf_client.get(key) and overwrite) or not gconf_client.get(key): 

                # We are either going to overwrite the key, or do it if it hasn't been set yet 

                if gconf_client.set_string(key, "deluge '%s'"): 

                    gconf_client.set_bool("/desktop/gnome/url-handlers/magnet/needs_terminal", False) 

                    gconf_client.set_bool("/desktop/gnome/url-handlers/magnet/enabled", True) 

                    log.info("Deluge registered as default magnet uri handler!") 

                    return True 

                else: 

                    log.error("Unable to register Deluge as default magnet uri handler.") 

                    return False 

    return False 

 

 

def save_pickled_state_file(filename, state): 

    """Save a file in the config directory and creates a backup 

 

    Params: 

        filename (str): Filename to be saved to config 

        state (state): The data to be pickled and written to file 

    """ 

    from deluge.configmanager import get_config_dir 

    filepath = os.path.join(get_config_dir(), "gtkui_state", filename) 

    filepath_bak = filepath + ".bak" 

    filepath_tmp = filepath + ".tmp" 

 

    try: 

        if os.path.isfile(filepath): 

            log.debug("Creating backup of %s at: %s", filename, filepath_bak) 

            shutil.copy2(filepath, filepath_bak) 

    except IOError as ex: 

        log.error("Unable to backup %s to %s: %s", filepath, filepath_bak, ex) 

    else: 

        log.info("Saving the %s at: %s", filename, filepath) 

        try: 

            with open(filepath_tmp, "wb") as _file: 

                # Pickle the state object 

                cPickle.dump(state, _file) 

                _file.flush() 

                os.fsync(_file.fileno()) 

            shutil.move(filepath_tmp, filepath) 

        except (IOError, EOFError, cPickle.PicklingError) as ex: 

            log.error("Unable to save %s: %s", filename, ex) 

            if os.path.isfile(filepath_bak): 

                log.info("Restoring backup of %s from: %s", filename, filepath_bak) 

                shutil.move(filepath_bak, filepath) 

 

 

def load_pickled_state_file(filename): 

    """Loads a file from the config directory, attempting backup if original fails to load. 

 

    Params: 

        filename (str): Filename to be loaded from config 

 

    Returns: 

        state: the unpickled state 

    """ 

    from deluge.configmanager import get_config_dir 

    filepath = os.path.join(get_config_dir(), "gtkui_state", filename) 

    filepath_bak = filepath + ".bak" 

    old_data_filepath = os.path.join(get_config_dir(), filename) 

 

    for _filepath in (filepath, filepath_bak, old_data_filepath): 

        log.info("Opening %s for load: %s", filename, _filepath) 

        try: 

            with open(_filepath, "rb") as _file: 

                state = cPickle.load(_file) 

        except (IOError, cPickle.UnpicklingError) as ex: 

            log.warning("Unable to load %s: %s", _filepath, ex) 

        else: 

            log.info("Successfully loaded %s: %s", filename, _filepath) 

            return state