class TrialsPlotWindow(BaseWidget):
    """ Show all boxes live state for an experiment"""

    EVENTS_TO_SHOW = [StateOccurrence, EventOccurrence]

    def __init__(self, session):
        """
        :param session: session reference
        :type session: pycontrolgui.windows.detail.entities.session_window.SessionWindow
        """
        BaseWidget.__init__(self, session.name)
        self.session = session

        self._refreshbtn = ControlButton('Refresh Timeline')
        self._list = ControlCheckBoxList('Events to show')
        self._events = ControlEventsGraph(session.name)

        self._list.hide()
        self._events.add_popup_menu_option('Show / Hide Events',
                                           self.__toggle_events_to_show_evt)
        self._events.add_track('')
        # for state_id, state_name in sorted(self.session.setup.board_task.states.items(), key=lambda x: x[0]):
        #	self._events.add_track(state_name)

        self._history_index = 0
        self._last_event = None
        self._session_start_timestamp = datetime_now.now()

        self.formset = ['_refreshbtn', '_list', '=', '_events']

        self._list_of_states_colors = [
            '#E0E0E0', '#FFCC99', '#FFFF99', 'CCFF99', '#99FFFF', '#99CCFF',
            '#FF99CC'
        ]

        self._states_names = {}

        self._timer = QTimer()
        self._timer.timeout.connect(self.read_message_queue)

        self._refreshbtn.value = self.__refresh_evt
        self._list.value = [(evt_type.__name__, True)
                            for evt_type in self.EVENTS_TO_SHOW]
        self._list.changed_event = self.__list_changed_evt

        self._available_events = dict([(evt_type.__name__, evt_type)
                                       for evt_type in self.EVENTS_TO_SHOW])

        self.__list_changed_evt()

    def __refresh_evt(self):
        """Clears the entire timeline and re-draws all the checked events from T = 0 """
        self._events.clear()
        self._history_index = 0
        self.read_message_queue()

    def __list_changed_evt(self):
        self._events_2_draw = tuple([
            self._available_events[event_name]
            for event_name in self._list.value
        ] + [SessionInfo])

    def __toggle_events_to_show_evt(self):
        if self._list.visible:
            self._list.hide()
        else:
            self._list.show()

    def show(self):
        # Prevent the call to be recursive because of the mdi_area
        if hasattr(self, '_show_called'):
            BaseWidget.show(self)
            return
        self._show_called = True
        self.mainwindow.mdi_area += self
        del self._show_called

        self._stop = False  # flag used to close the gui in the middle of a loading
        self.read_message_queue()
        if not self._stop:
            self._timer.start(conf.TIMELINE_PLUGIN_REFRESH_RATE)

    def hide(self):
        self._timer.stop()
        self._stop = True

    def before_close_event(self):
        self._timer.stop()
        self._stop = True
        self.session.trialsplot_action.setEnabled(True)

    def __add_event(self, start_timestamp, end_timestamp, track_id, name):

        self._last_event = self._events.add_event(
            start_timestamp,
            end_timestamp,
            track=track_id,
            title=name,
            color=self._list_of_states_colors[track_id % len(
                self._list_of_states_colors)])
        self._events.value = start_timestamp

    def timediff_ms(self, time_f, time_i):
        diff = datetime_now.now()

        diff = time_f - time_i
        elapsed_ms = (diff.days * 86400000) + \
            (diff.seconds * 1000) + (diff.microseconds / 1000)
        return elapsed_ms

    def read_message_queue(self):
        """ Update board queue and retrieve most recent messages """

        try:
            recent_history = self.session.messages_history[self.
                                                           _history_index:]

            for message in recent_history:

                if self._stop:
                    return

                if not isinstance(message, self._events_2_draw):
                    continue

                if isinstance(message, StateOccurrence):
                    if message.state_name not in self._states_names.keys():
                        self._states_names[message.state_name] = len(
                            self._states_names)

                    if not (math.isnan(message.start_timestamp)
                            or math.isnan(message.end_timestamp)):
                        bpod_start = int(round(message.start_timestamp * 1000))
                        bpod_end = int(round(message.end_timestamp * 1000))
                        self.__add_event(
                            bpod_start, bpod_end,
                            self._states_names[message.state_name],
                            message.state_name)

                elif isinstance(message, SessionInfo):
                    if message.content == 'SESSION-STARTED':
                        self._session_start_timestamp = message.pc_timestamp

                elif isinstance(message, EventOccurrence):
                    ts = None  # in case we don't find any valid timestamp, don't add the event to the timeline
                    # check which timestamp will be used. host timestamp wins over pc timestamp

                    if message.pc_timestamp is not None:
                        ts = self.timediff_ms(message.pc_timestamp,
                                              self._session_start_timestamp)

                    # proceed if we have a valid timestamp
                    if ts is not None:
                        # create a new event slot in the timeline in case current message is entirely new
                        if message.event_name not in self._states_names.keys():
                            self._states_names[message.event_name] = len(
                                self._states_names)
                        # add a time delta to ts so the event can be shown in the timeline
                        self.__add_event(
                            ts - 10, ts + 10,
                            self._states_names[message.event_name],
                            message.event_name)

                self._history_index += 1
                QEventLoop()

        except RunSetupError as err:
            logger.error(str(err), exc_info=True)
            self._timer.stop()

    @property
    def mainwindow(self):
        return self.session.mainwindow

    @property
    def title(self):
        return BaseWidget.title.fget(self)

    @title.setter
    def title(self, value):
        title = 'Trials-plot: {0}'.format(value)
        BaseWidget.title.fset(self, title)
