Skip to content

Commit

Permalink
Have spreadsheet use FileMode subclasses
Browse files Browse the repository at this point in the history
In order to not duplicate code for spreadsheet cell dumps and FileMode
outputs, make it possible for the spreadsheet to use the output module
code when dumping cells to files.

Next step would be doing this for thumbnails.
  • Loading branch information
dakoop committed Jul 17, 2014
1 parent d4c28c1 commit cb007f8
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 52 deletions.
106 changes: 65 additions & 41 deletions vistrails/core/modules/output_modules.py
Expand Up @@ -83,6 +83,10 @@ def get_all_fields(cls):
fields.sort()
return fields

@classmethod
def get_local_fields(cls):
return sorted(cls._fields)

@classmethod
def get_default(cls, k):
f = cls.get_field(k)
Expand Down Expand Up @@ -246,6 +250,29 @@ def get_mode_tree(cls):
for c in reversed(cls_list):
c.ensure_mode_dict()

def get_mode_config(self, mode_cls):
mode_config_cls = mode_cls.config_cls
mode_config_dict = {}
configuration = self.force_get_input('configuration')
if configuration is not None:
# want to search through all mode classes in case we have
# base class settings that should trump
cls_list = [mode_config_cls]
mode_config_cls_list = []
while len(cls_list) > 0:
c = cls_list.pop(0)
if issubclass(c, OutputModeConfig):
mode_config_cls_list.append(c)
cls_list.extend(c.__bases__)
mode_config_cls_list.reverse()

for mode_config_cls in mode_config_cls_list:
for k, v in configuration.iteritems():
if k == mode_config_cls.mode_type:
mode_config_dict.update(v)
mode_config = mode_config_cls(mode_config_dict)
return mode_config

def compute(self):
mode_cls = None
self.ensure_mode_dict()
Expand All @@ -270,29 +297,8 @@ def compute(self):
raise ModuleError(self, "No output mode is valid, output cannot "
"be generated")

mode_config = self.get_mode_config(mode_cls)
mode = mode_cls()
mode_config_cls = mode_cls.config_cls
mode_config = None
mode_config_dict = {}
configuration = self.force_get_input('configuration')
if configuration is not None:
# want to search through all mode classes in case we have
# base class settings that should trump
cls_list = [mode_config_cls]
mode_config_cls_list = []
while len(cls_list) > 0:
c = cls_list.pop(0)
if issubclass(c, OutputModeConfig):
mode_config_cls_list.append(c)
cls_list.extend(c.__bases__)
mode_config_cls_list.reverse()

for mode_config_cls in mode_config_cls_list:
for k, v in configuration.iteritems():
if k == mode_config_cls.mode_type:
mode_config_dict.update(v)
mode_config = mode_config_cls(mode_config_dict)

self.annotate({"output_mode": mode.mode_type})
mode.compute_output(self, mode_config)

Expand All @@ -319,12 +325,14 @@ class FileModeConfig(OutputModeConfig):
ConfigField('series', False, bool),
ConfigField('overwrite', True, bool),
ConfigField('seriesPadding', 3, int),
ConfigField('seriesStart', 0, int)]
ConfigField('seriesStart', 0, int),
ConfigField('format', None, str)]

class FileMode(OutputMode):
mode_type = "file"
priority = 1
config_cls = FileModeConfig
formats = []

# need to reset this after each execution!
series_next = 0
Expand All @@ -333,11 +341,42 @@ class FileMode(OutputMode):
def can_compute(cls):
return True

@classmethod
def get_formats(cls):
formats = []
cls_list = [cls]
while len(cls_list) > 0:
c = cls_list.pop(0)
if issubclass(c, FileMode):
if 'formats' in c.__dict__:
return c.formats
cls_list.extend(c.__bases__)
return []

def get_format(self, configuration=None):
format_map = {'png': 'png',
'jpeg': 'jpg',
'jpg': 'jpg',
'tif': 'tif',
'tiff': 'tif'}
if configuration is not None and 'format' in configuration:
conf_format = configuration['format']
if conf_format.lower() in format_map:
return format_map[conf_format.lower()]
return conf_format

# default is the first listed if it exists
format_list = self.get_formats()
if len(format_list) > 0:
return format_list[0]
return None

def get_series_num(self):
retval = FileMode.series_next
FileMode.series_next += 1
return retval


# FIXME should add format into this computation
def get_filename(self, configuration, full_path=None, filename=None,
dirname=None, basename=None, prefix=None, suffix=None,
overwrite=True, series=False, series_padding=3):
Expand Down Expand Up @@ -462,33 +501,19 @@ class FileOutput(OutputModule):
class ImageFileModeConfig(FileModeConfig):
mode_type = "imageFile"
_fields = [ConfigField('width', 800, int),
ConfigField('height', 600, int),
ConfigField('format', None, str)]
ConfigField('height', 600, int)]

class ImageFileMode(FileMode):
config_cls = ImageFileModeConfig
mode_type = "imageFile"

def get_format(self, configuration=None):
format_map = {'png': 'png',
'jpeg': 'jpg',
'jpg': 'jpg',
'tif': 'tif',
'tiff': 'tif'}
if configuration is not None:
img_format = configuration['format']
if img_format.lower() in format_map:
return format_map[img_format.lower()]
return img_format
return 'png'

class RichTextOutput(OutputModule):
# need specific spreadsheet richtext mode here
pass

_modules = [OutputModule, GenericOutput, FileOutput]

# need to put WebOutput, ImageOutput, RichTextOutput, SVGOutput, VTKOutput, MplOutput, etc. elsewhere
# need to put WebOutput, ImageOutput, RichTextOutput, SVGOutput, etc. elsewhere

