예제 #1
0
 def __init__(self, parent=None, gui_settings=None, config=None, **kw):
     QWidget.__init__(self, parent=parent)
     default_config = os.path.join(
         os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
         'core', 'default_config.json')
     #
     if config:
         Variables().read(config)
     else:
         Variables().read(default_config)
     #
     tabWidget = TabWidget(gui_settings)
     footer = Footer(self, gui_settings=gui_settings)
     layout = QVBoxLayout(self)
     self.setLayout(layout)
     self.layout().setAlignment(QtCore.Qt.AlignTop)
     self.layout().addWidget(tabWidget)
     self.layout().addWidget(footer)
     self.setObjectName("MainWidget")
    def setUp(self):
        """ Create the popup"""
        default_config_path = get_default_config_path()
        Variables().read(default_config_path)
        fin = open(default_config_path, 'r')
        self.defaults = json.load(fin)["res_evo_settings"]
        fin.close()

        self.popup = ResidueEvolutionPopup()
        self.variable_keys = tuple(self.popup.variables.keys())
        self.local_variable_keys = tuple(self.popup.local_variables.keys())
예제 #3
0
    def setUp(self):
        """ Create the popup"""
        default_config_path = get_default_config_path()
        Variables().read(default_config_path)
        fin = open(default_config_path, 'r')
        self.defaults = json.load(fin)["bar_plot_settings"]
        fin.close()

        self.popup = BarPlotPopup()
        self.variable_keys = tuple(self.popup.variables.keys())
        self.local_variable_keys = tuple(self.popup.local_variables.keys())
예제 #4
0
    def setUp(self):
        """ Create the popup"""

        default_config_path = get_default_config_path()
        Variables().read(default_config_path)
        fin = open(default_config_path, 'r')
        self.defaults = json.load(fin)["pre_files"]
        fin.close()

        self.popup = PRETheoreticalSelectionPopup()
        self.variable_keys = tuple(self.popup.variables.keys())
        self.local_variable_keys = tuple(self.popup.local_variables.keys())
    def setUp(self):
        """ Create the popup"""

        default_config_path = get_default_config_path()
        Variables().read(default_config_path)
        fin = open(default_config_path, 'r')
        self.defaults = json.load(fin)["csp_settings"]["csp_res_exceptions"]
        fin.close()

        self.popup = CSPExceptionsPopup()
        self.variable_keys = tuple(self.popup.variables.keys())
        self.local_variable_keys = tuple(self.popup.local_variables.keys())
예제 #6
0
class BasePopup(QDialog):
    """
    Base QDialog for all Farseer-NMR popups.
    
    Parameters:
        parent(QWidget): parent QWidget
        settings_keys(str or list): specifies the keys to access popup specific
            settings in variables.
        title(str): name of the popup.
    
    Methods:
        .launch()
    
    """

    variables = Variables()._vars

    def __init__(self,
                 parent,
                 settings_key=None,
                 title=None,
                 layout='grid',
                 **kw):
        QDialog.__init__(self, parent)
        self.setWindowTitle(title)

        if layout == 'grid':
            grid = QGridLayout()
            grid.setAlignment(QtCore.Qt.AlignTop)
            self.setLayout(grid)

        if layout == 'vbox':
            v_layout = QVBoxLayout()
            v_layout.setAlignment(QtCore.Qt.AlignTop)
            self.setLayout(v_layout)

        if settings_key:
            if isinstance(settings_key, str):
                self.local_variables = self.variables[settings_key]
                self.defaults = defaults[settings_key]

            elif isinstance(settings_key, list):
                self.local_variables = get_nested_value(
                    self.variables, settings_key)
                self.defaults = get_nested_value(defaults, settings_key)

    def launch(self):
        self.exec_()
        self.raise_()
예제 #7
0
    def setUp(self):
        ''' Create the popup'''
        default_config_path = get_default_config_path()
        Variables().read(default_config_path)
        fin = open(default_config_path, 'r')
        self.defaults = json.load(fin)
        fin.close()

        screen_resolution = app.desktop().screenGeometry()
        gui_settings, stylesheet = gui_utils.deliver_settings(
            screen_resolution)

        tabWidget = TabWidget(gui_settings)
        self.widget = Settings(tabWidget,
                               gui_settings=gui_settings,
                               footer=True)

        self.variable_keys = tuple(self.widget.variables.keys())