class ExportWindow(BaseWidget):
    def __init__(self, parent=None):
        BaseWidget.__init__(self, 'Export data', parent_win=parent)

        self.set_margin(5)
        self.setMinimumHeight(600)
        self.setMinimumWidth(800)

        self._tree = ControlTree('Data')
        self._apply = ControlButton('Apply', checkable=True)
        self._progress = ControlProgress('Progress')
        self._add = ControlButton('Add')
        self._remove = ControlButton('Remove')
        self._export_list = ControlList('Columns to export')

        self._outdir = ControlDir('Output directory')
        self._outfile = ControlText('Output file name')

        self._toggleevts = ControlCheckBox('Split files by events')
        self._splitevents = ControlCheckBoxList('Events')
        self._evtsreload = ControlButton('Reload events')

        self._formset = [[['_add', '_tree'], '||',
                          ['_remove', '_export_list']], '_toggleevts',
                         '_evtsreload', '_splitevents', '_outdir', '_outfile',
                         '_apply', '_progress']

        self._add.value = self.__add_column_event
        self._remove.value = self.__remove_column_event
        self._apply.value = self.__apply_btn_event
        self._evtsreload.value = self.__reload_events
        self._outdir.changed_event = self.__update_outfile_name_event
        self._outfile.changed_event = self.__update_outfile_name_event
        self._toggleevts.changed_event = self.__toggleevents_visibility
        self._splitevents.changed_event = self.__update_outfile_name_event
        self._splitevents.selection_changed_event = self.__update_outfile_name_event

        self._tree.show_header = False
        self._apply.icon = conf.ANNOTATOR_ICON_MOTION
        self._evtsreload.icon = conf.ANNOTATOR_ICON_REFRESH
        self._add.icon = conf.ANNOTATOR_ICON_ADD
        self._remove.icon = conf.ANNOTATOR_ICON_REMOVE

        self._progress.hide()
        self._splitevents.hide()
        self._evtsreload.hide()
        self._apply.enabled = False

        self._properties = []

    ###########################################################################
    ### EVENTS ################################################################
    ###########################################################################

    def __toggleevents_visibility(self):
        if self._toggleevts.value:
            self._splitevents.show()
            self._evtsreload.show()
        else:
            self._splitevents.hide()
            self._evtsreload.hide()

    def __field_full_name(self, tree_item):
        name = tree_item.text(0)
        while True:
            tree_item = tree_item.parent()
            if tree_item is None: break
            name = "{0} > {1}".format(tree_item.text(0), name)
        return name

    def __add_column_event(self):
        self.__update_outfile_name_event()
        item = self._tree.selected_item

        if item is None:
            return

        if hasattr(item, 'data_function'):
            self._export_list += [self.__field_full_name(item)]
            self._properties.append((len(item.win), item.data_function))
        elif isinstance(item.win, Value):
            self._export_list += [self.__field_full_name(item)]
            self._properties.append((len(item.win), item.win.get_value))

    def __remove_column_event(self):
        self.__update_outfile_name_event()
        if self._export_list.selected_row_index is None:
            return
        elif self._export_list.selected_row_index >= 0:
            self._properties.pop(self._export_list.selected_row_index)
            self._export_list -= -1

    def __update_outfile_name_event(self):
        """
		Update the output filename
		"""
        filename = self._outfile.value
        if len(filename.strip()) == 0: return

        outfilepath, outfile_extension = os.path.splitext(filename)
        names = [outfilepath] if len(outfilepath) > 0 else []

        if len(list(self._splitevents.value)) > 0:
            if '{event}' not in outfilepath: names.append('{event}')
            if '{start}' not in outfilepath: names.append('{start}')
            if '{end}' not in outfilepath: names.append('{end}')

        self._outfile.value = ('-'.join(names) + '.csv')
        self._apply.enabled = True

    def __apply_btn_event(self):

        if self._apply.checked:

            if len(self._properties) == 0:
                QMessageBox.about(
                    self, "Error",
                    "You need to select at least one value to export.")
                self._apply.checked = False
                return

            if self._outfile.value is None or len(
                    self._outfile.value.strip()) == 0:
                QMessageBox.about(
                    self, "Error",
                    "You need to select the name of the output file.")
                self._apply.checked = False
                return

            if self._outdir.value is None or len(self._outdir.value) == 0:
                QMessageBox.about(
                    self, "Error",
                    "You need to select the name of the output directory.")
                self._apply.checked = False
                return

            self.__update_outfile_name_event()

            self._export_list.enabled = False
            self._tree.enabled = False
            self._add.enabled = False
            self._remove.enabled = False
            self._outdir.enabled = False
            self._outfile.enabled = False
            self._apply.label = 'Cancel'

            ### calculate the video cuts #############################
            timeline = self.parent().timeline

            selected_events = self._splitevents.value
            videocuts = []
            if len(selected_events):
                # use the events to cut the video
                totalframes = 0
                for row in timeline.rows:
                    for event in row.events:
                        if event.title not in selected_events: continue
                        b = event.begin
                        e = event.end
                        totalframes += e - b
                        videocuts.append((int(b), int(e), event.title))
                videocuts = sorted(videocuts, key=lambda x: x[0])
            else:
                # no events were selected
                end = max([size for size, func in self._properties])
                totalframes = end
                videocuts = [(0, int(end), None)]
            ##########################################################

            self._progress.min = 0
            self._progress.max = totalframes
            self._progress.show()

            for b, e, eventname in videocuts:

                filename = self._outfile.value
                filename = filename.format(event=eventname, start=b, end=e)
                filename = os.path.join(self._outdir.value, filename)

                with open(filename, 'w') as out:

                    ## write the csv columns headers
                    out.write('frame;')
                    for values in self._export_list.value:
                        out.write(('{0};'.format(values[0])))
                    out.write('\n')

                    ## write the values
                    for index in range(b, e):
                        out.write('{0};'.format(index))
                        for _, func in self._properties:
                            out.write('{0};'.format(func(index)))
                        out.write('\n')
                        self._progress += 1

            self._export_list.enabled = True
            self._tree.enabled = True
            self._add.enabled = True
            self._remove.enabled = True
            self._outdir.enabled = True
            self._outfile.enabled = True
            self._apply.label = 'Apply'
            self._apply.checked = False
            self._progress.hide()

    def __copy_tree_node(self, item, new_item):
        new_item.win = item.win
        if hasattr(item, 'data_function'):
            new_item.data_function = item.data_function

    def __reload_events(self):
        """
		Find all the events available on the timeline
		"""
        timeline = self.parent().timeline
        rows = timeline.rows

        events = {}
        for row in rows:
            for event in row.events:
                events[event.title] = True

        events = sorted(events.keys())

        loaded_events = dict(self._splitevents.items)
        self._splitevents.value = [(e, loaded_events.get(e, False))
                                   for e in events]

    @property
    def project(self):
        return self._project

    @project.setter
    def project(self, value):
        self._project = value
        self._tree.clear()
        self._tree.clone_tree(value.tree, copy_function=self.__copy_tree_node)
        self.__reload_events()