class TestOutputModeConfig(unittest.TestCase):
def test_fields(self):
Expand Down Expand Up @@ -519,7 +544,6 @@ def test_get_item(self):

def test_get_default(self):
self.assertEqual(FileModeConfig.get_default("seriesStart"), 0)


if __name__ == '__main__':
import vistrails.core.application
Expand Down
1 change: 1 addition & 0 deletions vistrails/packages/matplotlib/bases.py
Expand Up @@ -174,6 +174,7 @@ class MplQuadContourSet(MplContourSet):

class MplFigureToFile(ImageFileMode):
config_cls = ImageFileModeConfig
formats = ['pdf', 'png', 'jpg']

def compute_output(self, output_module, configuration=None):
value = output_module.get_input('value')
Expand Down
5 changes: 4 additions & 1 deletion vistrails/packages/spreadsheet/basic_widgets.py
Expand Up @@ -310,7 +310,10 @@ def display_and_wait(self, output_module, configuration, cell_type,
spreadsheetWindow = spreadsheetController.findSpreadsheetWindow()
if spreadsheetWindow.echoMode == False:
spreadsheetWindow.configShow(show=True)
return spreadsheetWindow.displayCellEvent(e)
cell = spreadsheetWindow.displayCellEvent(e)
if cell is not None:
cell.set_output_module(output_module, configuration)
return cell


class SingleCellSheetReference(SheetReference):
Expand Down
78 changes: 68 additions & 10 deletions vistrails/packages/spreadsheet/spreadsheet_cell.py
Expand Up @@ -49,6 +49,7 @@
import analogy_api
from spreadsheet_config import configuration
from vistrails.core.system import strftime
from vistrails.core.modules.output_modules import FileMode

################################################################################

Expand Down Expand Up @@ -79,6 +80,8 @@ def __init__(self, parent=None, flags=QtCore.Qt.WindowFlags()):
# cell can be captured if it re-implements saveToPNG
self._capturingEnabled = (not isinstance(self, QCellWidget) and
hasattr(self, 'saveToPNG'))
self._output_module = None
self._output_configuration = None
self.connect(self._playerTimer,
QtCore.SIGNAL('timeout()'),
self.playNextFrame)
Expand Down Expand Up @@ -250,6 +253,40 @@ def saveToPDF(self, filename):
painter.drawPixmap(0, 0, pixmap)
painter.end()

def set_output_module(self, output_module, configuration=None):
self._output_module = output_module
self._output_configuration = configuration

def has_file_output_mode(self):
# from vistrails.core.modules.output_modules import FileMode
if self._output_module is None:
return False
for mode in self._output_module.get_sorted_mode_list():
if issubclass(mode, FileMode):
return True
return False

def get_file_output_modes(self):
modes = []
if self._output_module is not None:
for mode_cls in self._output_module.get_sorted_mode_list():
if issubclass(mode_cls, FileMode):
modes.append(mode_cls)
return modes

def get_conf_file_format(self):
if (self._output_configuration is not None and
'format' in self._output_configuration):
return self._output_configuration['format']
return None

def save_via_file_output(self, filename, mode_cls, save_format=None):
mode_config = self._output_module.get_mode_config(mode_cls)
mode_config['file'] = filename
if save_format is not None:
mode_config['format'] = save_format
mode = mode_cls()
mode.compute_output(self._output_module, mode_config)

################################################################################

Expand Down Expand Up @@ -300,16 +337,37 @@ def addSaveCellAction(self):

def exportCell(self, checked=False):
cell = self.sheet.getCell(self.row, self.col)
if not cell.save_formats:
QtGui.QMessageBox.information(
self, "Export cell",
"This cell type doesn't provide any export option")
return
filename = QtGui.QFileDialog.getSaveFileName(
self, "Select a File to Export the Cell",
".", ';;'.join(cell.save_formats))
if filename:
cell.dumpToFile(filename)
if cell.has_file_output_mode():
modes = cell.get_file_output_modes()
formats = []
format_map = {}
for mode in modes:
for m_format in mode.get_formats():
if m_format not in format_map:
formats.append(m_format)
format_map[m_format] = mode
selected_filter = None
if cell.get_conf_file_format() is not None:
selected_filter = '(*.%s)' % cell.get_conf_file_format()
(filename, save_format) = \
QtGui.QFileDialog.getSaveFileNameAndFilter(
self, "Select a File to Export the Cell",
".", ';;'.join(['(*.%s)' % f for f in formats]),
selected_filter)
if filename:
save_mode = format_map[save_format[3:-1]]
cell.save_via_file_output(filename, save_mode)
else:
if not cell.save_formats:
QtGui.QMessageBox.information(
self, "Export cell",
"This cell type doesn't provide any export option")
return
filename = QtGui.QFileDialog.getSaveFileName(
self, "Select a File to Export the Cell",
".", ';;'.join(cell.save_formats))
if filename:
cell.dumpToFile(filename)

def createToolBar(self):
""" createToolBar() -> None
Expand Down
1 change: 1 addition & 0 deletions vistrails/packages/tabledata/common.py
Expand Up @@ -272,6 +272,7 @@ def compute(self):
['converted_list'])) # names

class TableToFileMode(FileMode):
formats = ['html']
def write_html(self, table):
document = ['<!DOCTYPE html>\n'
'<html>\n <head>\n'
Expand Down
1 change: 1 addition & 0 deletions vistrails/packages/vtk/base_module.py
Expand Up @@ -266,6 +266,7 @@ def ProgressEvent(obj, event):

class vtkRendererToFile(ImageFileMode):
config_cls = ImageFileModeConfig
formats = ['png', 'jpg', 'tif', 'pnm']

@classmethod
def can_compute(cls):
Expand Down

0 comments on commit cb007f8

Please sign in to comment.