Skip to content

Commit

Permalink
merge news
Browse files Browse the repository at this point in the history
  • Loading branch information
erikjanss committed Jul 31, 2012
2 parents f76b2c8 + 711aee3 commit 0da4526
Show file tree
Hide file tree
Showing 29 changed files with 386 additions and 159 deletions.
2 changes: 1 addition & 1 deletion camelot/__init__.py
Expand Up @@ -26,7 +26,7 @@
the Django admin interface. Start building applications at warp speed, simply
by adding some additional information to you Elixir model."""

__version__ = 'master'
__version__ = '12.06.29'



8 changes: 0 additions & 8 deletions camelot/bin/camelot_admin.py
Expand Up @@ -43,9 +43,6 @@
command_description = [
('startproject', """Starts a new project, use startproject project_name.
"""),
('makemessages', """Outputs a message file with all field names of all
entities. This command requires settings.py of the project to be in the
PYTHONPATH"""),
('apidoc', """Extract API documentation from source code, to be used
with sphinx.
"""),
Expand Down Expand Up @@ -231,11 +228,6 @@ def startproject(module):
action = CreateNewProject()
action.start_project( options )

def makemessages():
from camelot.core.conf import settings
LOGGER.error( 'Not yet implemented' )
settings.setup_model()

def meta():
"""launch meta camelot, in a separate function to make sure camelot_admin
does not depend on PyQt, otherwise it is imposible to run to_pyside without
Expand Down
7 changes: 6 additions & 1 deletion camelot/core/orm.py
Expand Up @@ -98,7 +98,7 @@ class ClassMutator( object ):
def __init__( self, *args, **kwargs ):
# jam this mutator into the class's mutator list
class_locals = sys._getframe(1).f_locals
mutators = class_locals.setdefault(MUTATORS, [])
mutators = class_locals.setdefault( MUTATORS, [] )
mutators.append( (self, args, kwargs) )

def process( self, entity_dict, *args, **kwargs ):
Expand Down Expand Up @@ -288,6 +288,11 @@ def process( self, entity_dict, tablename = None, order_by = None ):
if order_by:
mapper_args = entity_dict.get('__mapper_args__', {} )
mapper_args['order_by'] = order_by

class has_field( ClassMutator ):

def process( self, entity_dict, name, *args, **kwargs ):
entity_dict[ name ] = Field( *args, **kwargs )