예제 #3
0
class SceneApp(HeatMapApp):
    def __init__(self, title=''):
        self._points_values = None  #used to map a color for each tracking point

        super(SceneApp, self).__init__(title)

        ##### CONTROLS ##############################################################################
        self._scene_file = ControlFile('Scene')
        self._scene_toggle_objs_list = ControlButton('Show/Hide objects',
                                                     checkable=True)
        self._scene_objs_list = ControlCheckBoxList('Objects')
        self._scene_opengl = ControlOpenGL('OpengGL Scene')
        self._scene_points_alfa = ControlSlider('Transparency', 10, 0, 100)
        self._scene_bg_color = ControlCombo('Background color')
        self._scene_apply_colorBnds = ControlButton('Apply colors boundaries')
        self._scene_points_size = ControlCombo('Points size')
        self._scene_obj_color = ControlText('Object color')

        #############################################################################################
        self._modules_tabs.update({
            'Heat map':
            [('_heatmapColor', '   |   ', 'Filters:', '_toggleHeatmapVars',
              '_toggleSphereVisibility', '_sphere', '   |   ',
              '_apply2Heatmap', ' '),
             ('_heatmapVarsList', '_heatmapVars', '_heatmapHigherVarsValues',
              '_heatMapMinVar', '_heatmapVarsBnds', '_heatMapMaxVar'),
             ({
                 '1:Map': ['_heatmap'],
                 '0:Scene':
                 [[('_scene_file', ' ', '_scene_toggle_objs_list', ' ',
                    '_scene_bg_color', '  |  ', '_scene_points_size', '  |  ',
                    '_scene_apply_colorBnds'), '_scene_points_alfa',
                   '_scene_obj_color', '_scene_objs_list'], '=',
                  '_scene_opengl']
             }, '_heatmapColorsBnds')]
        })
        #############################################################################################

        self._scene_bg_color += ('White', '1,1,1,1.0')
        self._scene_bg_color += ('Gray', '0.3,0.3,0.3,1.0')
        self._scene_bg_color += ('Black', 'None')

        self._scene_points_size += '1'
        self._scene_points_size += '3'
        self._scene_points_size += '6'
        self._scene_points_size += '8'

        self._scene_objs_list.hide()
        self._scene_obj_color.hide()

        self._scene_objs_list.changed = self.__changed_objects_list_event
        self._scene_toggle_objs_list.value = self.__toggle_objects_list_event
        self._scene_points_alfa.changed = self.__changed_scene_points_alfa_event
        self._scene_bg_color.changed = self.__changed_background_color_event
        self._scene_apply_colorBnds.value = self.__scene_apply_color_bnds_event
        self._scene_points_size.changed = self.__changed_scene_points_size_event
        self._scene_objs_list.selectionChanged = self.__selectionchanged_object_list_event
        self._scene_obj_color.changed = self.__changed_object_color_event

        self._scene = None
        self._scene_file.changed = self.__scene_file_selected

        self._scene_opengl.clear_color = 1, 1, 1, 1

        #self._scene_file.value 		= '/home/ricardo/Desktop/01Apollo201403210900/01Apollo201403210900_Scenario.obj'

    def initForm(self):
        super(SceneApp, self).initForm()
        #self._splitters[0].setStretchFactor(0,10)
        #self._splitters[0].setStretchFactor(1,90)

    ############################################################################################
    ### EVENTS #################################################################################
    ############################################################################################

    def __changed_object_color_event(self):
        index = self._scene_objs_list.mouseSelectedRowIndex
        self._scene.objects[index].color = eval(self._scene_obj_color.value)
        self._scene_opengl.repaint()

    def __selectionchanged_object_list_event(self):
        index = self._scene_objs_list.mouseSelectedRowIndex
        self._scene_obj_color.value = str(self._scene.objects[index].color)
        self._scene_obj_color.label = 'Object color ({0})'.format(
            self._scene.objects[index].name)

    def __changed_scene_points_size_event(self):
        self._scene.points_size = eval(self._scene_points_size.value)
        self._scene_opengl.repaint()

    def __toggle_objects_list_event(self):
        if self._scene_toggle_objs_list.checked:
            self._scene_objs_list.show()
            self._scene_obj_color.show()
        else:
            self._scene_objs_list.hide()
            self._scene_obj_color.hide()

    def __changed_background_color_event(self):
        self._scene_opengl.clear_color = eval(self._scene_bg_color.value)

    def __changed_scene_points_alfa_event(self):
        if self._points_values != None:
            self._scene.colors = self.__gen_colors(self._points_values.copy())
            self._scene_opengl.repaint()

    def __changed_objects_list_event(self):
        x, y, z = 0.0, 0.0, 0.0
        count = 0.0

        for obj in self._scene.objects:
            obj.active = obj.name in self._scene_objs_list.value
            obj.draw_faces = True

            if obj.active:
                for point in obj.points:
                    x += point[0]
                    y += point[1]
                    z += point[2]
                    count += 1.0

        if count == 0.0: count = 1.0
        self._scene._center = x / count, y / count, z / count
        self._scene_opengl.repaint()

    def __scene_file_selected(self):
        if len(self._scene_file.value) == 0: return

        self._scene = CustomScene()
        w = WavefrontOBJReader(self._scene_file.value)
        self._scene.objects = w.objects

        self._scene_opengl.value = self._scene
        self._scene_objs_list.clear()
        for obj in self._scene.objects:
            self._scene_objs_list += (obj.name, True)

    def __gen_colors(self, values):
        if len(values) == 0: return []
        if self._heatmapColor.value == vv.CM_BONE: func = 'bone'
        if self._heatmapColor.value == vv.CM_COOL: func = 'cool'
        if self._heatmapColor.value == vv.CM_COPPER: func = 'copper'
        if self._heatmapColor.value == vv.CM_GRAY: func = 'gray'
        if self._heatmapColor.value == vv.CM_HOT: func = 'hot'
        if self._heatmapColor.value == vv.CM_HSV: func = 'hsv'
        if self._heatmapColor.value == vv.CM_PINK: func = 'pink'
        if self._heatmapColor.value == vv.CM_JET: func = 'jet'
        if self._heatmapColor.value == vv.CM_AUTUMN: func = 'autumn'
        if self._heatmapColor.value == vv.CM_SPRING: func = 'spring'
        if self._heatmapColor.value == vv.CM_SUMMER: func = 'summer'
        if self._heatmapColor.value == vv.CM_WINTER: func = 'winter'

        normalized_vals = np.float32(values) / np.float32(values).max()
        normalized_vals = normalized_vals - normalized_vals.min()
        maximum = normalized_vals.max()

        func = getattr(cm, func)
        colors = []

        alpha = float(self._scene_points_alfa.value) / 100.0

        for v in normalized_vals:
            color = func(v / maximum)
            colors.append((color[0], color[1], color[2], alpha))

        return colors

    def __scene_apply_color_bnds_event(self):
        self._scene_apply_colorBnds.form.setStyleSheet("")
        if self._heatmapImg is None or not self._heatmapImg.any(): return

        lower, higher = self._heatmapColorsBnds.value
        a = self._points_values.copy()
        a[a < lower] = lower
        a[a > higher] = higher
        self._scene.colors = self.__gen_colors(a)

    def changed_heatmap_colors_bounds_event(self):
        super(SceneApp, self).changed_heatmap_colors_bounds_event()
        self._scene_apply_colorBnds.form.setStyleSheet("color: red")

    def changed_heatmap_color_event(self):
        super(SceneApp, self).changed_heatmap_color_event()

        if self._points_values != None:
            self._scene.colors = self.__gen_colors(self._points_values.copy())
            self._scene_opengl.repaint()

    def calculate_heatmap_event(self):
        super(SceneApp, self).calculate_heatmap_event()

        if self._scene:
            #Filter for the data from a lower and upper frame
            self._progress.min = lower = 0 if self._boundings.value[
                0] < 0 else int(self._boundings.value[0])
            self._progress.max = higher = len(
                self._data) if self._boundings.value[1] > (
                    len(self._data) + 1) else int(self._boundings.value[1])

            #Calculate the size of the map
            x_diff = self._data.xRange[1] - self._data.xRange[0]
            y_diff = self._data.yRange[1] - self._data.yRange[0]
            z_diff = self._data.zRange[1] - self._data.zRange[0]
            scale = self.fit_scale(x_diff, y_diff,
                                   z_diff)  #Fit the best scale value

            try:
                sphere = sphere_x, sphere_y, sphere_z, sphere_r = eval(
                    self._sphere.value)
            except:
                sphere = None
            min_var, max_var = self._heatmapVarsBnds.value
            which_var = 0 if self._heatmapVarsList.value == 'Velocity' else 1

            values = []
            points = []
            for i in range(lower, higher):
                if (i % 3000) == 0: self._progress.value = i
                if self._data[i] != None:
                    x, y, z = position = self._data[i].position

                    x += abs(self._data.xRange[0])
                    y += abs(self._data.yRange[0])
                    z += abs(self._data.zRange[0])
                    x = int(round(x * scale))
                    y = int(round(y * scale))
                    z = int(round(z * scale))

                    #Filter position by a defined sphere
                    if sphere != None and lin_dist3d(
                        (x, y, z), (sphere_x, sphere_y, sphere_z)) > sphere_r:
                        continue

                    #Use variables to construct the map, or positions
                    if self._toggleHeatmapVars.checked:
                        #velocities array has less 1 element than positions array
                        if which_var == 0 and len(self._velocities) <= i:
                            continue
                        #accelarations array has less 2 element than positions array
                        if which_var == 1 and len(self._accelerations) <= i:
                            continue
                        var = self._velocities[
                            i] if which_var == 0 else self._accelerations[i]
                        #Filter by variable boundaries
                        if not (min_var <= var <= max_var): continue

                    values.append(self._heatmapImg[z, x, y])
                    points.append(position)

            self._progress.value = higher

            self._points_values = np.float32(values)
            self._scene.points = points
            self._scene.colors = self.__gen_colors(self._points_values.copy())

            self._scene_apply_colorBnds.form.setStyleSheet("")

            self._scene_opengl.repaint()