예제 #8
0
    def load_config(self, path=None):
        """
        Connection from Tab footer to TabWidget for loading Farseer-NMR
        configuration files.
        """
        if not path:
            fname = QFileDialog.getOpenFileName(None, 'Load Configuration',
                                                os.getcwd())

        else:
            fname = [path]

        if fname[0]:
            if fname[0].split('.')[1] == 'json':
                Variables().read(fname[0])
                self.load_variables()
                self.config_file = fname[0]

        return
예제 #9
0
class BaseWidget(QWidget):
    """
    Forms the base of all Farseer-NMR widgets.
    
    The tabs inside the Farseer GUI are all subclasses of this class, which
    ensures that an instance of the variables "Borg" class is automatically
    available as self.variables without having to import it into individual
    widgets.
    
    The gui_settings argument is passed in when the subclassed widget is
    instantiated in TabWidget and ensures that all design and styling are
    applied to all GUI features.
    
    The footer boolean is used to switch on and off  the load, save and run
    buttons at the bottom of a widget. This can be useful if a widget is
    particularly space hungry.
    
    We strongly advocate that all additional widgets inherit from this base
    class!
    
    Parameters:
        parent (QWidget):
        gui_settings (dict): a dictionary carrying the settings required to
            correctly render the graphics based on screen resolution.
        footer (boolean): determines whether the footer will be displayed.
    """

    variables = Variables()._vars

    def __init__(self, parent=None, gui_settings=None, footer=True):
        QWidget.__init__(self, parent=parent)
        self.gui_settings = gui_settings

        if footer:
            self.tab_footer = TabFooter(self)
            self.tab_footer.load_config_button.clicked.connect(
                parent.load_config)
            self.tab_footer.save_config_button.clicked.connect(
                parent.save_config)
            self.tab_footer.run_farseer_button.clicked.connect(
                parent.run_farseer_calculation)
예제 #10
0
    def save_config(self, path=None):
        """
        Connection from Tab footer to TabWidget for saving Farseer-NMR
        configuration files.
        """
        self.interface.save_config()

        if not path:
            filters = "JSON files (*.json)"
            selected_filter = "JSON files (*.json)"
            fname = QFileDialog.getSaveFileName(self, "Save Configuration", "",
                                                filters, selected_filter)
        else:
            fname = [path]

        if not fname[0].endswith('.json'):
            fname = [fname[0] + ".json"]

        if fname[0]:
            with open(fname[0], 'w') as outfile:
                Variables().write(outfile)
                self.config_file = os.path.abspath(fname[0])

        print('Configuration saved to {}'.format(fname[0]))