class EntityMeta( DeclarativeMeta ):
"""Subclass of :class:`sqlalchmey.ext.declarative.DeclarativeMeta`. This
Expand Down
7 changes: 7 additions & 0 deletions camelot/core/utils.py
Expand Up @@ -54,6 +54,13 @@ def is_deleted_pyside( qobj ):
else:
pyqt = False
is_deleted = is_deleted_pyside
# try to activate the PySide backend of matplotlib
# http://www.scipy.org/Cookbook/Matplotlib/PySide
try:
import matplotlib
matplotlib.rcParams['backend.qt4'] = 'PySide'
except:
pass

def create_constant_function(constant):
return lambda:constant
Expand Down
4 changes: 3 additions & 1 deletion camelot/view/action_steps/__init__.py
Expand Up @@ -30,7 +30,8 @@
from open_file import ( OpenFile, OpenStream,
OpenString, OpenJinjaTemplate, WordJinjaTemplate )
from orm import CreateObject, DeleteObject, FlushSession, UpdateObject
from print_preview import PrintHtml, PrintPreview, PrintJinjaTemplate
from print_preview import ( PrintChart, PrintHtml, PrintPreview,
PrintJinjaTemplate )
from select_file import SelectFile
from select_object import SelectObject
from text_edit import EditTextDocument
Expand All @@ -51,6 +52,7 @@
OpenJinjaTemplate.__name__,
OpenStream.__name__,
OpenString.__name__,
PrintChart.__name__,
PrintHtml.__name__,
PrintJinjaTemplate.__name__,
PrintPreview.__name__,
Expand Down
42 changes: 42 additions & 0 deletions camelot/view/action_steps/print_preview.py
Expand Up @@ -85,6 +85,48 @@ def gui_run( self, gui_context ):
dialog = self.render()
dialog.exec_()

class ChartDocument( QtCore.QObject ):
"""Helper class to print matplotlib charts
:param chart: a :class:`camelot.container.chartcontainer.FigureContainer` object
or a :class:`camelot.container.chartcontainer.AxesContainer` subclass
"""

def __init__( self, chart ):
from camelot.container.chartcontainer import structure_to_figure_container
super( ChartDocument, self ).__init__()
self.chart = structure_to_figure_container( chart )

def print_( self, printer ):
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
rect = printer.pageRect( QtGui.QPrinter.Inch )
dpi = printer.resolution()
fig = Figure( facecolor='#ffffff')
fig.set_size_inches( ( rect.width(), rect.height() ) )
fig.set_dpi( dpi )
self.chart.plot_on_figure( fig )
canvas = FigureCanvas( fig )
canvas.render( printer )

class PrintChart( PrintPreview ):
"""
Display a print preview dialog box for a matplotlib chart.
:param chart: a :class:`camelot.container.chartcontainer.FigureContainer` object
or a :class:`camelot.container.chartcontainer.AxesContainer` subclass
Example use of this action step :
.. literalinclude:: ../../../test/test_action.py
:start-after: begin chart print
:end-before: end chart print
"""

def __init__( self, chart ):
super( PrintChart, self ).__init__( ChartDocument( chart ) )

class PrintHtml( PrintPreview ):
"""
Display a print preview dialog box for an html string.
Expand Down
37 changes: 19 additions & 18 deletions camelot/view/controls/delegates/stardelegate.py
Expand Up @@ -29,41 +29,42 @@
from camelot.view.controls import editors
from camelot.view.art import Icon

class StarDelegate(CustomDelegate):
"""Delegate for integer values from (1 to 5)(Rating Delegate)
"""
class StarDelegate( CustomDelegate ):
"""Delegate for integer values from ( default from 1 to 5)(Rating Delegate)
"""

__metaclass__ = DocumentationMetaclass

editor = editors.StarEditor
editor = editors.StarEditor
star_icon = Icon('tango/16x16/status/weather-clear.png')

def __init__(self, parent=None, editable=True, maximum=5, **kwargs):
CustomDelegate.__init__(self,
parent=parent,
editable=editable,
maximum=maximum,
**kwargs)
def __init__( self, parent = None, editable = True, maximum = 5, **kwargs ):
CustomDelegate.__init__( self,
parent = parent,
editable = editable,
maximum = maximum,
**kwargs)
self.maximum = maximum

def paint(self, painter, option, index):
def paint( self, painter, option, index ):
painter.save()
self.drawBackground(painter, option, index)
stars = variant_to_pyobject( index.model().data(index, Qt.EditRole) )

rect = option.rect
rect = QtCore.QRect(rect.left()+3, rect.top()+6, rect.width()-5, rect.height())
rect = QtCore.QRect( rect.left()+3, rect.top()+6,
rect.width()-5, rect.height() )

if( option.state & QtGui.QStyle.State_Selected ):
painter.fillRect(option.rect, option.palette.highlight())
else:
if not self.editable:
painter.fillRect(option.rect, option.palette.window())

for i in range(5):

pixmap = self.star_icon.getQPixmap()
style = QtGui.QApplication.style()
for i in range( self.maximum ):
if i+1<=stars:
icon = Icon('tango/16x16/status/weather-clear.png').getQPixmap()
QtGui.QApplication.style().drawItemPixmap(painter, rect, 1, icon)
style.drawItemPixmap( painter, rect, 1, pixmap )
rect = QtCore.QRect(rect.left()+20, rect.top(), rect.width(), rect.height())
painter.restore()