예제 #4
0
class GraphApp(BaseApp):
	"""Application form"""

	def __init__(self, title='Variables graphs'):
		super(GraphApp,self).__init__(title)

		self._graph   	  = ControlVisVis("Graph")
		self._toggleVars  = ControlButton('Show/Hide variables', checkable=True)
		self._loadGraph   = ControlButton('Apply')
		self._varsList	  = ControlCheckBoxList('Variables')

		self._varsList += ('Frames',True)
		self._varsList += ('X',True)
		self._varsList += ('Y',True)
		self._varsList += ('Z',False)
		self._varsList += ('Velocity',False)
		self._varsList += ('Acceleration',False)

		self._modules_tabs.update({
			'Graphs': [ 
				('_toggleVars',' '),
				'_varsList',
				'_loadGraph',
				'_graph'],
		})
		
		
		self._loadGraph.value 	= self.__calculate_graph
		self._toggleVars.value = self.__show_hide_variables
		self._varsList.hide()
		self._loadGraph.hide()
	
	def __show_hide_variables(self):
		#Show and hide the variables list
		if self._toggleVars.checked:
			self._varsList.show()
			self._loadGraph.show()
		else:
			self._varsList.hide()
			self._loadGraph.hide()
			
	
	def __calculate_graph(self):
		#Render the graph
		if self._data==None:
			self.warning("Please load the data first.", "The data is missing")
			return

		lower  = 0 if self._boundings.value[0]<0 else self._boundings.value[0]
		higher = len(self._data) if self._boundings.value[1]>(len(self._data)+1) else self._boundings.value[1]

		self._progress.min = lower
		self._progress.max = higher

		values = []
		variables = self._varsList.value

		if len(variables)>3:
			self.warning("Please select the maximum of 3 variables.", "Too many variables selected")
			return

		for i in range(int(lower), int(higher)-2 ):
			self._progress.value = i
			if self._data[i]!=None:
				val = []
				pos = self._data[i].position
					
				if 'Frames' in variables: 		val.append(i)
				if 'X' in variables: 			val.append(pos[0])
				if 'Y' in variables: 			val.append(pos[1])
				if 'Z' in variables: 			val.append(pos[2])
				if 'Velocity' in variables: 	val.append(self._velocities[i])
				if 'Acceleration' in variables: val.append(self._accelerations[i])

				values.append( val )
		
		self._graph.value = [values]
