Source code for pyworkflow.gui.project.labels

# **************************************************************************
# *
# * Authors:     J.M. De la Rosa Trevin (jmdelarosa@cnb.csic.es)
# *
# * Unidad de  Bioinformatica of Centro Nacional de Biotecnologia , CSIC
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 3 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307  USA
# *
# *  All comments concerning this program package may be sent to the
# *  e-mail address 'scipion@cnb.csic.es'
# *
# **************************************************************************
"""
Tree widget implementation.
"""
        
import tkinter as tk
from pyworkflow import Config
from pyworkflow.project import Label
from pyworkflow.gui import Icon, configureWeigths
from pyworkflow.gui.tree import TreeProvider
import pyworkflow.gui.dialog as dialog


[docs]class LabelsTreeProvider(TreeProvider): """ Populate Tree from Labels. """ def __init__(self, objList=None): TreeProvider.__init__(self) self.objList = objList self._parentDict = {}
[docs] def getColumns(self): return [('name', 300), ('color', 150)]
[docs] def getObjectInfo(self, label:Label): return {'key': label.getName(), 'parent': None, 'text': label.getName(), 'values': (label.getColor()), 'tags': label.getColor()}
[docs] def getObjectPreview(self, obj): return None, None
[docs] def getObjectActions(self, obj): return []
def _getObjectList(self): """Retrieve the object list""" return self.objList
[docs] def getObjects(self): objList = self._getObjectList() return objList
[docs] def configureTags(self, tree): for label in self.getObjects(): tree.tag_configure(label.getColor(), background=label.getColor())
[docs]class LabelsDialog(dialog.ToolbarListDialog): """ This class extend from ListDialog to allow an extra toolbar to handle operations over the elements in the list (e.g. Edit, New, Delete). """ def __init__(self, parent, labels, **kwargs): """ From kwargs: message: message tooltip to show when browsing. selected: the item that should be selected. validateSelectionCallback: a callback function to validate selected items. allowSelect: if set to False, the 'Select' button will not be shown. """ self.labels = labels toolbarButtons = [ dialog.ToolbarButton('Add', self._addLabel, Icon.ACTION_NEW), dialog.ToolbarButton('Edit', self._editLabel, Icon.ACTION_EDIT), dialog.ToolbarButton('Delete', self._deleteLabel, Icon.ACTION_DELETE) ] helpMsg ="Select the label to edit or delete. Selected labels will be assigned to selected protocols." \ "\nUse 'Control' key for multiple selection. Do not select any label to clear the labels of selected protocols." dialog.ToolbarListDialog.__init__(self, parent, "Manage labels", LabelsTreeProvider(labels), helpMsg, toolbarButtons, allowsEmptySelection=True, itemDoubleClick=self._editLabel, cancelButton=False, **kwargs) def _newColor(self): """ Pick a color by default for a given label from a predefined list. Check that the color have not been used by other label. """ colors = ["#e57373", "#4fc3f7", "#81c784", "#ff8a65", "#9575cd", "#a1887f", "#ffd54f", "#dce775", "#4db6ac"] for c in colors: if all(l.getColor().lower() != c for l in self.labels): return c return 'red' def _addLabel(self, e=None): label = Label(color=self._newColor()) dlg = EditLabelDialog(self, "Add label", label) if dlg.resultYes(): self.labels.addLabel(label) self.tree.update() def _editLabel(self, e=None): selection = self.tree.getSelectedObjects() if selection: label = selection[0] dlg = EditLabelDialog(self, "Edit label", label) if dlg.resultYes(): self.tree.update() def _deleteLabel(self, e=None): selection = self.tree.getSelectedObjects() if selection: labelsStr = '\n'.join('- %s' % l.getName() for l in selection) if dialog.askYesNo("Delete a label", "Are you sure to delete the " "following label(s)?\n %s" % labelsStr, self): for label in selection: self.labels.deleteLabel(label) self.tree.update()
[docs]class EditLabelDialog(dialog.Dialog): """ Dialog to edit a label (name, color) """ def __init__(self, parent, title, label, **kwargs): self.label = label dialog.Dialog.__init__(self, parent, title)
[docs] def body(self, bodyFrame): bodyFrame.config(bg=Config.SCIPION_BG_COLOR) configureWeigths(bodyFrame, 1, 1) # Label label_text = tk.Label(bodyFrame, text="Name", bg=Config.SCIPION_BG_COLOR, bd=0) label_text.grid(row=0, column=0, sticky='nw', padx=(15, 10), pady=15) # Label box var = tk.StringVar() var.set(self.label.getName()) self.textVar = var self.textLabel = tk.Entry(bodyFrame, width=20, textvariable=var) self.textLabel.grid(row=0, column=1, sticky='news', padx=5, pady=5) # Comment colorLabel = tk.Label(bodyFrame, text='Color \n(Click to change)', bg=Config.SCIPION_BG_COLOR, bd=0) colorLabel.grid(row=1, column=0, sticky='nw', padx=(15, 10), pady=15) self.colorVar = tk.StringVar() self.colorVar.set(self.label.getColor()) self.colorBox = tk.Frame(bodyFrame, bg=self.colorVar.get()) self.colorBox.grid(row=1, column=1, sticky='news', padx=5, pady=5) colorLabel.bind('<Button-1>', self._changeColor) self.colorBox.bind('<Button-1>', self._changeColor)
[docs] def apply(self): self.label.setName(self.textVar.get()) self.label.setColor(self.colorVar.get())
def _changeColor(self, e=None): hexColor = dialog.askColor(parent=self, defaultColor=self.colorVar.get()) if hexColor is not None: self.colorBox.config(bg=hexColor) self.colorVar.set(hexColor)
[docs] def validate(self): validationMsg = None if len(self.textVar.get().strip()) == 0: validationMsg = "Label name can't be empty.\n" if validationMsg is not None: dialog.showError("Validation error", validationMsg, self) return False return True