예제 #11
0
class PeakListArea(QWidget):
    """
    A widget containing a QGraphicsScene for rendering the drag and drop
    creation of the Farseer-NMR cube.

    When a peaklist is dropped on a PeakListLabel instance, the variables
    instance is updated and its position in the Farseer-NMR cube is specified.

    Parameters:
        parent (QWidget): specifies the parent widget containing the QLabel
            and the QSpinBox.
        gui_settings (dict): a dictionary carrying the settings required to
            correctly render the graphics based on screen resolution.

    Methods:
        .setEvents()
        .side_bar()
        .update_variables()
        .show_update_warning()
        .show_duplicate_key_warning()
        .update_experimental_dataset(values_dict)
        .check_conditions_for_tree()
        .update_tree()
        .add_connecting_line()
    """

    variables = Variables()._vars

    def __init__(self, parent, gui_settings):
        QWidget.__init__(self, parent)
        self.scene = QGraphicsScene(self)
        self.height = gui_settings['peaklistarea_height']
        self.scrollContents = QGraphicsView(self.scene, self)
        self.scrollContents.setRenderHint(QtGui.QPainter.Antialiasing)
        self.scene.setSceneRect(0, 0, width, self.height)
        layout = QGridLayout()
        self.setLayout(layout)
        self.layout().addWidget(self.scrollContents)
        self.scrollContents.setMinimumSize(gui_settings['scene_width'],
                                           gui_settings['scene_height'])
        self.scrollContents.setAcceptDrops(True)
        self.set_events()
        self.updateClicks = 0

    def set_events(self):
        self.scrollContents.scene().dragEnterEvent = self._dragEnterEvent

    def _dragEnterEvent(self, event):
        event.accept()

    def side_bar(self):
        return self.parent().parent().parent().side_bar

    def update_variables(self):
        self.update_tree()

    def show_update_warning(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText("Reset Experimental Series")
        msg.setInformativeText("Do you want to all peaklists from the "
                               "Experimental Series and re-draw the series?")
        msg.setWindowTitle("Reset Experimental Series")
        msg.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)

        retval = msg.exec_()
        return retval

    def show_duplicate_key_warning(self, axis):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText("Duplicate conditions")
        msg.setInformativeText("There are duplicate "
                               "conditions on the {} axis. ".format(axis))
        msg.setWindowTitle("Duplicate conditions")
        msg.setStandardButtons(QMessageBox.Ok)
        retval = msg.exec_()
        return retval

    def show_empty_condition_warning(self):
        msg = QMessageBox()
        msg.setIcon(QMessageBox.Warning)
        msg.setText("Empty conditions")
        msg.setInformativeText("There are empty conditions, "
                               "so dataset cannot be drawn.")
        msg.setWindowTitle("Empty conditions")
        msg.setStandardButtons(QMessageBox.Ok)
        retval = msg.exec_()
        return retval

    def update_experimental_dataset(self, values_dict):
        tmp_dict = {}

        for z in values_dict["z"]:
            tmp_dict[z] = {}
            for y in values_dict["y"]:
                tmp_dict[z][y] = {}
                for x in values_dict["x"]:
                    tmp_dict[z][y][x] = ''
                    if self.variables["experimental_dataset"][z][y].keys():
                        tmp_dict[z][y][x] = \
                            self.variables["experimental_dataset"][z][y][x]

        return tmp_dict

    def check_conditions_for_tree(self):
        self.values_dict = self.variables["conditions"]

        # Check if condition boxes are empty and throw warning if so.
        if not all(x for v in self.values_dict.values() for x in v):
            self.show_empty_condition_warning()
            return False

        if len(set(self.values_dict['z'])) != len(self.values_dict['z']):
            self.show_duplicate_key_warning('z')
            return False

        if len(set(self.values_dict['y'])) != len(self.values_dict['y']):
            self.show_duplicate_key_warning('y')
            return False

        if len(set(self.values_dict['x'])) != len(self.values_dict['x']):
            self.show_duplicate_key_warning('x')
            return False

        return True

    def update_tree(self):

        if not self.check_conditions_for_tree():
            return

        if self.updateClicks > 0:
            if self.show_update_warning() == QMessageBox.Cancel:
                return

        self.peak_list_objects = []
        self.peak_list_dict = {}
        self.show()
        self.side_bar().refresh_sidebar()
        self.scene.clear()
        z_conds = self.values_dict['z']
        y_conds = self.values_dict['y']
        x_conds = self.values_dict['x']
        num_x = len(x_conds)
        num_y = len(y_conds)
        num_z = len(z_conds)
        total_x = num_x * num_y * num_z
        keys_to_remove = [
            k for k in self.variables['fasta_files'].keys() if k not in y_conds
        ]
        for k in keys_to_remove:
            del self.variables['fasta_files'][k]

        if total_x > 10:
            self.scrollContents.setSceneRect(0, 0, width, total_x * 22)

        else:
            self.scrollContents.setSceneRect(0, 0, width, self.height)

        self.scrollContents.fitInView(0, 0, width, self.height,
                                      QtCore.Qt.KeepAspectRatio)

        if total_x < 2:
            x_spacing = self.scene.height() / 2

        elif 2 < total_x < 10:
            x_spacing = self.scene.height() / (total_x + 1)

        else:
            x_spacing = 20

        zz_pos = 0
        yy_pos = self.scene.width() * 0.25
        xx_pos = self.scene.width() * 0.5
        pl_pos = self.scene.width() * 0.75
        xx_vertical = x_spacing
        num = 0

        for i, z in enumerate(z_conds):
            self.peak_list_dict[z] = {}
            y_markers = []

            for j, y in enumerate(y_conds):
                self.peak_list_dict[z][y] = {}
                x_markers = []

                for k, x in enumerate(x_conds):
                    xx = ConditionLabel(str(x), [xx_pos, xx_vertical])
                    self.scene.addItem(xx)

                    if z not in self.variables["experimental_dataset"].keys() \
                            or y not in self.variables["experimental_dataset"][z].keys() \
                            or x not in self.variables["experimental_dataset"][z][y].keys():
                        pl = PeakListLabel(self,
                                           'Drop peaklist here',
                                           self.scene, [pl_pos, xx_vertical],
                                           x_cond=x,
                                           y_cond=y,
                                           z_cond=z)
                        self.peak_list_dict[z][y][x] = ''

                    elif not self.variables["experimental_dataset"][z][y][x]:
                        pl = PeakListLabel(self,
                                           'Drop peaklist here',
                                           self.scene, [pl_pos, xx_vertical],
                                           x_cond=x,
                                           y_cond=y,
                                           z_cond=z)
                        self.peak_list_dict[z][y][x] = ''

                    else:
                        pl_name = self.variables["experimental_dataset"][z][y][
                            x]
                        pl = PeakListLabel(self,
                                           pl_name,
                                           self.scene, [pl_pos, xx_vertical],
                                           x_cond=x,
                                           y_cond=y,
                                           z_cond=z,
                                           peak_list=pl_name)
                        self.peak_list_dict[z][y][x] = pl_name
                        self.side_bar()._raise_context_menu(pl_name)

                    self.peak_list_objects.append(pl)
                    self.scene.addItem(pl)
                    self.add_connecting_line(xx, pl)
                    x_markers.append(xx)
                    num += 1
                    xx_vertical += x_spacing

                if len(x_markers) % 2 == 1:
                    yy_vertical = x_markers[int(math.ceil(len(x_markers)) /
                                                2)].y()

                else:
                    yy_vertical = x_markers[int(
                        math.ceil(len(x_markers)) / 2)].y() - (x_spacing / 2)

                yy = ConditionLabel(str(y), [yy_pos, yy_vertical])
                y_markers.append(yy)
                self.scene.addItem(yy)

                for x_marker in x_markers:
                    self.add_connecting_line(yy, x_marker)

            if len(y_markers) % 2 == 1:
                zz_vertical = y_markers[int(math.ceil(len(y_markers)) / 2)].y()

            else:
                zz_vertical = (y_markers[0].y() + y_markers[-1].y()) / 2

            zz = ConditionLabel(str(z), [zz_pos, zz_vertical])
            self.scene.addItem(zz)

            for x_marker in y_markers:
                self.add_connecting_line(zz, x_marker)

        self.updateClicks += 1
        self.variables["experimental_dataset"] = self.peak_list_dict

    def add_connecting_line(self, atom1, atom2):

        if atom1.y() > atom2.y():
            y1 = atom1.y() + (atom1.boundingRect().height() * .5)
            y2 = atom2.y() + (atom2.boundingRect().height() * .5)

        elif atom1.y() < atom2.y():
            y1 = atom1.y() + (atom1.boundingRect().height() * .5)
            y2 = atom2.y() + (atom2.boundingRect().height() * .5)

        else:
            y1 = atom1.y() + (atom1.boundingRect().height() * 0.5)
            y2 = atom2.y() + (atom2.boundingRect().height() * 0.5)

        if atom1.x() > atom2.x():
            x1 = atom1.x()
            x2 = atom2.x() + atom2.boundingRect().width()

        elif atom1.x() < atom2.x():
            x1 = atom1.x() + atom1.boundingRect().width()
            x2 = atom2.x()

        else:
            x1 = atom1.x() + (atom1.boundingRect().width() / 2)
            x2 = atom2.x() + (atom1.boundingRect().width() / 2)

        new_line = QGraphicsLineItem(x1, y1, x2, y2)
        pen = QtGui.QPen()
        pen.setColor(QtGui.QColor("#FAFAF7"))
        pen.setCosmetic(True)
        pen.setWidth(1)
        new_line.setPen(pen)
        self.scene.addItem(new_line)