예제 #5
0
class SimpleExample1(BaseWidget):
    def __init__(self):
        super(SimpleExample1, self).__init__(' Thực Tập Cơ Sở ')

        #main menu
        self.mainmenu = [{
            'File': [{
                'Open Excel': self.__open,
                'icon': 'img/folder_open.png'
            }, '-', {
                'Import': self.__import,
                'icon': 'img/import_icon.png'
            }]
        }]

        #tkinler for messagebox
        root = tk.Tk()
        root.withdraw()

        #list
        self._list = ControlList('Danh sách')
        self._list.readonly = True

        #1.open file excel và heap sort
        self._file = ControlFile('Chọn file Excel')
        self._butheapsort = ControlButton('Heap Sort')
        self._butheapsort.icon = 'img/sort_icon.png'
        self._butheapsort.value = self.__heapsort
        self._butloadexcel = ControlButton('Load')
        self._butloadexcel.icon = 'img/load_icon.png'
        self._butloadexcel.value = self.__load
        self._butremoveloadexcel = ControlButton('Hủy bỏ')
        self._butremoveloadexcel.icon = 'img/remove_icon.png'
        self._butremoveloadexcel.value = self.__removeloadexcel

        #2.thêm thửa đất
        self._diachi = ControlText('Địa chỉ')
        self._dientich = ControlText('Diện tích')
        self._chusohuuhientai = ControlText('Chủ sở hữu hiện tại')
        self._loainha = ControlText('Loại nhà')
        self._mucdichsudung = ControlText('Mục đích Sử dụng')
        self._giatien = ControlText('Giá tiền')
        self._but1 = ControlButton('Thêm thửa đất')
        self._but1.value = self.__add
        self._but1.icon = 'img/add_icon.png'

        #3.tìm kiếm thử đất và xóa
        #tìm kiếm
        self._butsearch = ControlButton('Tìm kiếm')
        self._butsearch.icon = 'img/search_icon.png'
        self._butsearch.value = self.__search
        self._timkiem = ControlText('Tìm Kiếm')
        self._checklisttimkiem = ControlCheckBoxList('Chọn tiêu chí tìm kiếm:')
        self._checklisttimkiem.hide()
        self._buttonhideshowtimkiem = ControlButton('Hiển thị tiêu chí')
        self._buttonhideshowtimkiem.value = self._buthideshowtimkiem
        self._buttonhideshowtimkiem.icon = 'img/show.png'
        self._buthuybo = ControlButton('Hủy bỏ')
        self._buthuybo.icon = 'img/remove_icon.png'
        self._buthuybo.value = self._huybo
        #xóa
        self._textxoa = ControlText('Nhập nội dung cần xóa')
        self._butxoa = ControlButton('Xoá')
        self._butxoa.icon = 'img/delete_icon.png'
        self._butxoa.value = self.__xoa
        self._checklistxoa = ControlCheckBoxList('Chọn tiêu chí xóa:')
        self._checklistxoa.hide()
        self._buttonhideshowxoa = ControlButton('Hiển thị tiêu chí')
        self._buttonhideshowxoa.value = self._buthideshowxoa
        self._buttonhideshowxoa.icon = 'img/show.png'

        #4.xuất
        self._directory = ControlDir('Chọn chỗ xuất file excel')
        self._tenfilexuat = ControlText('Tên file xuất')
        self._butxuat = ControlButton('Xuất')
        self._butxuat.icon = 'img/export_icon.png'
        self._butxuat.value = self.__xuat

        #5.merge
        self._filemerge = ControlFile('Chọn file Excel cần merge')
        self._butimport = ControlButton('Import')
        self._butimport.icon = 'img/import2_icon.png'
        self._butimport.value = self._import
        self._butmerge = ControlButton('Gộp')
        self._butmerge.icon = 'img/merge_icon'
        self._butmerge.value = self._merge
        self._butmerge.hide()
        self._listmerge = ControlList('Danh sách import')
        self._listmerge.readonly = True
        self._buttonhideshow = ControlButton('Hiển thị tùy chọn')
        self._buttonhideshow.value = self._buthideshow
        self._buttonhideshow.hide()
        self._buttonhideshow.icon = 'img/show.png'
        self._checklist = ControlCheckBoxList(
            'Chọn tiêu chí giữ trong danh sách import:')
        self._checklist.hide()
        self._buttonremovemerge = ControlButton('Hủy bỏ')
        self._buttonremovemerge.value = self._remove
        self._buttonremovemerge.icon = 'img/remove_icon.png'
        self._buttonremovemerge.hide()

        #formset as layout
        self.formset = [{
            '1.Mở File và Heap Sort': [
                ' ', '_file', ' ',
                (' ', '_butloadexcel', '_butremoveloadexcel', '_butheapsort',
                 ' '), ' '
            ],
            '2.Thêm': [
                ' ', '_diachi', '_dientich', '_chusohuuhientai', '_loainha',
                '_mucdichsudung', '_giatien', ' ', (' ', '_but1', ' '), ' '
            ],
            '3.Tìm kiếm và Xóa': [
                ' ', '_textxoa', ' ',
                (' ', '_butxoa', '_buttonhideshowxoa', '_checklistxoa', ' '),
                ' ', '_timkiem', ' ',
                (' ', '_butsearch', '_buttonhideshowtimkiem',
                 '_checklisttimkiem', '_buthuybo', ' '), ' '
            ],
            '4.Xuất': [
                ' ', '_directory', ' ', '_tenfilexuat', ' ',
                (' ', '_butxuat', ' '), ' '
            ],
            '5.Merge danh sách': [
                '_filemerge',
                (' ', '_butimport', '_butmerge', '_buttonremovemerge',
                 '_buttonhideshow', '_checklist', ' '), '_listmerge'
            ],
        }, '', '', '_list']

