# **************************************************************************
# *
# * 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, getDefaultFont
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]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, font=getDefaultFont(), 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