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

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

360

361

362

363

364

365

366

367

368

369

370

371

372

373

374

375

376

377

378

379

380

381

382

383

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

478

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

518

519

520

521

522

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

542

543

544

545

546

547

548

549

550

551

552

553

554

555

556

557

558

559

560

561

562

563

564

565

566

567

568

569

570

571

572

573

574

575

576

577

578

579

580

581

582

583

584

585

586

587

588

589

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

629

630

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

# 

# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@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. 

# 

 

import logging 

 

import gtk 

import pygtk 

from gobject import SIGNAL_RUN_LAST, TYPE_NONE, signal_new 

 

from deluge.ui.gtkui.common import load_pickled_state_file, save_pickled_state_file 

 

pygtk.require('2.0') 

 

 

signal_new('button-press-event', gtk.TreeViewColumn, SIGNAL_RUN_LAST, TYPE_NONE, (gtk.gdk.Event,)) 

 

log = logging.getLogger(__name__) 

 

 

class ListViewColumnState: 

    """Used for saving/loading column state""" 

    def __init__(self, name, position, width, visible, sort, sort_order): 

        self.name = name 

        self.position = position 

        self.width = width 

        self.visible = visible 

        self.sort = sort 

        self.sort_order = sort_order 

 

 

class ListView: 

    """ListView is used to make custom GtkTreeViews.  It supports the adding 

    and removing of columns, creating a menu for a column toggle list and 

    support for 'status_field's which are used while updating the columns data. 

    """ 

 

    class ListViewColumn: 

        """Holds information regarding a column in the ListView""" 

        def __init__(self, name, column_indices): 

            # Name is how a column is identified and is also the header 

            self.name = name 

            # Column_indices holds the indexes to the liststore_columns that 

            # this column utilizes. It is stored as a list. 

            self.column_indices = column_indices 

            # Column is a reference to the GtkTreeViewColumn object 

            self.column = None 

            # This is the name of the status field that the column will query 

            # the core for if an update is called. 

            self.status_field = None 

            # If column is 'hidden' then it will not be visible and will not 

            # show up in any menu listing;  it cannot be shown ever. 

            self.hidden = False 

            # If this is set, it is used to sort the model 

            self.sort_func = None 

            self.sort_id = None 

 

    class TreeviewColumn(gtk.TreeViewColumn, object): 

        """ 

            TreeViewColumn does not signal right-click events, and we need them 

            This subclass is equivalent to TreeViewColumn, but it signals these events 

 

            Most of the code of this class comes from Quod Libet (http://www.sacredchao.net/quodlibet) 

        """ 

 

        def __init__(self, title=None, cell_renderer=None, ** args): 

            """ Constructor, see gtk.TreeViewColumn """ 

            gtk.TreeViewColumn.__init__(self, title, cell_renderer, ** args) 

            label = gtk.Label(title) 

            self.set_widget(label) 

            label.show() 

            label.__realize = label.connect('realize', self.on_realize) 

            self.title = title 

            self.data_func = None 

            self.data_func_data = None 

            self.cell_renderer = None 

 

        def on_realize(self, widget): 

            widget.disconnect(widget.__realize) 

            del widget.__realize 

            button = widget.get_ancestor(gtk.Button) 

            if button is not None: 

                button.connect('button-press-event', self.on_button_pressed) 

 

        def on_button_pressed(self, widget, event): 

            self.emit('button-press-event', event) 

 

        def set_cell_data_func_attributes(self, cell_renderer, func, func_data=None): 

            """Store the values to be set by set_cell_data_func""" 

            self.data_func = func 

            self.data_func_data = func_data 

            self.cell_renderer = cell_renderer 

 

        def set_visible(self, visible): 

            gtk.TreeViewColumn.set_visible(self, visible) 

            if self.data_func: 

                if not visible: 

                    # Set data function to None to prevent unecessary calls when column is hidden 

                    self.set_cell_data_func(self.cell_renderer, None, func_data=None) 

                else: 

                    self.set_cell_data_func(self.cell_renderer, self.data_func, self.data_func_data) 

 

    def __init__(self, treeview_widget=None, state_file=None): 

        log.debug("ListView initialized..") 

 

        if treeview_widget is not None: 

            # User supplied a treeview widget 

            self.treeview = treeview_widget 

        else: 

            self.treeview = gtk.TreeView() 

 

        self.treeview.set_enable_search(True) 

        self.treeview.set_search_equal_func(self.on_keypress_search_by_name) 

 

        if state_file: 

            self.load_state(state_file) 

 

        self.liststore = None 

        self.model_filter = None 

 

        self.treeview.set_rules_hint(True) 

        self.treeview.set_reorderable(False) 

        self.treeview.get_selection().set_mode(gtk.SELECTION_MULTIPLE) 

 

        # Dictionary of 'header' or 'name' to ListViewColumn object 

        self.columns = {} 

        # Column_index keeps track of the order of the visible columns. 

        self.column_index = [] 

        # The column types for the list store.. this may have more entries than 

        # visible columns due to some columns utilizing more than 1 liststore 

        # column and some columns being hidden. 

        self.liststore_columns = [] 

        # The GtkMenu that is created after every addition, removal or reorder 

        self.menu = None 

        # A list of menus that self.menu will be a submenu of everytime it is 

        # created. 

        self.checklist_menus = [] 

 

        # Store removed columns state.  This is needed for plugins that remove 

        # their columns prior to having the state list saved on shutdown. 

        self.removed_columns_state = [] 

 

        # Since gtk TreeModelSort doesn't do stable sort, remember last sort order so we can 

        self.last_sort_order = {} 

        self.unique_column_id = None 

        self.default_sort_column_id = None 

 

        # Create the model filter and column 

        self.add_bool_column("filter", hidden=True) 

 

    def create_model_filter(self): 

        """create new filter-model 

        must be called after listview.create_new_liststore 

        """ 

        model_filter = self.liststore.filter_new() 

        model_filter.set_visible_column( 

            self.columns["filter"].column_indices[0]) 

        self.model_filter = gtk.TreeModelSort(model_filter) 

        self.model_filter.connect("sort-column-changed", self.on_model_sort_changed) 

        self.model_filter.connect("row-inserted", self.on_model_row_inserted) 

        self.treeview.set_model(self.model_filter) 

        self.set_sort_functions() 

        self.set_model_sort() 

 

    def set_model_sort(self): 

        column_state = self.get_sort_column_from_state() 

        if column_state: 

            self.treeview.get_model().set_sort_column_id(column_state.sort, column_state.sort_order) 

        # Using the default sort column 

        elif self.default_sort_column_id: 

            self.model_filter.set_sort_column_id(self.default_sort_column_id, gtk.SORT_ASCENDING) 

        self.model_filter.set_default_sort_func(None) 

 

    def get_sort_column_from_state(self): 

        """Find the first (should only be one) state with sort enabled""" 

        if self.state is None: 

            return None 

        for column_state in self.state: 

            if column_state.sort is not None and column_state.sort > -1: 

                return column_state 

        return None 

 

    def on_model_sort_changed(self, model): 

        if self.unique_column_id: 

            self.last_sort_order = {} 

 

            def record_position(model, path, iter, data): 

                self.last_sort_order[model[iter][self.unique_column_id]] = path[0] 

            model.foreach(record_position, None) 

 

    def on_model_row_inserted(self, model, path, iter): 

        if self.unique_column_id: 

            self.last_sort_order.setdefault( 

                model[iter][self.unique_column_id], len(model) - 1) 

 

    def stabilize_sort_func(self, sort_func): 

        def stabilized(model, iter1, iter2, data): 

            result = sort_func(model, iter1, iter2, data) 

            if result == 0 and self.unique_column_id: 

                unique1 = model[iter1][self.unique_column_id] 

                unique2 = model[iter2][self.unique_column_id] 

                if unique1 in self.last_sort_order and unique2 in self.last_sort_order: 

                    result = cmp(self.last_sort_order[unique1], 

                                 self.last_sort_order[unique2]) 

                # If all else fails, fall back to sorting by unique column 

                if result == 0: 

                    result = cmp(unique1, unique2) 

 

            return result 

        return stabilized 

 

    def generic_sort_func(self, model, iter1, iter2, data): 

        return cmp(model[iter1][data], model[iter2][data]) 

 

    def set_sort_functions(self): 

        for column in self.columns.values(): 

            sort_func = column.sort_func or self.generic_sort_func 

            self.model_filter.set_sort_func( 

                column.sort_id, 

                self.stabilize_sort_func(sort_func), 

                column.sort_id) 

 

    def create_column_state(self, column, position=None): 

        if not position: 

            # Find the position 

            for index, c in enumerate(self.treeview.get_columns()): 

                if column.get_title() == c.get_title(): 

                    position = index 

                    break 

        sort = None 

        if self.model_filter: 

            sort_id, order = self.model_filter.get_sort_column_id() 

            if self.get_column_name(sort_id) == column.get_title(): 

                sort = sort_id 

 

        return ListViewColumnState(column.get_title(), position, column.get_width(), 

                                   column.get_visible(), sort, int(column.get_sort_order())) 

 

    def save_state(self, filename): 

        """Saves the listview state (column positions and visibility) to 

            filename.""" 

        # A list of ListViewColumnStates 

        state = [] 

 

        # Workaround for all zero widths after removing column on shutdown 

        if not any(c.get_width() for c in self.treeview.get_columns()): 

            return 

 

        # Get the list of TreeViewColumns from the TreeView 

        for counter, column in enumerate(self.treeview.get_columns()): 

            # Append a new column state to the state list 

            state.append(self.create_column_state(column, counter)) 

 

        state += self.removed_columns_state 

 

        self.state = state 

        save_pickled_state_file(filename, state) 

 

    def load_state(self, filename): 

        """Load the listview state from filename.""" 

        self.state = load_pickled_state_file(filename) 

 

    def set_treeview(self, treeview_widget): 

        """Set the treeview widget that this listview uses.""" 

        self.treeview = treeview_widget 

        self.treeview.set_model(self.liststore) 

        return 

 

    def get_column_index(self, name): 

        """Get the liststore column indices belonging to this column. 

        Will return a list. 

        """ 

        return self.columns[name].column_indices 

 

    def get_column_name(self, index): 

        """Get the header name for a liststore column index""" 

        for key, value in self.columns.items(): 

            if index in value.column_indices: 

                return key 

 

    def get_state_field_column(self, field): 

        """Returns the column number for the state field""" 

        for column in self.columns.keys(): 

            if self.columns[column].status_field is None: 

                continue 

 

            for f in self.columns[column].status_field: 

                if field == f: 

                    return self.columns[column].column_indices[ 

                        self.columns[column].status_field.index(f)] 

 

    def on_menuitem_toggled(self, widget): 

        """Callback for the generated column menuitems.""" 

        # Get the column name from the widget 

        name = widget.get_child().get_text() 

 

        # Set the column's visibility based on the widgets active state 

        try: 

            self.columns[name].column.set_visible(widget.get_active()) 

        except KeyError: 

            self.columns[unicode(name)].column.set_visible(widget.get_active()) 

        return 

 

    def on_treeview_header_right_clicked(self, column, event): 

        if event.button == 3: 

            self.menu.popup(None, None, None, event.button, event.get_time()) 

 

    def register_checklist_menu(self, menu): 

        """Register a checklist menu with the listview.  It will automatically 

        attach any new checklist menu it makes to this menu. 

        """ 

        self.checklist_menus.append(menu) 

 

    def create_checklist_menu(self): 

        """Creates a menu used for toggling the display of columns.""" 

        menu = self.menu = gtk.Menu() 

        # Iterate through the column_index list to preserve order 

        for name in self.column_index: 

            column = self.columns[name] 

            # If the column is hidden, then we do not want to show it in the 

            # menu. 

            if column.hidden is True: 

                continue 

            menuitem = gtk.CheckMenuItem(column.name) 

            # If the column is currently visible, make sure it's set active 

            # (or checked) in the menu. 

            if column.column.get_visible() is True: 

                menuitem.set_active(True) 

            # Connect to the 'toggled' event 

            menuitem.connect("toggled", self.on_menuitem_toggled) 

            # Add the new checkmenuitem to the menu 

            menu.append(menuitem) 

 

        # Attach this new menu to all the checklist_menus 

        for _menu in self.checklist_menus: 

            _menu.set_submenu(menu) 

            _menu.show_all() 

        return menu 

 

    def create_new_liststore(self): 

        """Creates a new GtkListStore based on the liststore_columns list""" 

        # Create a new liststore with added column and move the data from the 

        # old one to the new one. 

        new_list = gtk.ListStore(*tuple(self.liststore_columns)) 

 

        # This function is used in the liststore.foreach method with user_data 

        # being the new liststore and the columns list 

        def copy_row(model, path, row, user_data): 

            new_list, columns = user_data 

            new_row = new_list.append() 

            for column in range(len(columns)): 

                # Get the current value of the column for this row 

                value = model.get_value(row, column) 

                # Set the value of this row and column in the new liststore 

                new_list.set_value(new_row, column, value) 

 

        # Do the actual row copy 

        if self.liststore is not None: 

            self.liststore.foreach(copy_row, (new_list, self.columns)) 

 

        self.liststore = new_list 

 

    def remove_column(self, header): 

        """Removes the column with the name 'header' from the listview""" 

        # Store a copy of this columns state in case it's re-added 

        state = self.create_column_state(self.columns[header].column) 

        self.removed_columns_state.append(state) 

 

        # Start by removing this column from the treeview 

        self.treeview.remove_column(self.columns[header].column) 

        # Get the column indices 

        column_indices = self.columns[header].column_indices 

        # Delete the column 

        del self.columns[header] 

        self.column_index.remove(header) 

        # Shift the column_indices values of those columns effected by the 

        # removal.  Any column_indices > the one removed. 

        for column in self.columns.values(): 

            if column.column_indices[0] > column_indices[0]: 

                # We need to shift this column_indices 

                for index in column.column_indices: 

                    index = index - len(column_indices) 

 

        # Remove from the liststore columns list 

        for index in column_indices: 

            del self.liststore_columns[index] 

 

        # Create a new liststore 

        self.create_new_liststore() 

        # Create new model for the treeview 

        self.create_model_filter() 

 

        # Re-create the menu 

        self.create_checklist_menu() 

        return 

 

    def add_column(self, header, render, col_types, hidden, position, 

                   status_field, sortid, text=0, value=0, pixbuf=0, function=None, 

                   column_type=None, sort_func=None, tooltip=None, default=True, 

                   unique=False, default_sort=False): 

        """Adds a column to the ListView""" 

        # Add the column types to liststore_columns 

        column_indices = [] 

        if type(col_types) is list: 

            for col_type in col_types: 

                self.liststore_columns.append(col_type) 

                column_indices.append(len(self.liststore_columns) - 1) 

        else: 

            self.liststore_columns.append(col_types) 

            column_indices.append(len(self.liststore_columns) - 1) 

 

        # Add to the index list so we know the order of the visible columns. 

        if position is not None: 

            self.column_index.insert(position, header) 

        else: 

            self.column_index.append(header) 

 

        # Create a new column object and add it to the list 

        self.columns[header] = self.ListViewColumn(header, column_indices) 

 

        self.columns[header].status_field = status_field 

        self.columns[header].sort_func = sort_func 

        self.columns[header].sort_id = column_indices[sortid] 

 

        if unique: 

            self.unique_column_id = column_indices[sortid] 

        if default_sort: 

            self.default_sort_column_id = column_indices[sortid] 

 

        # Create a new list with the added column 

        self.create_new_liststore() 

 

        # Happens only on columns added after the torrent list has been loaded 

        if self.model_filter: 

            self.create_model_filter() 

 

        column = self.TreeviewColumn(header) 

 

        if column_type == "text": 

            column.pack_start(render) 

            column.add_attribute(render, "text", self.columns[header].column_indices[text]) 

        elif column_type == "bool": 

            column.pack_start(render) 

            column.add_attribute(render, "active", self.columns[header].column_indices[0]) 

        elif column_type == "func": 

            column.pack_start(render, True) 

            if len(self.columns[header].column_indices) > 1: 

                column.set_cell_data_func_attributes(render, function, tuple(self.columns[header].column_indices)) 

            else: 

                column.set_cell_data_func_attributes(render, function, self.columns[header].column_indices[0]) 

        elif column_type == "progress": 

            column.pack_start(render) 

            if function is None: 

                column.add_attribute(render, "text", self.columns[header].column_indices[text]) 

                column.add_attribute(render, "value", self.columns[header].column_indices[value]) 

            else: 

                column.set_cell_data_func_attributes(render, function, tuple(self.columns[header].column_indices)) 

        elif column_type == "texticon": 

            column.pack_start(render[pixbuf], False) 

            if function is not None: 

                column.set_cell_data_func_attributes(render[pixbuf], function, 

                                                     self.columns[header].column_indices[pixbuf]) 

            column.pack_start(render[text], True) 

            column.add_attribute(render[text], "text", self.columns[header].column_indices[text]) 

        elif column_type is None: 

            return 

 

        column.set_sort_column_id(self.columns[header].column_indices[sortid]) 

        column.set_clickable(True) 

        column.set_resizable(True) 

        column.set_expand(False) 

        column.set_min_width(10) 

        column.set_reorderable(True) 

        column.set_visible(not hidden) 

        column.connect('button-press-event', 

                       self.on_treeview_header_right_clicked) 

 

        if tooltip: 

            column.get_widget().set_tooltip_markup(tooltip) 

 

        # Check for loaded state and apply 

        column_in_state = False 

        if self.state is not None: 

            for column_state in self.state: 

                if header == column_state.name: 

                    # We found a loaded state 

                    column_in_state = True 

                    if column_state.width > 0: 

                        column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) 

                        column.set_fixed_width(column_state.width) 

 

                    column.set_visible(column_state.visible) 

                    position = column_state.position 

                    break 

 

        # Set this column to not visible if its not in the state and 

        # its not supposed to be shown by default 

        if not column_in_state and not default and not hidden: 

            column.set_visible(False) 

 

        if position is not None: 

            self.treeview.insert_column(column, position) 

        else: 

            self.treeview.append_column(column) 

 

        # Set hidden in the column 

        self.columns[header].hidden = hidden 

        self.columns[header].column = column 

        # Re-create the menu item because of the new column 

        self.create_checklist_menu() 

 

        return True 

 

    def add_text_column(self, header, col_type=str, hidden=False, position=None, 

                        status_field=None, sortid=0, column_type="text", 

                        sort_func=None, tooltip=None, default=True, unique=False, 

                        default_sort=False): 

        """Add a text column to the listview.  Only the header name is required. 

        """ 

        render = gtk.CellRendererText() 

        self.add_column(header, render, col_type, hidden, position, 

                        status_field, sortid, column_type=column_type, 

                        sort_func=sort_func, tooltip=tooltip, default=default, 

                        unique=unique, default_sort=default_sort) 

 

        return True 

 

    def add_bool_column(self, header, col_type=bool, hidden=False, 

                        position=None, status_field=None, sortid=0, 

                        column_type="bool", tooltip=None, default=True): 

 

        """Add a bool column to the listview""" 

        render = gtk.CellRendererToggle() 

        self.add_column(header, render, col_type, hidden, position, 

                        status_field, sortid, column_type=column_type, 

                        tooltip=tooltip, default=default) 

 

    def add_func_column(self, header, function, col_types, sortid=0, 

                        hidden=False, position=None, status_field=None, 

                        column_type="func", sort_func=None, tooltip=None, default=True): 

        """Add a function column to the listview.  Need a header name, the 

        function and the column types.""" 

 

        render = gtk.CellRendererText() 

        self.add_column(header, render, col_types, hidden, position, 

                        status_field, sortid, column_type=column_type, 

                        function=function, sort_func=sort_func, tooltip=tooltip, default=default) 

 

        return True 

 

    def add_progress_column(self, header, col_types=[float, str], sortid=0, 

                            hidden=False, position=None, status_field=None, 

                            function=None, column_type="progress", 

                            tooltip=None, default=True): 

        """Add a progress column to the listview.""" 

 

        render = gtk.CellRendererProgress() 

        self.add_column(header, render, col_types, hidden, position, 

                        status_field, sortid, function=function, 

                        column_type=column_type, value=0, text=1, 

                        tooltip=tooltip, default=default) 

 

        return True 

 

    def add_texticon_column(self, header, col_types=[str, str], sortid=1, 

                            hidden=False, position=None, status_field=None, 

                            column_type="texticon", function=None, 

                            tooltip=None, default=True, default_sort=False): 

        """Adds a texticon column to the listview.""" 

        render1 = gtk.CellRendererPixbuf() 

        render2 = gtk.CellRendererText() 

 

        self.add_column(header, (render1, render2), col_types, hidden, position, 

                        status_field, sortid, column_type=column_type, 

                        function=function, pixbuf=0, text=1, tooltip=tooltip, 

                        default=default, default_sort=default_sort) 

 

        return True 

 

    def on_keypress_search_by_name(self, model, column, key, iter): 

        torrent_name_col = self.columns["Name"].column_indices[1] 

        return not model[iter][torrent_name_col].lower().startswith(key.lower()) 

 

    def restore_columns_order_from_state(self): 

        if self.state is None: 

            # No state file exists, so, no reordering can be done 

            return 

        columns = self.treeview.get_columns() 

 

        def find_column(header): 

            for column in columns: 

                if column.get_title() == header: 

                    return column 

 

        restored_columns = [] 

        for col_state in self.state: 

            if col_state.name in restored_columns: 

                # Duplicate column in state!?!?!? 

                continue 

            elif not col_state.visible: 

                # Column is not visible, no need to reposition 

                continue 

 

            try: 

                column_at_position = columns[col_state.position] 

            except IndexError: 

                # Ignore extra columns from Plugins in col_state 

                continue 

            if col_state.name == column_at_position.get_title(): 

                # It's in the right position 

                continue 

            column = find_column(col_state.name) 

            if not column: 

                log.debug("Could not find column matching \"%s\" on state." % 

                          col_state.name) 

                # The cases where I've found that the column could not be found 

                # is when not using the english locale, ie, the default one, or 

                # when changing locales between runs. 

                # On the next load, all should be fine 

                continue 

            self.treeview.move_column_after(column, column_at_position) 

            # Get columns again to keep reordering since positions have changed 

            columns = self.treeview.get_columns() 

            restored_columns.append(col_state.name) 

        self.create_new_liststore()