#event for mainmenu

    def __open(self):
        self._file.click()

    def __import(self):
        self._filemerge.click()

#event tab 1
#event for _butremoveloadexcel

    def __removeloadexcel(self):
        if not values:
            messagebox.showwarning("Warning", "Không có thông tin cần loại bỏ")
        else:
            values.clear()
            fsqc.clear()
            self._refresh()

    #event for _butheapsort
    def __heapsort(self):
        if self._list.rows_count <= 1:
            messagebox.showwarning("Warning", "không có list để sort")
        else:
            heap_sort()
            self._refresh()

    #event for load button
    def __load(self):
        if not self._file.value:
            tk.messagebox.showwarning("Warning", "Đường dẫn trống")
        else:
            try:
                if self._file.value != '':
                    path = self._file.value
                    read(path)
                    self._list.value = [values_name]
                    n = 0
                    for i in range(int(len(values) / numberofcols[0])):
                        self._list.__add__(values[n:n + numberofcols[0]])
                        n = n + numberofcols[0]
                    if self._checklistxoa.count < 1:
                        for s in range(0, len(values_name)):
                            self._checklistxoa.__add__((values_name[s]))
                    if self._checklisttimkiem.count < 1:
                        for s in range(0, len(values_name)):
                            self._checklisttimkiem.__add__((values_name[s]))
            except:
                tk.messagebox.showwarning(
                    "Warning",
                    "Không thể đọc file khác excel hoặc đường dẫn không đúng")

