def __init__(self, working_dir, calibration_model=None, jcpds_phase=None):
        """
        :param working_dir: dictionary of working directories
        :param calibration_model: Reference to CalibrationData object
        :param jcpds_phase: Reference to JcpdsPhase object

        :type calibration_model: CalibrationModel
        :type jcpds_phase: jcpds
        """
        super(JcpdsEditorController, self).__init__()
        self.widget = JcpdsEditorWidget()
        self.working_dir = working_dir
        self.calibration_model = calibration_model
        self.active = False
        self.create_connections()
        if jcpds_phase is not None:
            self.show_phase(jcpds_phase)
class JcpdsEditorController(QtCore.QObject):
    """
    JcpdsEditorController handles all the signals and changes associated with Jcpds editor widget
    """
    canceled_editor = QtCore.pyqtSignal(jcpds)
    lattice_param_changed = QtCore.pyqtSignal()
    eos_param_changed = QtCore.pyqtSignal()

    reflection_line_edited = QtCore.pyqtSignal()
    reflection_line_added = QtCore.pyqtSignal()
    reflection_line_removed = QtCore.pyqtSignal(int)
    reflection_line_cleared = QtCore.pyqtSignal()

    phase_modified = QtCore.pyqtSignal()

    def __init__(self, working_dir, calibration_model=None, jcpds_phase=None):
        """
        :param working_dir: dictionary of working directories
        :param calibration_model: Reference to CalibrationData object
        :param jcpds_phase: Reference to JcpdsPhase object

        :type calibration_model: CalibrationModel
        :type jcpds_phase: jcpds
        """
        super(JcpdsEditorController, self).__init__()
        self.widget = JcpdsEditorWidget()
        self.working_dir = working_dir
        self.calibration_model = calibration_model
        self.active = False
        self.create_connections()
        if jcpds_phase is not None:
            self.show_phase(jcpds_phase)

    def show_phase(self, jcpds_phase=None, wavelength=None):
        self.start_jcpds_phase = deepcopy(jcpds_phase)
        self.jcpds_phase = jcpds_phase
        if wavelength is None:
            if self.calibration_model is not None:
                wavelength = self.calibration_model.wavelength * 1e10
        self.widget.show_jcpds(jcpds_phase, wavelength)

    def update_phase_view(self, jcpds_phase):
        if self.calibration_model is None:
            wavelength = None
        else:
            wavelength = self.calibration_model.wavelength * 1e10
        self.widget.show_jcpds(jcpds_phase, wavelength=wavelength)

    def update_view(self):
        self.jcpds_phase.compute_v0()
        self.jcpds_phase.compute_d0()
        self.jcpds_phase.compute_d()
        self.update_phase_view(self.jcpds_phase)

    def show_view(self):
        self.active = True
        self.widget.raise_widget()

    def close_view(self):
        self.active = False
        self.widget.close()

    def create_connections(self):

        self.phase_modified.connect(self.update_filename)

        self.widget.comments_txt.editingFinished.connect(self.comments_changed)

        self.widget.symmetry_cb.currentIndexChanged.connect(self.symmetry_changed)

        self.widget.lattice_a_sb.valueChanged.connect(self.lattice_a_changed)
        self.widget.lattice_b_sb.valueChanged.connect(self.lattice_b_changed)
        self.widget.lattice_c_sb.valueChanged.connect(self.lattice_c_changed)

        self.widget.lattice_ab_sb.valueChanged.connect(self.lattice_ab_changed)
        self.widget.lattice_ca_sb.valueChanged.connect(self.lattice_ca_changed)
        self.widget.lattice_cb_sb.valueChanged.connect(self.lattice_cb_changed)

        self.widget.lattice_alpha_sb.valueChanged.connect(self.lattice_alpha_changed)
        self.widget.lattice_beta_sb.valueChanged.connect(self.lattice_beta_changed)
        self.widget.lattice_gamma_sb.valueChanged.connect(self.lattice_gamma_changed)

        self.widget.lattice_length_step_txt.editingFinished.connect(self.lattice_length_step_changed)
        self.widget.lattice_angle_step_txt.editingFinished.connect(self.lattice_angle_step_changed)
        self.widget.lattice_ratio_step_txt.editingFinished.connect(self.lattice_ratio_step_changed)

        self.widget.eos_K_txt.editingFinished.connect(self.eos_K_changed)
        self.widget.eos_Kp_txt.editingFinished.connect(self.eos_Kp_changed)
        self.widget.eos_alphaT_txt.editingFinished.connect(self.eos_alphaT_changed)
        self.widget.eos_dalphadT_txt.editingFinished.connect(self.eos_dalphadT_changed)
        self.widget.eos_dKdT_txt.editingFinished.connect(self.eos_dKdT_changed)
        self.widget.eos_dKpdT_txt.editingFinished.connect(self.eos_dKpdT_changed)

        self.widget.reflections_delete_btn.clicked.connect(self.reflections_delete_btn_click)
        self.widget.reflections_add_btn.clicked.connect(self.reflections_add_btn_click)
        self.widget.reflections_clear_btn.clicked.connect(self.reflections_clear_btn_click)

        self.widget.reflection_table.cellChanged.connect(self.reflection_table_changed)

        self.widget.reflection_table.keyPressEvent = self.reflection_table_key_pressed

        self.widget.reflection_table.verticalScrollBar().valueChanged.connect(self.reflection_table_scrolled)

        self.previous_header_item_index_sorted = None
        self.widget.reflection_table.horizontalHeader().sectionClicked.connect(self.horizontal_header_clicked)

        self.widget.save_as_btn.clicked.connect(self.save_as_btn_clicked)
        self.widget.reload_file_btn.clicked.connect(self.reload_file_btn_clicked)
        self.widget.ok_btn.clicked.connect(self.ok_btn_clicked)
        self.widget.cancel_btn.clicked.connect(self.cancel_btn_clicked)

        self.widget.closeEvent = self.view_closed

    def update_filename(self):
        self.widget.filename_txt.setText(self.jcpds_phase.filename)

    def comments_changed(self):
        self.jcpds_phase.comments[0] = str(self.widget.comments_txt.text())
        self.phase_modified.emit()

    def symmetry_changed(self):
        new_symmetry = str(self.widget.symmetry_cb.currentText()).upper()
        self.jcpds_phase.symmetry = new_symmetry
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_a_changed(self):
        self.jcpds_phase.a0 = float(self.widget.lattice_a_sb.value())
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_b_changed(self):
        self.jcpds_phase.b0 = float(self.widget.lattice_b_sb.value())
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_c_changed(self):
        self.jcpds_phase.c0 = float(self.widget.lattice_c_sb.value())
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_ab_changed(self):
        ab_ratio = float(self.widget.lattice_ab_sb.value())
        self.jcpds_phase.a0 = self.jcpds_phase.b0 * ab_ratio
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_ca_changed(self):
        ca_ratio = float(self.widget.lattice_ca_sb.value())
        self.jcpds_phase.c0 = self.jcpds_phase.a0 * ca_ratio
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_cb_changed(self):
        cb_ratio = float(self.widget.lattice_cb_sb.value())
        self.jcpds_phase.c0 = self.jcpds_phase.b0 * cb_ratio
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_alpha_changed(self):
        self.jcpds_phase.alpha0 = float(self.widget.lattice_alpha_sb.value())
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_beta_changed(self):
        self.jcpds_phase.beta0 = float(self.widget.lattice_beta_sb.value())
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()

    def lattice_gamma_changed(self):
        self.jcpds_phase.gamma0 = float(self.widget.lattice_gamma_sb.value())
        self.update_view()
        self.phase_modified.emit()
        self.lattice_param_changed.emit()


    def lattice_length_step_changed(self):
        value = float(str(self.widget.lattice_length_step_txt.text()))
        self.widget.lattice_a_sb.setSingleStep(value)
        self.widget.lattice_b_sb.setSingleStep(value)
        self.widget.lattice_c_sb.setSingleStep(value)

    def lattice_angle_step_changed(self):
        value = float(str(self.widget.lattice_angle_step_txt.text()))
        self.widget.lattice_alpha_sb.setSingleStep(value)
        self.widget.lattice_beta_sb.setSingleStep(value)
        self.widget.lattice_gamma_sb.setSingleStep(value)

    def lattice_ratio_step_changed(self):
        value = float(str(self.widget.lattice_ratio_step_txt.text()))
        self.widget.lattice_ab_sb.setSingleStep(value)
        self.widget.lattice_ca_sb.setSingleStep(value)
        self.widget.lattice_cb_sb.setSingleStep(value)

    def eos_K_changed(self):
        self.jcpds_phase.k0 = float(str(self.widget.eos_K_txt.text()))
        self.update_view()
        self.eos_param_changed.emit()
        self.phase_modified.emit()

    def eos_Kp_changed(self):
        self.jcpds_phase.k0p0 = float(str(self.widget.eos_Kp_txt.text()))
        self.update_view()
        self.eos_param_changed.emit()
        self.phase_modified.emit()

    def eos_alphaT_changed(self):
        self.jcpds_phase.alpha_t0 = float(str(self.widget.eos_alphaT_txt.text()))
        self.update_view()
        self.eos_param_changed.emit()
        self.phase_modified.emit()

    def eos_dalphadT_changed(self):
        self.jcpds_phase.d_alpha_dt = float(str(self.widget.eos_dalphadT_txt.text()))
        self.update_view()
        self.eos_param_changed.emit()
        self.phase_modified.emit()

    def eos_dKdT_changed(self):
        self.jcpds_phase.dk0dt = float(str(self.widget.eos_dKdT_txt.text()))
        self.update_view()
        self.eos_param_changed.emit()
        self.phase_modified.emit()

    def eos_dKpdT_changed(self):
        self.jcpds_phase.dk0pdt = float(str(self.widget.eos_dKpdT_txt.text()))
        self.update_view()
        self.eos_param_changed.emit()
        self.phase_modified.emit()

    def reflections_delete_btn_click(self):
        rows = self.widget.get_selected_reflections()
        if rows is None:
            return

        rows.sort()
        rows = np.array(rows)
        for ind in range(len(rows)):
            self.widget.remove_reflection_from_table(rows[ind])
            self.jcpds_phase.remove_reflection(rows[ind])
            self.reflection_line_removed.emit(rows[ind])
            rows = rows - 1
        self.widget.reflection_table.resizeColumnsToContents()
        self.widget.reflection_table.verticalHeader().setResizeMode(QtGui.QHeaderView.Fixed)
        self.update_filename()
        self.phase_modified.emit()

    def reflections_add_btn_click(self):
        self.jcpds_phase.add_reflection()
        self.widget.add_reflection_to_table(0., 0., 0., 0., 0., 0., 0., 0.)
        self.widget.reflection_table.selectRow(self.widget.reflection_table.rowCount() - 1)
        self.reflection_line_added.emit()
        self.phase_modified.emit()

    def reflection_table_changed(self, row, col):
        label_item = self.widget.reflection_table.item(row, col)
        if label_item.text() != '':
            value = float(str(label_item.text()))
            if col == 0:  # h
                self.jcpds_phase.reflections[row].h = value
            elif col == 1:  # k
                self.jcpds_phase.reflections[row].k = value
            elif col == 2:  # l
                self.jcpds_phase.reflections[row].l = value
            elif col == 3:  # intensity
                self.jcpds_phase.reflections[row].intensity = value

        self.update_view()
        self.widget.reflection_table.resizeColumnsToContents()
        self.reflection_line_edited.emit()

    def reflection_table_key_pressed(self, key_press_event):
        if key_press_event == QtGui.QKeySequence.Copy:
            res = ''
            selection_ranges = self.widget.reflection_table.selectedRanges()
            for range_ind in range(len(selection_ranges)):
                if range_ind > 0:
                    res += '\n'
                for row_ind in range(int(selection_ranges[range_ind].rowCount())):
                    if row_ind > 0:
                        res += '\n'
                    for col_ind in range(selection_ranges[range_ind].columnCount()):
                        if col_ind > 0:
                            res += '\t'
                        res += str(self.widget.reflection_table.item(
                            selection_ranges[range_ind].topRow() + row_ind,
                            selection_ranges[range_ind].leftColumn() + col_ind).text())
            QtGui.QApplication.clipboard().setText(res)
        elif key_press_event == QtGui.QKeySequence.SelectAll:
            self.widget.reflection_table.selectAll()

    def reflections_clear_btn_click(self):
        self.widget.reflection_table.clearContents()
        self.widget.reflection_table.setRowCount(0)
        self.widget.reflection_table.resizeColumnsToContents()
        self.jcpds_phase.reflections = []
        self.reflection_line_cleared.emit()
        self.phase_modified.emit()

    def reflection_table_scrolled(self):
        self.widget.reflection_table.resizeColumnsToContents()

    def horizontal_header_clicked(self, ind):

        if self.previous_header_item_index_sorted == ind:
            reversed = True
        else:
            reversed = False

        if ind == 0:
            self.jcpds_phase.sort_reflections_by_h(reversed)
        elif ind == 1:
            self.jcpds_phase.sort_reflections_by_k(reversed)
        elif ind == 2:
            self.jcpds_phase.sort_reflections_by_l(reversed)
        elif ind == 3:
            self.jcpds_phase.sort_reflections_by_intensity(reversed)
        elif ind == 4 or ind == 6:
            self.jcpds_phase.sort_reflections_by_d(reversed)
        elif ind == 5 or ind == 7:
            self.jcpds_phase.sort_reflections_by_d(not reversed)

        self.widget.show_jcpds(self.jcpds_phase, wavelength=self.calibration_model.wavelength * 1e10)
        self.widget.reflection_table.resizeColumnsToContents()

        if self.previous_header_item_index_sorted == ind:
            self.previous_header_item_index_sorted = None
        else:
            self.previous_header_item_index_sorted = ind

    def save_as_btn_clicked(self, filename=False):
        if filename is False:
            filename = str(QtGui.QFileDialog.getSaveFileName(self.widget, "Save JCPDS phase.",
                                                             self.working_dir['phase'],
                                                             ('JCPDS Phase (*.jcpds)')))

        if filename != '':
            self.jcpds_phase.save_file(filename)
            self.show_phase(self.jcpds_phase)
            self.lattice_param_changed.emit()
            self.phase_modified.emit()

    def reload_file_btn_clicked(self):
        self.jcpds_phase.reload_file()
        self.canceled_editor.emit(self.jcpds_phase)
        self.phase_modified.emit()
        self.show_phase(self.jcpds_phase)

    def ok_btn_clicked(self):
        self.close_view()

    def cancel_btn_clicked(self):
        self.widget.close()
        self.jcpds_phase = deepcopy(self.start_jcpds_phase)
        self.canceled_editor.emit(self.jcpds_phase)
        self.phase_modified.emit()

    def view_closed(self, _):
        self.close_view()