예제 #12
0
class TabWidget(QTabWidget):
    """
    The container for all tab widgets in the Farseer-NMR GUI.

    To add a new tab to the tab widget, the QWidget class of the needs to be
    imported into this file. The instantiation of the class and the addition
    of the QWidget to the TabWidget need to be coded in the add_tabs_to_widget
    method.

    Parameters:
        gui_settings (dict): a dictionary carrying the settings required to
            correctly render the graphics based on screen resolution.

    Methods:
        .add_tabs_to_widget()
        .set_data_sets()
        .add_tab(QWidget, str, str)
        .load_config(str)
        .load_variables()
        .load_peak_lists(str)
        .save_config(str)
        .run_farseer_calculation
    """
    variables = Variables()._vars

    def __init__(self, gui_settings):
        QTabWidget.__init__(self, parent=None)

        self.widgets = []
        self.gui_settings = gui_settings
        self._add_tab_logo()
        self.add_tabs_to_widget()

    def add_tabs_to_widget(self):
        """
        Create instances of all widget classes and add them to the TabWidget
        """
        self.peaklist_selection = \
            PeaklistSelection(self, gui_settings=self.gui_settings, footer=False)
        self.interface = Settings(self,
                                  gui_settings=self.gui_settings,
                                  footer=True)
        self.add_tab(self.peaklist_selection, "PeakList Selection")
        self.add_tab(self.interface, "Settings", "Settings")
        self.widgets.extend([self.peaklist_selection, self.interface])

    def set_data_sets(self):
        """Set data in the tabs if they have data_sets as an attribute"""
        for widget in self.widgets:
            if hasattr(widget, 'set_data_sets'):
                widget.set_data_sets()

    def add_tab(self, widget, name, object_name=None):
        """Re-implemented of the addTab method to ensure proper compatibility
        with the stylesheet and architecture.
        """
        tab = QWidget()
        tab.setLayout(QGridLayout())
        tab.layout().addWidget(widget)
        self.addTab(tab, name)

        if object_name:
            tab.setObjectName(object_name)

    def load_config(self, path=None):
        """
        Connection from Tab footer to TabWidget for loading Farseer-NMR
        configuration files.
        """
        if not path:
            fname = QFileDialog.getOpenFileName(None, 'Load Configuration',
                                                os.getcwd())

        else:
            fname = [path]

        if fname[0]:
            if fname[0].split('.')[1] == 'json':
                Variables().read(fname[0])
                self.load_variables()
                self.config_file = fname[0]

        return

    def load_variables(self):
        """Load variables into self.variables instance."""
        self.interface.load_variables()
        self.peaklist_selection.load_variables()
        self.peaklist_selection.side_bar.update_from_config()

    def load_peak_lists(self, path=None):
        """Load peaklists into sidebar. Called from self.load_variables."""
        if os.path.exists(path):
            self.peaklist_selection.side_bar.load_from_path(path)

    def save_config(self, path=None):
        """
        Connection from Tab footer to TabWidget for saving Farseer-NMR
        configuration files.
        """
        self.interface.save_config()

        if not path:
            filters = "JSON files (*.json)"
            selected_filter = "JSON files (*.json)"
            fname = QFileDialog.getSaveFileName(self, "Save Configuration", "",
                                                filters, selected_filter)
        else:
            fname = [path]

        if not fname[0].endswith('.json'):
            fname = [fname[0] + ".json"]

        if fname[0]:
            with open(fname[0], 'w') as outfile:
                Variables().write(outfile)
                self.config_file = os.path.abspath(fname[0])

        print('Configuration saved to {}'.format(fname[0]))

    def run_farseer_calculation(self):
        """
        Executes Farseer-NMR calculation in its own thread.
        Saves configuration if not already saved.
        Performs necessary checks for execution.
        """

        msg = QMessageBox()
        msg.setStandardButtons(QMessageBox.Ok)
        msg.setIcon(QMessageBox.Warning)

        if not all(x for x in self.variables["conditions"].values()):
            msg.setText('Experimental Series not set up correctly.')
            msg.setInformativeText("""Please ensure that all conditions in the
Peaklist Tree have labels and that all
X axis conditions have a peaklist associated.""")
            msg.exec_()
            return

        from core.Threading import Threading
        output_path = self.variables["general_settings"]["output_path"]
        run_msg = check_input_construction(output_path, self.variables)
        print(run_msg)

        if run_msg in ["Spectra", "Backbone", "Sidechains"]:
            msg.setText("{} Path Exists.".format(run_msg))
            msg.setInformativeText(
                """{} folder already exists in Calculation Output Path.
Calculation cannot be launched.""".format(run_msg))
            msg.exec_()

        elif run_msg == "No dataset":
            msg.setText("No dataset configured.")
            msg.setInformativeText(
                "No Experimental dataset has been created. "
                "Please define an Experimental Dataset Tree and populate it \
with the corresponding peaklist files.")
            msg.exec_()

        elif run_msg == "FASTA file not provided":
            msg.setText("FASTA file not provided.")
            msg.setInformativeText("""The Apply FASTA box is activated.
This calculation requires FASTA files to be
specified for each Y axis condition.""")
            msg.exec_()

        elif run_msg == "No FASTA for peaklist":
            msg.setText("No FASTA for NmrDraw/NmrView peaklists")
            msg.setInformativeText("""You have input NmrView/NmrDraw peaklists.
These require a FASTA file to be specified.
Plase do so in FASTA menu.
Refer to WET#26 for more details.
""")
            msg.exec_()

        elif run_msg == "No populated Tree":
            msg.setText("Tree not completely populated.")
            msg.setInformativeText(
                "There are branches in the Experimental Tree which are \
not populated. Please ensure that all branches have a peaklist assigned.")
            msg.exec_()

        elif run_msg == "Para name not set":
            msg.setText("You have activated Do PRE Analysis")
            msg.setInformativeText(
                """When analysing paramagnetic data, the datapoint names
of the Z axis must be exactly "dia" and "para"
for diamagnetic and paramagnetic datasets, respectively.

We appologise but other words are not accepted.
Please correct the Z names accordingly.
""")
            msg.exec_()

        elif run_msg == "PRE file not provided":
            msg.setText("PRE file not provided.")
            msg.setInformativeText("""The PRE Analysis box is activated.
This calculation requires Theoretical PRE files
to be specified for each Y axis condition.""")
            msg.exec_()

        elif run_msg == "Run":
            create_directory_structure(output_path, self.variables)
            #from core.farseermain import start_logger, read_user_variables, run_farseer
            from core.farseermain import run_farseer
            run_config_name = "user_config_{}.json".format(
                datetime.datetime.now().strftime("%Y%m%d_%H%M%S"))
            config_path = os.path.join(output_path, run_config_name)
            self.save_config(path=config_path)
            Threading(function=run_farseer, args=[config_path])

        else:
            print('Run could not be initiated')

    def _add_tab_logo(self):
        """Add logo to tab header."""
        self.tablogo = QLabel(self)
        self.tablogo.setAutoFillBackground(True)
        self.tablogo.setAlignment(QtCore.Qt.AlignHCenter
                                  | QtCore.Qt.AlignVCenter)
        pixmap = QtGui.QPixmap(
            os.path.join(ICON_DIR, 'icons', 'header-logo.png'))
        self.tablogo.setPixmap(pixmap)
        self.tablogo.setContentsMargins(9, 0, 0, 6)
        self.setCornerWidget(self.tablogo, corner=QtCore.Qt.TopLeftCorner)
        self.setFixedSize(
            QtCore.QSize(self.gui_settings['app_width'],
                         self.gui_settings['app_height']))