#event tab 2
#event for thêm button

    def __add(self):
        var = str(self._diachi.value).strip().split(',')
        var2 = var[0].split('/')
        var3 = var2[0]
        if self._list.rows_count < 1:
            messagebox.showwarning("Warning", "Không có list để thêm vào")
        elif len(var3) == 0 \
                or (not var3[0].isdigit() and len(var3)  == 1 ) \
                or ( not var3[0:(len(var3) -1 )].isdigit() and len(var3) > 1 ) :
            messagebox.showwarning("Warning", "Địa chỉ không hợp lệ")
        elif not str(self._dientich.value).strip().isnumeric():
            messagebox.showwarning("Warning", "Diện tích không hợp lệ")
        elif not str(self._chusohuuhientai.value).strip():
            messagebox.showwarning("Warning", "Chủ sở hữu trống")
        elif not str(self._loainha.value).strip():
            messagebox.showwarning("Warning", "loại nhà trống")
        elif not str(self._mucdichsudung.value).strip():
            messagebox.showwarning("Warning", "mục đích sử dụng trống")
        elif not str(self._giatien.value).strip():
            messagebox.showwarning("Warning", "giá tiền trống")
        else:
            index = self._list.rows_count
            values.append(index)
            values.append(str(self._diachi.value))
            values.append(str(self._dientich.value))
            values.append(str(self._chusohuuhientai.value))
            values.append(str(self._loainha.value))
            values.append(str(self._mucdichsudung.value))
            values.append(str(self._giatien.value))
            if var3.isdigit():
                fsqc.append(int(var3[0:(len(var3))]))
            else:
                fsqc.append(int(var3[0:(len(var3) - 1)]))
            heap_sort()
            self._refresh()

