Skip to content

Commit

Permalink
Merge pull request #87 from nowsecure/conversation_view_report
Browse files Browse the repository at this point in the history
Update view when data_source changes
  • Loading branch information
bellini666 committed Aug 20, 2015
2 parents be3976c + 384748d commit affecd6
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 1 deletion.
9 changes: 8 additions & 1 deletion datagrid_gtk3/db/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
"""

from gi.repository import GObject


class Node(list):

Expand Down Expand Up @@ -40,7 +42,7 @@ def is_children_loaded(self, recursive=False):
return loaded


class DataSource(object):
class DataSource(GObject.GObject):
"""Base class for data sources."""

ID_COLUMN = 'rowid'
Expand All @@ -50,6 +52,7 @@ class DataSource(object):
FLAT_COLUMN = None

def __init__(self):
super(DataSource, self).__init__()
self.columns = []
self.total_recs = 0
self.display_all = True
Expand Down Expand Up @@ -80,3 +83,7 @@ def update(self, params, ids=None):

class EmptyDataSource(DataSource):
"""Data source that can be used when an empty data grid is required."""

__gsignals__ = {
'rows-changed': (GObject.SignalFlags.RUN_LAST, None, (object, object)),
}
26 changes: 26 additions & 0 deletions datagrid_gtk3/db/sqlite.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
import operator
import sqlite3
import struct
import weakref
from contextlib import closing

from gi.repository import GObject
from sqlalchemy import (
Column,
INTEGER,
Expand Down Expand Up @@ -75,6 +77,12 @@ class SQLiteDataSource(DataSource):
the columns visibility in the database.
"""

__gsignals__ = {
'rows-changed': (GObject.SignalFlags.RUN_LAST, None, (object, object)),
}

_DBS = weakref.WeakSet()

MAX_RECS = 100
SQLITE_PY_TYPES = {
'INT': long,
Expand Down Expand Up @@ -116,6 +124,9 @@ def __init__(self, db_file, table=None, update_table=None, config=None,
self.update_table = table
self.config = config
self.columns = self.get_columns()
self.columns_idx = {
col['name']: i for i, col in enumerate(self.columns)}

for col in self.columns:
self.table.append_column(column(col['name']))

Expand Down Expand Up @@ -143,6 +154,8 @@ def __init__(self, db_file, table=None, update_table=None, config=None,
'RENAME TO __visible_columns')
conn.commit()

self.__class__._DBS.add(self)

###
# Public
###
Expand Down Expand Up @@ -269,6 +282,19 @@ def update(self, params, ids=None):
cursor.execute(sql)
conn.commit()

# Emit rows-changed for any other databases connected to the same
# database and table. This is to allow any view using them
# to update themselves with the changes done here.
# The current object will not emit the event as it is the one who
# made the update and thus, is assumed to know about the changes
for db in self.__class__._DBS:
if db is self:
continue
if (db.db_file, db.table.name) != (self.db_file, self.table.name):
continue

db.emit('rows-changed', params, ids)

def get_all_record_ids(self, params=None):
"""Get all the record primary keys for given params.
Expand Down
42 changes: 42 additions & 0 deletions datagrid_gtk3/ui/grid.py
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,7 @@ def bind_datasource(self, data_source):
widget.show()

self._refresh_view()
data_source.connect('rows-changed', self.on_data_source_rows_changed)

def add_options_filter(self, attr, options, add_empty_option=True):
"""Add optional options filter for attr.
Expand Down Expand Up @@ -823,6 +824,39 @@ def on_filter_changed(self, combo, attr):

self._refresh_view(update_dict=update_dict, remove_keys=remove_keys)

def on_data_source_rows_changed(self, data_source, params, ids):
"""Handle data_source rows-changed signal.
When a row gets updated on data source, make sure to reflect
them on the view, without requiring to do an extra query for that.
:param data_source: The data source which emitted the signal
:type data_source: `datagrid_gtk3.db.DataSource`
:param params: A dict of params that got updated, mapped as
``column_name: new_value``
:type params: dict
:param ids: The row ids that got updated
:type ids: [int]
"""
params_idx = [
(self.model.data_source.columns_idx[k], v)
for k, v in params.iteritems()]
rows = (row
for id_, row in self.model.row_id_mapper.iteritems()
if ids is None or id_ in ids)

for row in rows:
for idx, value in params_idx:
row.data[idx] = value

path = Gtk.TreePath(row.path)
self.model.row_changed(path, self.model.get_iter(row.path))
# Even if we call `view.queue_draw` here, it would only be updated
# when it got focused. By setting refresh_draw to True, it will
# force it to refresh the values when the view gets visible on the
# screen, even if it is not focused atm.
self.view.refresh_draw = True

def on_data_loaded(self, model, total_recs):
"""Update the total records label.
Expand Down Expand Up @@ -1012,6 +1046,7 @@ def __init__(self, model, **kwargs):
self._all_expanded = False
self._block_all_expanded = False

self.refresh_draw = False
self._block_draw = False

###
Expand All @@ -1037,6 +1072,9 @@ def do_draw(self, cr):
"""
if self._block_draw:
return
if self.refresh_draw:
GObject.idle_add(self.queue_draw)
self.refresh_draw = False
return Gtk.TreeView.do_draw(self, cr)

def refresh(self):
Expand Down Expand Up @@ -1480,6 +1518,7 @@ def __init__(self, model, **kwargs):
self.connect('button-release-event', self.on_button_release_event)
self.connect('key-press-event', self.on_key_press_event)

self.refresh_draw = False
self._block_draw = False

###
Expand All @@ -1505,6 +1544,9 @@ def do_draw(self, cr):
"""
if self._block_draw:
return
if self.refresh_draw:
GObject.idle_add(self.queue_draw)
self.refresh_draw = False
return Gtk.IconView.do_draw(self, cr)

def refresh(self):
Expand Down

0 comments on commit affecd6

Please sign in to comment.