예제 #13
0
class SideBar(QTreeWidget):
    """
    A QTreeWidget that enables drag-and-drop loading and parsing of peaklists.

    Peaklist files are dropped onto the sidebar, their format is detected and
    they are loaded into Farseer-NMR identified by the file name. The labels in
    the sidebar point to in memory representations of the peaklists, which are
    parsed out when a calculation is executed.


    Parameters:
        parent (QWidget):
        gui_settings (dict): a dictionary carrying the settings required to
            correctly render the graphics based on screen resolution.

    Methods:
        .update_from_config()
        .dragEnterEvent(QMouseEvent)
        .dropEvent(QMouseEvent)
        .load_from_path(str)
        .refresh_sidebar()
        .load_peaklist(str)
        .add_item(str)
        ._raise_context_menu(str)
        """
    variables = Variables()._vars

    def __init__(self, parent=None, gui_settings=None):
        QTreeWidget.__init__(self, parent)
        self.header().hide()
        self.setDragEnabled(True)
        self.setExpandsOnDoubleClick(False)
        self.setDragDropMode(self.InternalMove)
        self.acceptDrops()
        self.setMinimumWidth(200)
        self.setMaximumWidth(320)
        self.setFixedHeight(gui_settings['sideBar_height'])
        self.peakLists = self.variables['peaklists']
        self.setSortingEnabled(True)
        self.update_from_config()

    def update_from_config(self):
        """Update sidebar contents based on configuration file."""
        self.clear()
        used_peaklists = []
        self.peakLists = self.variables["peaklists"]

        if not all(x for v in self.variables["conditions"].values()
                   for x in v):
            self.refresh_sidebar()

        else:
            for z in self.variables["conditions"]["z"]:
                for y in self.variables["conditions"]["y"]:
                    for x in self.variables["conditions"]["x"]:
                        used_peaklists.append(
                            self.variables["experimental_dataset"][z][y][x])

            unused_peaklists = \
                [x for x, pl in self.variables["peaklists"].items() if x not in used_peaklists]

            for peaklist in unused_peaklists:
                self.add_item(peaklist)

    def dragEnterEvent(self, event):
        """Re-implemenation for drag-and-drop behaviour."""
        event.accept()

        if not event.mimeData().hasUrls():

            item = self.itemAt(event.pos())

            if not item:
                return

            text = item.text(0)
            event.mimeData().setText(text)

    def dropEvent(self, event):
        """Re-implemenation for drag-and-drop behaviour."""
        if event.mimeData().hasUrls():
            event.accept()
            file_paths = [url.path() for url in event.mimeData().urls()]

            for file_path in file_paths:
                self.load_from_path(file_path)

    def load_from_path(self, file_path):
        """load a peaklists from a directory path."""
        name = None

        if os.path.isdir(file_path):
            for root, dirs, filenames in os.walk(file_path):
                for filename in filenames:
                    try:
                        path = os.path.join(root, filename)
                        name, path = self.load_peaklist(path)

                    except IOError:
                        pass

        else:
            name, path = self.load_peaklist(file_path)

        if name:
            return name, path

    def refresh_sidebar(self):
        """ clear the sidebar and refresh the peaklist names."""
        self.clear()

        for peaklist in self.peakLists.keys():
            self.add_item(peaklist)

    def load_peaklist(self, file_path):
        """load individual peaklist from a file path."""

        if os.path.isdir(file_path):
            return

        name = os.path.basename(file_path)

        if name not in self.peakLists.keys():
            peaklist = read_peaklist(file_path)

            if peaklist:
                pl_name = name

                if peaklist[0].format_ in peaklist_format_requires_fasta:
                    msg = QMessageBox()
                    msg.setIcon(QMessageBox.Warning)
                    msg.setText("Peaklist with no residue type information")
                    msg.setInformativeText(
                        """This peaklist doesn't contain information residue types.

Please ensure to select an approriate FASTA file
in the correct Y axis condition.

Refer to WET#26 for more details.""")
                    msg.setWindowTitle("Duplicate conditions")
                    msg.setStandardButtons(QMessageBox.Ok)
                    msg.exec_()

                item = self.add_item(pl_name)
                self.peakLists[item.text(0)] = peaklist
                self.peakLists[pl_name] = file_path

                return pl_name, file_path

            else:
                #print("*** File not loaded into SideBar\n***")
                return None, None

        else:
            print('Peaklist with name %s already exists.' % name)
            return None, None

    def add_item(self, name):
        """Add a peaklist pointer to the side bar as a QTreeWidgetItem."""
        newItem = QTreeWidgetItem(self)
        newItem.setFlags(newItem.flags() & ~QtCore.Qt.ItemIsDropEnabled)
        newItem.setText(0, name)
        self.sortByColumn(0, QtCore.Qt.AscendingOrder)

        return newItem

    def _raise_context_menu(self, item_name):
        """raise a context menu to enabled deletion of objects."""
        import sip
        result = self.findItems(item_name, QtCore.Qt.MatchRecursive, 0)

        if result:
            sip.delete(result[0])