Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extract sync decorator #261

Merged
merged 4 commits into from
Aug 15, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions activity_browser/app/ui/tables/inventory.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

from activity_browser.app.settings import project_settings
from .table import ABTableWidget, ABTableItem
from .views import ABDataFrameView
from .views import ABDataFrameView, dataframe_sync
from ..icons import icons
from ...signals import signals
from ...bwutils.metadata import AB_metadata
Expand Down Expand Up @@ -229,7 +229,7 @@ def item_double_clicked(self, proxy_index):
# for key, amount in func_unit.items():
# self.append_row(key, str(amount))

@ABDataFrameView.decorated_sync
@dataframe_sync
def sync(self, db_name, df=None):
if isinstance(df, pd.DataFrame): # skip the rest of the sync here if a dataframe is directly supplied
print('Pandas Dataframe passed to sync.', df.shape)
Expand Down
10 changes: 5 additions & 5 deletions activity_browser/app/ui/tables/lca_results.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
import numpy as np

from .views import ABDataFrameView
# from ...bwutils.commontasks import wrap_text
from .views import ABDataFrameView, dataframe_sync


class LCAResultsTable(ABDataFrameView):
@ABDataFrameView.decorated_sync
@dataframe_sync
def sync(self, df):
self.dataframe = df


class InventoryTable(ABDataFrameView):
@ABDataFrameView.decorated_sync
@dataframe_sync
def sync(self, df):
self.dataframe = df
# sort ignoring case sensitivity
Expand All @@ -24,7 +24,7 @@ def __init__(self, parent):
super(ContributionTable, self).__init__(parent)
self.parent = parent

@ABDataFrameView.decorated_sync
@dataframe_sync
def sync(self):
# df = self.parent.df.replace(np.nan, '', regex=True)
# df.columns = [wrap_text(k, max_length=20) for k in df.columns]
Expand Down
111 changes: 47 additions & 64 deletions activity_browser/app/ui/tables/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
import os
from functools import wraps

from PyQt5.QtCore import QSize, QSortFilterProxyModel, Qt, pyqtSlot
from PyQt5.QtCore import (QAbstractTableModel, QSize, QSortFilterProxyModel,
Qt, pyqtSlot)
from PyQt5.QtWidgets import QFileDialog, QTableView

from activity_browser.app.settings import ab_settings
Expand All @@ -12,6 +13,27 @@
SimpleCopyDragPandasModel, SimpleCopyPandasModel)


def dataframe_sync(sync):
""" Syncs the data from the dataframe into the table view.

Uses either of the PandasModel classes depending if the class is
'drag-enabled'.
"""
@wraps(sync)
def wrapper(self, *args, **kwargs):
sync(self, *args, **kwargs)

self.model = self._select_model()
# See: http://doc.qt.io/qt-5/qsortfilterproxymodel.html#details
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.model)
self.proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive)
self.setModel(self.proxy_model)
self._resize()

return wrapper


class ABDataFrameView(QTableView):
""" Base class for showing pandas dataframe objects as tables.
"""
Expand Down Expand Up @@ -39,29 +61,17 @@ def get_max_height(self):
def sizeHint(self):
return QSize(self.width(), self.get_max_height())

@classmethod
def decorated_sync(cls, sync):
""" Syncs the data from the dataframe into the table view.
def _select_model(self) -> QAbstractTableModel:
""" Select which model to use for the proxy model.
"""
if hasattr(self, 'drag_model'):
return DragPandasModel(self.dataframe)
return PandasModel(self.dataframe)

Uses either of the PandasModel classes depending if the class is
'drag-enabled'.
def _resize(self):
""" Custom table resizing to perform after setting new (proxy) model.
"""
@wraps(sync)
def wrapper(self, *args, **kwargs):
sync(self, *args, **kwargs)

if hasattr(self, 'drag_model'):
self.model = DragPandasModel(self.dataframe)
else:
self.model = PandasModel(self.dataframe)
# See: http://doc.qt.io/qt-5/qsortfilterproxymodel.html#details
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.model)
self.proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive)
self.setModel(self.proxy_model)
self.setMaximumHeight(self.get_max_height())

return wrapper
self.setMaximumHeight(self.get_max_height())

@staticmethod
def get_source_index(proxy_index):
Expand Down Expand Up @@ -131,49 +141,22 @@ def keyPressEvent(self, e):
class ABDataFrameSimpleCopy(ABDataFrameView):
""" A view-only class which copies values without including headers
"""
@classmethod
def decorated_sync(cls, sync):
""" Syncs the data from the dataframe into simple copy models
"""
@wraps(sync)
def wrapper(self, *args, **kwargs):
sync(self, *args, **kwargs)

if hasattr(self, 'drag_model'):
self.model = SimpleCopyDragPandasModel(self.dataframe)
else:
self.model = SimpleCopyPandasModel(self.dataframe)
self.proxy_model = QSortFilterProxyModel()
self.proxy_model.setSourceModel(self.model)
self.proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive)
self.setModel(self.proxy_model)
self.setMaximumHeight(self.get_max_height())

return wrapper
def _select_model(self) -> QAbstractTableModel:
if hasattr(self, 'drag_model'):
return SimpleCopyDragPandasModel(self.dataframe)
return SimpleCopyPandasModel(self.dataframe)


class ABDataFrameEdit(ABDataFrameView):
""" Inherit from view class but override decorated_sync to use
editable models.
""" Inherit from view class but use editable models and more flexible
sizing.
"""
@classmethod
def decorated_sync(cls, sync):
""" Syncs the data from the dataframe into editable models
"""
@wraps(sync)
def wrapper(self, *args, **kwargs):
sync(self, *args, **kwargs)

if hasattr(self, 'drag_model'):
self.model = EditableDragPandasModel(self.dataframe)
else:
self.model = EditablePandasModel(self.dataframe)
self.proxy_model = QSortFilterProxyModel() # see: http://doc.qt.io/qt-5/qsortfilterproxymodel.html#details
self.proxy_model.setSourceModel(self.model)
self.proxy_model.setSortCaseSensitivity(Qt.CaseInsensitive)
self.setModel(self.proxy_model)
self.setMaximumHeight(self.get_max_height())
self.resizeColumnsToContents()
self.resizeRowsToContents()

return wrapper
def _select_model(self) -> QAbstractTableModel:
if hasattr(self, 'drag_model'):
return EditableDragPandasModel(self.dataframe)
return EditablePandasModel(self.dataframe)

def _resize(self) -> None:
self.setMaximumHeight(self.get_max_height())
self.resizeColumnsToContents()
self.resizeRowsToContents()