23 changes: 6 additions & 17 deletions camelot/view/controls/editors/charteditor.py
Expand Up @@ -27,11 +27,12 @@
from PyQt4 import QtGui
from PyQt4 import QtCore

from camelot.admin.action.list_action import ListActionGuiContext
from camelot.core.utils import ugettext as _
from camelot.view.controls.editors.customeditor import AbstractCustomEditor
from camelot.view.controls.editors.wideeditor import WideEditor
from camelot.view.proxy import ValueLoading
from camelot.view.art import Icon
from camelot.core.utils import ugettext as _

PAD_INCHES = 0.1

Expand Down Expand Up @@ -107,6 +108,7 @@ def __init__(self, parent=None, width=50, height=40, dpi=50, field_name='chart',
self.show_fullscreen_signal.connect(self.show_fullscreen)
self.canvas.updateGeometry()
self._litebox = None
self.gui_context = ListActionGuiContext()

@QtCore.pyqtSlot()
def copy_to_clipboard(self):
Expand All @@ -118,22 +120,9 @@ def copy_to_clipboard(self):
@QtCore.pyqtSlot()
def print_preview(self):
"""Popup a print preview dialog for the Chart"""
dialog = QtGui.QPrintPreviewDialog()
dialog.paintRequested.connect( self.on_paint_request )
dialog.exec_()

@QtCore.pyqtSlot( QtGui.QPrinter )
def on_paint_request(self, printer):
from matplotlib.figure import Figure
from matplotlib.backends.backend_qt4agg import FigureCanvasQTAgg as FigureCanvas
rect = printer.pageRect( QtGui.QPrinter.Inch )
dpi = printer.resolution()
fig = Figure( facecolor='#ffffff')
fig.set_figsize_inches( (rect.width(),rect.height()) )
fig.set_dpi( dpi )
self._value.plot_on_figure( fig )
canvas = FigureCanvas(fig)
canvas.render( printer )
from camelot.view.action_steps import PrintChart
print_chart = PrintChart( self._value )
print_chart.gui_run( self.gui_context )

def set_field_attributes(self, *args, **kwargs):
"""Overwrite set_field attributes because a ChartEditor cannot be disabled
Expand Down
14 changes: 7 additions & 7 deletions camelot/view/controls/editors/stareditor.py
Expand Up @@ -28,7 +28,7 @@
from customeditor import CustomEditor
from camelot.view.art import Icon

class StarEditor(CustomEditor):
class StarEditor( CustomEditor ):

star_icon = Icon('tango/16x16/status/weather-clear.png')
no_star_icon = Icon('tango/16x16/status/weather-clear-noStar.png')
Expand All @@ -46,9 +46,9 @@ def __init__(self,
layout.setContentsMargins( 0, 0, 0, 0)
layout.setSpacing(0)

self.starCount = 5
self.maximum = maximum
self.buttons = []
for i in range(self.starCount):
for i in range(self.maximum):
button = QtGui.QToolButton(self)
button.setIcon(self.no_star_icon.getQIcon())
button.setFocusPolicy(Qt.ClickFocus)
Expand All @@ -63,10 +63,10 @@ def __init__(self,
def createStarClick(i):
return lambda:self.starClick(i+1)

for i in range(self.starCount):
for i in range(self.maximum):
self.buttons[i].clicked.connect(createStarClick(i))

for i in range(self.starCount):
for i in range(self.maximum):
layout.addWidget(self.buttons[i])
layout.addStretch()
self.setLayout(layout)
Expand All @@ -85,7 +85,7 @@ def starClick(self, value):
self.stars -= 1
else:
self.stars = int(value)
for i in range(self.starCount):
for i in range(self.maximum):
if i+1 <= self.stars:
self.buttons[i].setIcon(self.star_icon.getQIcon())
else:
Expand All @@ -95,7 +95,7 @@ def starClick(self, value):
def set_value(self, value):
value = CustomEditor.set_value(self, value) or 0
self.stars = int(value)
for i in range(self.starCount):
for i in range(self.maximum):
if i+1 <= self.stars:
self.buttons[i].setIcon(self.star_icon.getQIcon())
else:
Expand Down
13 changes: 6 additions & 7 deletions camelot/view/controls/filter_operator.py
Expand Up @@ -24,6 +24,7 @@

from PyQt4 import QtGui, QtCore

from camelot.view.field_attributes import order_operators
from camelot.core.utils import ugettext
from camelot.view.utils import operator_names
from camelot.view.controls.user_translatable_label import UserTranslatableLabel
Expand Down Expand Up @@ -149,13 +150,11 @@ def decorate_query(self, query):
return query.filter(getattr(self._entity, self._field_name)==None)
field = getattr(self._entity, self._field_name)
operator, arity = self.get_operator_and_arity()
if arity == 1:
args = field, self._value
elif arity == 2:
args = field, self._value, self._value2
else:
assert False, 'Unsupported operator arity: %d' % arity
return query.filter(operator(*args))
values = [self._value, self._value2][:arity]
none_values = sum( v == None for v in values )
if ( operator in order_operators ) and none_values > 0:
return query
return query.filter( operator( field, *values ) )

def get_operator_and_arity(self):
""":return: the current operator and its arity"""
Expand Down
7 changes: 6 additions & 1 deletion camelot/view/controls/formview.py
Expand Up @@ -266,7 +266,7 @@ def __init__(self, title, admin, model, index, parent = None):

layout = QtGui.QVBoxLayout()
layout.setSpacing( 1 )
layout.setMargin( 1 )
layout.setContentsMargins( 1, 1, 1, 1 )
layout.setObjectName( 'layout' )
form_and_actions_layout = QtGui.QHBoxLayout()
form_and_actions_layout.setObjectName('form_and_actions_layout')
Expand Down Expand Up @@ -354,6 +354,11 @@ def set_toolbar_actions(self, actions):
toolbar.addAction( qaction )
toolbar.addWidget( BusyWidget() )
layout.insertWidget( 0, toolbar, 0, Qt.AlignTop )
# @todo : this show is needed on OSX or the form window
# is hidden after the toolbar is added, maybe this can
# be solved using windowflags, since this causes some
# flicker
self.show()

@QtCore.pyqtSlot( bool )
def action_triggered( self, _checked = False ):
Expand Down
2 changes: 1 addition & 1 deletion camelot/view/controls/tableview.py
Expand Up @@ -390,7 +390,7 @@ def __init__(self, admin, parent=None):
column_groups.setObjectName( 'column_groups' )
layout = QtGui.QVBoxLayout()
layout.setSpacing( 0 )
layout.setMargin( 0 )
layout.setContentsMargins( 0, 0, 0, 0 )
layout.addWidget( table_widget )
layout.addWidget( column_groups )
self.setLayout( layout )
Expand Down
6 changes: 6 additions & 0 deletions camelot/view/field_attributes.py
Expand Up @@ -49,6 +49,12 @@
_numerical_operators = (operator.eq, operator.ne, operator.lt, operator.le, operator.gt, operator.ge, between_op)
_text_operators = (operator.eq, operator.ne, like_op)

#
# operators assuming an order in the values they operate on. these operators don't
# work on None values
#
order_operators = (operator.lt, operator.le, operator.gt, operator.ge, between_op, like_op)

_sqlalchemy_to_python_type_ = {

sqlalchemy.types.Boolean: lambda f: {
Expand Down
2 changes: 1 addition & 1 deletion camelot/view/flowlayout.py
Expand Up @@ -20,7 +20,7 @@ def __init__( self, parent = None ):
"""
super(FlowLayout, self).__init__(parent)
if parent is not None:
self.setMargin( 0 )
self.setContentsMargins( 0, 0, 0, 0 )
self.setSpacing( -1 )
self.item_list = []

Expand Down

0 comments on commit 0da4526

Please sign in to comment.