#event tab 3
#search  :

    def __search(self):
        if self._list.rows_count <= 1:
            messagebox.showwarning("Warning", "Danh sách rỗng")
        elif not self._timkiem.value:
            messagebox.showwarning("Warning",
                                   "Vui lòng nhập nội dung tìm kiếm")
        elif self._checklisttimkiem.selected_row_index == -1:
            messagebox.showwarning("Warning", "Vui lòng chọn tiêu chí cần xóa")
            self._checklisttimkiem.show()
            self._buttonhideshowtimkiem.icon = 'img/hide_icon.png'
            self._buttonhideshowtimkiem.label = 'Ẩn tiêu chí'
        else:
            self._refresh()
            s = 1
            while s < self._list.rows_count:
                if not (str(self._timkiem.value).strip()) in str(
                        self._list.get_value(
                            self._checklisttimkiem.selected_row_index, s)):
                    self._list.__sub__(s)
                    s = s - 1
                s = s + 1

    def _huybo(self):
        self._refresh()

    def _buthideshowtimkiem(self):
        if not values_name:
            tk.messagebox.showwarning("Warning",
                                      "Không có list để chọn tiêu chí")
        elif str(self._buttonhideshowtimkiem.label) == 'Ẩn tiêu chí':
            self._checklisttimkiem.hide()
            self._buttonhideshowtimkiem.icon = 'img/show.png'
            self._buttonhideshowtimkiem.label = 'Hiển thị tiêu chí'
        elif str(self._buttonhideshowtimkiem.label) == 'Hiển thị tiêu chí':
            self._checklisttimkiem.show()
            self._buttonhideshowtimkiem.icon = 'img/hide_icon.png'
            self._buttonhideshowtimkiem.label = 'Ẩn tiêu chí'

    #delete
    def __xoa(self):
        if self._list.rows_count <= 1:
            messagebox.showwarning("Warning", "Danh sách rỗng")
        elif not self._textxoa.value:
            messagebox.showwarning("Warning", "Vui lòng nhập nội dung cần xóa")
        elif self._checklistxoa.selected_row_index == -1:
            messagebox.showwarning("Warning", "Vui lòng chọn tiêu chí cần xóa")
            self._checklistxoa.show()
            self._buttonhideshowxoa.icon = 'img/hide_icon.png'
            self._buttonhideshowxoa.label = 'Ẩn tiêu chí'
        else:
            result = messagebox.askokcancel('Warning', 'Bạn có chắc muốn xóa?')
            startvaluescount = len(values)
            if result == 1:
                s = 1
                while s < len(values):
                    if (str(self._textxoa.value).strip()) in str(
                            values[s + self._checklistxoa.selected_row_index -
                                   1]):
                        del fsqc[s // 7]
                        del values[(s - 1):(s + 6)]
                        s = s - 7
                    s = s + 7
                self._refresh()
            if startvaluescount > len(values):
                messagebox.showinfo("Sucess!!", "Đã xóa dữ liệu thành công")
                self._checklistxoa.hide()
                self._buttonhideshowxoa.icon = 'img/show.png'
                self._buttonhideshowxoa.label = 'Hiển thị tiêu chí'
            else:
                messagebox.showinfo(
                    "Opps",
                    "Nội dung cần xóa không có trong cột tiêu chí trong danh sách"
                )

    def _buthideshowxoa(self):
        if not values_name:
            tk.messagebox.showwarning("Warning",
                                      "Không có list để chọn tiêu chí")
        elif str(self._buttonhideshowxoa.label) == 'Ẩn tiêu chí':
            self._checklistxoa.hide()
            self._buttonhideshowxoa.icon = 'img/show.png'
            self._buttonhideshowxoa.label = 'Hiển thị tiêu chí'
        elif str(self._buttonhideshowxoa.label) == 'Hiển thị tiêu chí':
            self._checklistxoa.show()
            self._buttonhideshowxoa.icon = 'img/hide_icon.png'
            self._buttonhideshowxoa.label = 'Ẩn tiêu chí'
#event tab 4
#event _butxuat

    def __xuat(self):
        # kiểm tra đường dẫn
        if not os.path.isdir(self._directory.value):
            messagebox.showwarning("Warning", "đường dẫn ko có")
        elif not self._tenfilexuat.value:
            messagebox.showwarning("Warning", "tên file rỗng")
        elif not values and not values_name:
            messagebox.showwarning("Warning", "không có dữ liệu để xuất")
        else:
            try:
                os.makedirs(self._tenfilexuat.value)
                os.rmdir(self._tenfilexuat.value)
                if os.path.isfile(self._directory.value + '/' +
                                  self._tenfilexuat.value + '.xls'):
                    result = messagebox.askokcancel(
                        'Warning', 'File đã tồn tại bạn có muốn ghi đè lên  ?')
                    if result == 1:
                        write(self._directory.value, self._tenfilexuat.value)
                        myfile = Path(self._directory.value + '/' +
                                      self._tenfilexuat.value + '.xls')
                        if myfile.is_file():
                            messagebox.showinfo("Sucess!!",
                                                "Đã xuất file thành công")
                else:
                    result = messagebox.askokcancel('Warning',
                                                    'Bạn có chắc muốn xuất?')
                    if result == 1:
                        write(self._directory.value, self._tenfilexuat.value)
                        myfile = Path(self._directory.value + '/' +
                                      self._tenfilexuat.value + '.xls')
                        if myfile.is_file():
                            messagebox.showinfo("Sucess!!",
                                                "Đã xuất file thành công")
            except OSError:
                messagebox.showwarning(
                    "Warning",
                    "Tên file không hợp lệ hoặc đang được mở bởi ứng dụng khác"
                )

#event tab 5
#event _butmerge

    def _merge(self):
        if self._list.rows_count < 1:
            messagebox.showwarning("Warning", "Danh sách rỗng")
        else:
            result = messagebox.askokcancel('Warning', 'Bạn có chắc muốn gộp?')
            if result == 1:
                for i in range(1, len(valuesimport), 7):
                    n = False
                    for s in range(1, len(values), 7):
                        if valuesimport[i] == values[s]:
                            f = self._checklist.checked_indexes
                            for c in range(0, len(f), 1):
                                values[s + int(f[c]) -
                                       1] = valuesimport[i + int(f[c]) - 1]
                            n = True
                    if not n:
                        fsqc.append(fsqcimport[int(i / 7)])
                        for s in range(i - 1, i + 6):
                            values.append(valuesimport[s])
                self._refresh()
                for i in range(0, self._listmerge.rows_count):
                    self._listmerge.__sub__(i)
                    for j in range(0, self._listmerge.rows_count):
                        self._listmerge.__sub__(j)
                self._clearimportdata()
                self._checklist.hide()
                self._buttonhideshow.icon = 'img/show.png'
                self._buttonhideshow.label = 'Hiển thị tùy chọn'
                self._buttonremovemerge.hide()
                self._butmerge.hide()
                self._buttonhideshow.hide()
                tk.messagebox.showinfo("Success", "Đã merge thành công")

    #event _buttonremovemerge
    def _remove(self):
        if self._listmerge.rows_count < 1:
            tk.messagebox.showwarning("Warning", "Đã xóa hết!")
        else:
            for i in range(0, self._listmerge.rows_count):
                self._listmerge.__sub__(i)
                for j in range(0, self._listmerge.rows_count):
                    self._listmerge.__sub__(j)
            self._clearimportdata()
            self._checklist.clear()
            self._buttonremovemerge.hide()
            self._buttonhideshow.hide()
            self._checklist.hide()
            self._butmerge.hide()

    #event  _buttonhideshow
    def _buthideshow(self):
        if str(self._buttonhideshow.label) == 'Ẩn tùy chọn':
            self._checklist.hide()
            self._buttonhideshow.icon = 'img/show.png'
            self._buttonhideshow.label = 'Hiển thị tùy chọn'
        elif str(self._buttonhideshow.label) == 'Hiển thị tùy chọn':
            self._checklist.show()
            self._buttonhideshow.icon = 'img/hide_icon.png'
            self._buttonhideshow.label = 'Ẩn tùy chọn'

    #event _buttonimport
    def _import(self):
        if not self._filemerge.value:
            tk.messagebox.showwarning("Warning", "Đường dẫn trống")
        else:
            path = self._filemerge.value
            try:
                importexcel(path)
                self._listmerge.value = [values_nameimport]
                n = 0
                for i in range(int(len(valuesimport) / numberofcolsimport[0])):
                    self._listmerge.__add__(
                        valuesimport[n:n + numberofcolsimport[0]])
                    n = n + numberofcolsimport[0]
                if self._checklist.count < 1:
                    for s in range(0, len(values_nameimport)):
                        self._checklist.__add__((values_nameimport[s], True))
                if self._listmerge and not self._buttonhideshow.visible:
                    if str(self._buttonhideshow.label) == 'Ẩn tùy chọn':
                        self._buttonhideshow.icon = 'img/show.png'
                        self._buttonhideshow.label = 'Hiển thị tùy chọn'
                self._buttonhideshow.show()
                self._buttonremovemerge.show()
                self._butmerge.show()
            except:
                tk.messagebox.showwarning(
                    "Warning",
                    "Không thể đọc file khác excel hoặc đường dẫn không đúng")

#reusable function

    def _refresh(self):
        for i in range(1, self._list.rows_count):
            self._list.__sub__(i)
            for j in range(1, self._list.rows_count):
                self._list.__sub__(j)
        n = 0
        for i in range(int(len(values) / numberofcols[0])):
            self._list.__add__(values[n:n + numberofcols[0]])
            n = n + numberofcols[0]
        # update STT
        for s in range(1, self._list.rows_count):
            values[(s - 1) * 7] = s
            self._list.set_value(0, s, s)

    def _clearimportdata(self):
        fsqcimport.clear()
        valuesimport.clear()
        sqcimport.clear()
        numberofcolsimport.clear()
        values_nameimport.clear()
        self._checklist.clear()