Revision: 8064 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=8064&view=rev Author: jdh2358 Date: 2010-01-03 18:30:04 +0000 (Sun, 03 Jan 2010)
Log Message: ----------- added qt4_editor dialog Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py trunk/matplotlib/setup.py Added Paths: ----------- trunk/matplotlib/lib/matplotlib/backends/qt4_editor/ trunk/matplotlib/lib/matplotlib/backends/qt4_editor/__init__.py trunk/matplotlib/lib/matplotlib/backends/qt4_editor/figureoptions.py trunk/matplotlib/lib/matplotlib/backends/qt4_editor/formlayout.py trunk/matplotlib/license/LICENSE_QT4_EDITOR Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2010-01-02 06:30:15 UTC (rev 8063) +++ trunk/matplotlib/CHANGELOG 2010-01-03 18:30:04 UTC (rev 8064) @@ -1,3 +1,5 @@ +2010-01-03 Added Pierre's qt4 formlayout editor and toolbar button - JDH + 2009-12-31 Add support for using math text as marker symbols (Thanks to tcb) - MGD Modified: trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2010-01-02 06:30:15 UTC (rev 8063) +++ trunk/matplotlib/lib/matplotlib/backends/backend_qt4.py 2010-01-03 18:30:04 UTC (rev 8064) @@ -12,6 +12,7 @@ from matplotlib.figure import Figure from matplotlib.mathtext import MathTextParser from matplotlib.widgets import SubplotTool +import matplotlib.backends.qt4_editor.figureoptions as figureoptions try: from PyQt4 import QtCore, QtGui, Qt @@ -330,10 +331,16 @@ a = self.addAction(self._icon('subplots.png'), 'Subplots', self.configure_subplots) a.setToolTip('Configure subplots') + + a = self.addAction(self._icon("qt4_editor_options.svg"), + 'Customize', self.edit_parameters) + a.setToolTip('Edit curves line and axes parameters') + a = self.addAction(self._icon('filesave.svg'), 'Save', self.save_figure) a.setToolTip('Save the figure') + self.buttons = {} # Add the x,y location widget at the right side of the toolbar @@ -352,6 +359,36 @@ # reference holder for subplots_adjust window self.adj_window = None + def edit_parameters(self): + allaxes = self.canvas.figure.get_axes() + if len(allaxes) == 1: + axes = allaxes[0] + else: + titles = [] + for axes in allaxes: + title = axes.get_title() + ylabel = axes.get_ylabel() + if title: + text = title + if ylabel: + text += ": "+ylabel + text += " (%s)" + elif ylabel: + text = "%s (%s)" % ylabel + else: + text = "%s" + titles.append(text % repr(axes)) + item, ok = QtGui.QInputDialog.getItem(self, 'Customize', + 'Select axes:', titles, + 0, False) + if ok: + axes = allaxes[titles.index(unicode(item))] + else: + return + + figureoptions.figure_edit(axes, self) + + def dynamic_update( self ): self.canvas.draw() Added: trunk/matplotlib/lib/matplotlib/backends/qt4_editor/figureoptions.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/qt4_editor/figureoptions.py (rev 0) +++ trunk/matplotlib/lib/matplotlib/backends/qt4_editor/figureoptions.py 2010-01-03 18:30:04 UTC (rev 8064) @@ -0,0 +1,154 @@ +# -*- coding: utf-8 -*- +# +# Copyright © 2009 Pierre Raybaut +# Licensed under the terms of the MIT License +# see the mpl licenses directory for a copy of the license + +"""Module that provides a GUI-based editor for matplotlib's figure options""" + +import os.path as osp + +import matplotlib.backends.qt4_editor.formlayout as formlayout +from PyQt4.QtGui import QIcon + +def get_icon(name): + import matplotlib + basedir = osp.join(matplotlib.rcParams['datapath'], 'images') + return QIcon(osp.join(basedir, name)) + +LINESTYLES = { + '-': 'Solid', + '--': 'Dashed', + '-.': 'DashDot', + ':': 'Dotted', + 'steps': 'Steps', + 'none': 'None', + } + +MARKERS = { + 'none': 'None', + 'o': 'circles', + '^': 'triangle_up', + 'v': 'triangle_down', + '<': 'triangle_left', + '>': 'triangle_right', + 's': 'square', + '+': 'plus', + 'x': 'cross', + '*': 'star', + 'D': 'diamond', + 'd': 'thin_diamond', + '1': 'tripod_down', + '2': 'tripod_up', + '3': 'tripod_left', + '4': 'tripod_right', + 'h': 'hexagon', + 'H': 'rotated_hexagon', + 'p': 'pentagon', + '|': 'vertical_line', + '_': 'horizontal_line', + '.': 'dots', + } + +COLORS = {'b': '#0000ff', 'g': '#00ff00', 'r': '#ff0000', 'c': '#ff00ff', + 'm': '#ff00ff', 'y': '#ffff00', 'k': '#000000', 'w': '#ffffff'} + +def col2hex(color): + """Convert matplotlib color to hex""" + return COLORS.get(color, color) + +def figure_edit(axes, parent=None): + """Edit matplotlib figure options""" + sep = (None, None) # separator + + has_curve = len(axes.get_lines()) > 0 + + # Get / General + xmin, xmax = axes.get_xlim() + ymin, ymax = axes.get_ylim() + general = [('Title', axes.get_title()), + sep, + (None, "<b>X-Axis</b>"), + ('Min', xmin), ('Max', xmax), + ('Label', axes.get_xlabel()), + ('Scale', [axes.get_xscale(), 'linear', 'log']), + sep, + (None, "<b>Y-Axis</b>"), + ('Min', ymin), ('Max', ymax), + ('Label', axes.get_ylabel()), + ('Scale', [axes.get_yscale(), 'linear', 'log']) + ] + + if has_curve: + # Get / Curves + linedict = {} + for line in axes.get_lines(): + label = line.get_label() + if label == '_nolegend_': + continue + linedict[label] = line + curves = [] + linestyles = LINESTYLES.items() + markers = MARKERS.items() + curvelabels = sorted(linedict.keys()) + for label in curvelabels: + line = linedict[label] + curvedata = [ + ('Label', label), + sep, + (None, '<b>Line</b>'), + ('Style', [line.get_linestyle()] + linestyles), + ('Width', line.get_linewidth()), + ('Color', col2hex(line.get_color())), + sep, + (None, '<b>Marker</b>'), + ('Style', [line.get_marker()] + markers), + ('Size', line.get_markersize()), + ('Facecolor', col2hex(line.get_markerfacecolor())), + ('Edgecolor', col2hex(line.get_markeredgecolor())), + ] + curves.append([curvedata, label, ""]) + + datalist = [(general, "Axes", "")] + if has_curve: + datalist.append((curves, "Curves", "")) + result = formlayout.fedit(datalist, title="Figure options", parent=parent, + icon=get_icon('qt4_editor_options.svg')) + if result is None: + return + + if has_curve: + general, curves = result + else: + general, = result + + # Set / General + title, xmin, xmax, xlabel, xscale, ymin, ymax, ylabel, yscale = general + axes.set_xscale(xscale) + axes.set_yscale(yscale) + axes.set_title(title) + axes.set_xlim(xmin, xmax) + axes.set_xlabel(xlabel) + axes.set_ylim(ymin, ymax) + axes.set_ylabel(ylabel) + + if has_curve: + # Set / Curves + for index, curve in enumerate(curves): + line = linedict[curvelabels[index]] + label, linestyle, linewidth, color, \ + marker, markersize, markerfacecolor, markeredgecolor = curve + line.set_label(label) + line.set_linestyle(linestyle) + line.set_linewidth(linewidth) + line.set_color(color) + if marker is not 'none': + line.set_marker(marker) + line.set_markersize(markersize) + line.set_markerfacecolor(markerfacecolor) + line.set_markeredgecolor(markeredgecolor) + + # Redraw + figure = axes.get_figure() + figure.canvas.draw() + Added: trunk/matplotlib/lib/matplotlib/backends/qt4_editor/formlayout.py =================================================================== --- trunk/matplotlib/lib/matplotlib/backends/qt4_editor/formlayout.py (rev 0) +++ trunk/matplotlib/lib/matplotlib/backends/qt4_editor/formlayout.py 2010-01-03 18:30:04 UTC (rev 8064) @@ -0,0 +1,487 @@ +# -*- coding: utf-8 -*- +""" +formlayout +========== + +Module creating PyQt4 form dialogs/layouts to edit various type of parameters + + +formlayout License Agreement (MIT License) +------------------------------------------ + +Copyright (c) 2009 Pierre Raybaut + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +""" + +__version__ = '1.0.5' +__license__ = __doc__ + +DEBUG = False + +import sys +STDERR = sys.stderr + +try: + from PyQt4.QtGui import QFormLayout +except ImportError: + raise ImportError, "Warning: formlayout requires PyQt4 >v4.3" + +from PyQt4.QtGui import (QWidget, QLineEdit, QComboBox, QLabel, QSpinBox, QIcon, + QStyle, QDialogButtonBox, QHBoxLayout, QVBoxLayout, + QDialog, QColor, QPushButton, QCheckBox, QColorDialog, + QPixmap, QTabWidget, QApplication, QStackedWidget, + QDateEdit, QDateTimeEdit, QFont, QFontComboBox, + QFontDatabase, QGridLayout) +from PyQt4.QtCore import (Qt, SIGNAL, SLOT, QSize, QString, + pyqtSignature, pyqtProperty) +from datetime import date + + +class ColorButton(QPushButton): + """ + Color choosing push button + """ + __pyqtSignals__ = ("colorChanged(QColor)",) + + def __init__(self, parent=None): + QPushButton.__init__(self, parent) + self.setFixedSize(20, 20) + self.setIconSize(QSize(12, 12)) + self.connect(self, SIGNAL("clicked()"), self.chooseColor) + self._color = QColor() + + def chooseColor(self): + rgba, valid = QColorDialog.getRgba(self._color.rgba(), + self.parentWidget()) + if valid: + color = QColor.fromRgba(rgba) + self.setColor(color) + + def color(self): + return self._color + + @pyqtSignature("QColor") + def setColor(self, color): + if color != self._color: + self._color = color + self.emit(SIGNAL("colorChanged(QColor)"), self._color) + pixmap = QPixmap(self.iconSize()) + pixmap.fill(color) + self.setIcon(QIcon(pixmap)) + + color = pyqtProperty("QColor", color, setColor) + + +def text_to_qcolor(text): + """ + Create a QColor from specified string + Avoid warning from Qt when an invalid QColor is instantiated + """ + color = QColor() + if isinstance(text, QString): + text = str(text) + if not isinstance(text, (unicode, str)): + return color + if text.startswith('#') and len(text)==7: + correct = '#0123456789abcdef' + for char in text: + if char.lower() not in correct: + return color + elif text not in list(QColor.colorNames()): + return color + color.setNamedColor(text) + return color + + +class ColorLayout(QHBoxLayout): + """Color-specialized QLineEdit layout""" + def __init__(self, color, parent=None): + QHBoxLayout.__init__(self) + assert isinstance(color, QColor) + self.lineedit = QLineEdit(color.name(), parent) + self.connect(self.lineedit, SIGNAL("textChanged(QString)"), + self.update_color) + self.addWidget(self.lineedit) + self.colorbtn = ColorButton(parent) + self.colorbtn.color = color + self.connect(self.colorbtn, SIGNAL("colorChanged(QColor)"), + self.update_text) + self.addWidget(self.colorbtn) + + def update_color(self, text): + color = text_to_qcolor(text) + if color.isValid(): + self.colorbtn.color = color + + def update_text(self, color): + self.lineedit.setText(color.name()) + + def text(self): + return self.lineedit.text() + + +def font_is_installed(font): + """Check if font is installed""" + return [fam for fam in QFontDatabase().families() if unicode(fam)==font] + +def tuple_to_qfont(tup): + """ + Create a QFont from tuple: + (family [string], size [int], italic [bool], bold [bool]) + """ + if not isinstance(tup, tuple) or len(tup) != 4 \ + or not font_is_installed(tup[0]) \ + or not isinstance(tup[1], int) \ + or not isinstance(tup[2], bool) \ + or not isinstance(tup[3], bool): + return None + font = QFont() + family, size, italic, bold = tup + font.setFamily(family) + font.setPointSize(size) + font.setItalic(italic) + font.setBold(bold) + return font + +def qfont_to_tuple(font): + return (unicode(font.family()), int(font.pointSize()), + font.italic(), font.bold()) + + +class FontLayout(QGridLayout): + """Font selection""" + def __init__(self, value, parent=None): + QGridLayout.__init__(self) + font = tuple_to_qfont(value) + assert font is not None + + # Font family + self.family = QFontComboBox(parent) + self.family.setCurrentFont(font) + self.addWidget(self.family, 0, 0, 1, -1) + + # Font size + self.size = QComboBox(parent) + self.size.setEditable(True) + sizelist = range(6, 12) + range(12, 30, 2) + [36, 48, 72] + size = font.pointSize() + if size not in sizelist: + sizelist.append(size) + sizelist.sort() + self.size.addItems([str(s) for s in sizelist]) + self.size.setCurrentIndex(sizelist.index(size)) + self.addWidget(self.size, 1, 0) + + # Italic or not + self.italic = QCheckBox(self.tr("Italic"), parent) + self.italic.setChecked(font.italic()) + self.addWidget(self.italic, 1, 1) + + # Bold or not + self.bold = QCheckBox(self.tr("Bold"), parent) + self.bold.setChecked(font.bold()) + self.addWidget(self.bold, 1, 2) + + def get_font(self): + font = self.family.currentFont() + font.setItalic(self.italic.isChecked()) + font.setBold(self.bold.isChecked()) + font.setPointSize(int(self.size.currentText())) + return qfont_to_tuple(font) + + +class FormWidget(QWidget): + def __init__(self, data, comment="", parent=None): + super(FormWidget, self).__init__(parent) + from copy import deepcopy + self.data = deepcopy(data) + self.widgets = [] + self.formlayout = QFormLayout(self) + if comment: + self.formlayout.addRow(QLabel(comment)) + self.formlayout.addRow(QLabel(" ")) + if DEBUG: + print "\n"+("*"*80) + print "DATA:", self.data + print "*"*80 + print "COMMENT:", comment + print "*"*80 + self.setup() + + def setup(self): + for label, value in self.data: + if DEBUG: + print "value:", value + if label is None and value is None: + # Separator: (None, None) + self.formlayout.addRow(QLabel(" "), QLabel(" ")) + self.widgets.append(None) + continue + elif label is None: + # Comment + self.formlayout.addRow(QLabel(value)) + self.widgets.append(None) + continue + elif tuple_to_qfont(value) is not None: + field = FontLayout(value, self) + elif text_to_qcolor(value).isValid(): + field = ColorLayout(QColor(value), self) + elif isinstance(value, (str, unicode)): + field = QLineEdit(value, self) + elif isinstance(value, (list, tuple)): + selindex = value.pop(0) + field = QComboBox(self) + if isinstance(value[0], (list, tuple)): + keys = [ key for key, _val in value ] + value = [ val for _key, val in value ] + else: + keys = value + field.addItems(value) + if selindex in value: + selindex = value.index(selindex) + elif selindex in keys: + selindex = keys.index(selindex) + elif not isinstance(selindex, int): + print >>STDERR, "Warning: '%s' index is invalid (label: " \ + "%s, value: %s)" % (selindex, label, value) + selindex = 0 + field.setCurrentIndex(selindex) + elif isinstance(value, bool): + field = QCheckBox(self) + field.setCheckState(Qt.Checked if value else Qt.Unchecked) + elif isinstance(value, float): + field = QLineEdit(repr(value), self) + elif isinstance(value, int): + field = QSpinBox(self) + field.setValue(value) + field.setMaximum(1e9) + elif isinstance(value, date): + if hasattr(value, 'hour'): + field = QDateTimeEdit(self) + field.setDateTime(value) + else: + field = QDateEdit(self) + field.setDate(value) + else: + field = QLineEdit(repr(value), self) + self.formlayout.addRow(label, field) + self.widgets.append(field) + + def get(self): + valuelist = [] + for index, (label, value) in enumerate(self.data): + field = self.widgets[index] + if label is None: + # Separator / Comment + continue + elif tuple_to_qfont(value) is not None: + value = field.get_font() + elif isinstance(value, (str, unicode)): + value = unicode(field.text()) + elif isinstance(value, (list, tuple)): + index = int(field.currentIndex()) + if isinstance(value[0], (list, tuple)): + value = value[index][0] + else: + value = value[index] + elif isinstance(value, bool): + value = field.checkState() == Qt.Checked + elif isinstance(value, float): + value = float(field.text()) + elif isinstance(value, int): + value = int(field.value()) + elif isinstance(value, date): + if hasattr(value, 'hour'): + value = field.dateTime().toPyDateTime() + else: + value = field.date().toPyDate() + else: + value = eval(str(field.text())) + valuelist.append(value) + return valuelist + + +class FormComboWidget(QWidget): + def __init__(self, datalist, comment="", parent=None): + super(FormComboWidget, self).__init__(parent) + layout = QVBoxLayout() + self.setLayout(layout) + self.combobox = QComboBox() + layout.addWidget(self.combobox) + + self.stackwidget = QStackedWidget(self) + layout.addWidget(self.stackwidget) + self.connect(self.combobox, SIGNAL("currentIndexChanged(int)"), + self.stackwidget, SLOT("setCurrentIndex(int)")) + + self.widgetlist = [] + for data, title, comment in datalist: + self.combobox.addItem(title) + widget = FormWidget(data, comment=comment, parent=self) + self.stackwidget.addWidget(widget) + self.widgetlist.append(widget) + + def get(self): + return [ widget.get() for widget in self.widgetlist] + + +class FormTabWidget(QWidget): + def __init__(self, datalist, comment="", parent=None): + super(FormTabWidget, self).__init__(parent) + layout = QVBoxLayout() + self.tabwidget = QTabWidget() + layout.addWidget(self.tabwidget) + self.setLayout(layout) + self.widgetlist = [] + for data, title, comment in datalist: + if len(data[0])==3: + widget = FormComboWidget(data, comment=comment, parent=self) + else: + widget = FormWidget(data, comment=comment, parent=self) + index = self.tabwidget.addTab(widget, title) + self.tabwidget.setTabToolTip(index, comment) + self.widgetlist.append(widget) + + def get(self): + return [ widget.get() for widget in self.widgetlist] + + +class FormDialog(QDialog): + """Form Dialog""" + def __init__(self, data, title="", comment="", + icon=None, parent=None): + super(FormDialog, self).__init__(parent) + + # Form + if isinstance(data[0][0], (list, tuple)): + self.formwidget = FormTabWidget(data, comment=comment, + parent=self) + elif len(data[0])==3: + self.formwidget = FormComboWidget(data, comment=comment, + parent=self) + else: + self.formwidget = FormWidget(data, comment=comment, + parent=self) + layout = QVBoxLayout() + layout.addWidget(self.formwidget) + + # Button box + bbox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) + self.connect(bbox, SIGNAL("accepted()"), SLOT("accept()")) + self.connect(bbox, SIGNAL("rejected()"), SLOT("reject()")) + layout.addWidget(bbox) + + self.setLayout(layout) + + self.setWindowTitle(title) + if not isinstance(icon, QIcon): + icon = QWidget().style().standardIcon(QStyle.SP_MessageBoxQuestion) + self.setWindowIcon(icon) + + def accept(self): + self.data = self.formwidget.get() + QDialog.accept(self) + + def reject(self): + self.data = None + QDialog.reject(self) + + def get(self): + """Return form result""" + return self.data + + +def fedit(data, title="", comment="", icon=None, parent=None): + """ + Create form dialog and return result + (if Cancel button is pressed, return None) + + data: datalist, datagroup + + datalist: list/tuple of (field_name, field_value) + datagroup: list/tuple of (datalist *or* datagroup, title, comment) + + -> one field for each member of a datalist + -> one tab for each member of a top-level datagroup + -> one page (of a multipage widget, each page can be selected with a combo + box) for each member of a datagroup inside a datagroup + + Supported types for field_value: + - int, float, str, unicode, bool + - colors: in Qt-compatible text form, i.e. in hex format or name (red,...) + (automatically detected from a string) + - list/tuple: + * the first element will be the selected index (or value) + * the other elements can be couples (key, value) or only values + """ + + # Create a QApplication instance if no instance currently exists + # (e.g. if the module is used directly from the interpreter) + if QApplication.startingUp(): + QApplication([]) + + dialog = FormDialog(data, title, comment, icon, parent) + if dialog.exec_(): + return dialog.get() + + + +if __name__ == "__main__": + + def create_datalist_example(): + return [('str', 'this is a string'), + ('list', [0, '1', '3', '4']), + ('list2', ['--', ('none', 'None'), ('--', 'Dashed'), + ('-.', 'DashDot'), ('-', 'Solid'), + ('steps', 'Steps'), (':', 'Dotted')]), + ('float', 1.2), + (None, 'Other:'), + ('int', 12), + ('font', ('Arial', 10, False, True)), + ('color', '#123409'), + ('bool', True), + ('datetime', date(2010, 10, 10)), + ] + + def create_datagroup_example(): + datalist = create_datalist_example() + return ((datalist, "Category 1", "Category 1 comment"), + (datalist, "Category 2", "Category 2 comment"), + (datalist, "Category 3", "Category 3 comment")) + + #--------- datalist example + datalist = create_datalist_example() + print "result:", fedit(datalist, title="Example", + comment="This is just an <b>example</b>.") + + #--------- datagroup example + datagroup = create_datagroup_example() + print "result:", fedit(datagroup, "Global title") + + #--------- datagroup inside a datagroup example + datalist = create_datalist_example() + datagroup = create_datagroup_example() + print "result:", fedit(((datagroup, "Title 1", "Tab 1 comment"), + (datalist, "Title 2", "Tab 2 comment"), + (datalist, "Title 3", "Tab 3 comment")), + "Global title") Added: trunk/matplotlib/license/LICENSE_QT4_EDITOR =================================================================== --- trunk/matplotlib/license/LICENSE_QT4_EDITOR (rev 0) +++ trunk/matplotlib/license/LICENSE_QT4_EDITOR 2010-01-03 18:30:04 UTC (rev 8064) @@ -0,0 +1,30 @@ + +Module creating PyQt4 form dialogs/layouts to edit various type of parameters + + +formlayout License Agreement (MIT License) +------------------------------------------ + +Copyright (c) 2009 Pierre Raybaut + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. +""" Modified: trunk/matplotlib/setup.py =================================================================== --- trunk/matplotlib/setup.py 2010-01-02 06:30:15 UTC (rev 8063) +++ trunk/matplotlib/setup.py 2010-01-03 18:30:04 UTC (rev 8064) @@ -49,6 +49,7 @@ packages = [ 'matplotlib', 'matplotlib.backends', + 'matplotlib.backends.qt4_editor', 'matplotlib.projections', 'matplotlib.testing', 'matplotlib.testing.jpl_units', This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. ------------------------------------------------------------------------------ This SF.Net email is sponsored by the Verizon Developer Community Take advantage of Verizon's best-in-class app development support A streamlined, 14 day to market process makes app distribution fast and easy Join now and get one step closer to millions of Verizon customers http://p.sf.net/sfu/verizon-dev2dev _______________________________________________ Matplotlib-checkins mailing list Matplotlib-checkins@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/matplotlib-checkins