예제 #1
0
class MyFrame(wx.Frame):
    results = []
    downloads = []

    def __init__(self, *args, **kwds):
        kwds["style"] = wx.DEFAULT_FRAME_STYLE
        wx.Frame.__init__(self, *args, **kwds)
        font = wx.Font(9,
                       wx.FONTFAMILY_DEFAULT,
                       style=wx.FONTSTYLE_NORMAL,
                       weight=wx.FONTWEIGHT_NORMAL)
        self.lbl_query = wx.StaticText(self,
                                       -1,
                                       "  Song:  ",
                                       style=wx.ALIGN_CENTRE)
        self.lbl_query.SetFont(font)
        self.txt_query = wx.TextCtrl(self, 1, "", style=wx.TE_PROCESS_ENTER)
        self.fb = wx.StaticBitmap(self,
                                  bitmap=wx.BitmapFromImage(
                                      wx.ImageFromStream(
                                          fbicon, wx.BITMAP_TYPE_PNG)),
                                  size=(22, 22))
        self.folder_chooser = wx.Button(
            self,
            -1,
            "Choose Destination",
            size=[-1, self.txt_query.GetSize().GetHeight()])
        self.lst_results = ObjectListView(self, -1, style=wx.LC_REPORT)
        self.lst_downloads = GroupListView(self, -1, style=wx.LC_REPORT)
        self.lst_artists = ObjectListView(self, -1, style=wx.LC_REPORT)
        self.lst_albums = ObjectListView(self, -1, style=wx.LC_REPORT)
        self.lst_songs = ObjectListView(self, -1, style=wx.LC_REPORT)
        self.frame_statusbar = self.CreateStatusBar(1, wx.SB_RAISED)
        self.__set_properties()
        self.__do_layout()
        self.Bind(EVT_EXEC_FUNC, self._ExecFunc)
        self.Bind(wx.EVT_TEXT_ENTER, self._TextEnter, self.txt_query)
        self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self._ResultsContext,
                  self.lst_results)
        self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self._ResultsContext,
                  self.lst_songs)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._DoubleClick,
                  self.lst_results)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._DoubleClick,
                  self.lst_songs)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self._DoubleClick,
                  self.lst_downloads)
        self.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self._DownloadsContext,
                  self.lst_downloads)
        self.Bind(wx.EVT_BUTTON, self._ChooseFolder, self.folder_chooser)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self._ObjectSelected,
                  self.lst_artists)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self._ObjectSelected,
                  self.lst_albums)
        self.fb.Bind(wx.EVT_LEFT_DOWN, self._FBClick)
        self.txt_query.Bind(wx.EVT_KEY_DOWN, self._Tab)
        self.Bind(wx.EVT_CLOSE, self._Close)
        self.menu_results = {}
        self.menu_downloads = {}
        self.menu_results[ID_DOWNLOAD] = "Download"
        self.menu_downloads[ID_REMOVE] = "Remove"
        self.artists = []
        if sys.platform == 'win32':
            self.SetIcon(wx.Icon(sys.executable, wx.BITMAP_TYPE_ICO))
        else:
            if os.path.exists("groove.ico"):
                self.SetIcon(wx.Icon("groove.ico", wx.BITMAP_TYPE_ICO))

    def __set_properties(self):
        self.SetTitle("JTR's Grooveshark Downloader v" + version)
        self.SetSize((600, 400))
        self.frame_statusbar.SetStatusWidths([-1])
        frame_statusbar_fields = [""]
        columns = [
            ColumnDefn("Title",
                       "left",
                       0,
                       valueGetter="SongName",
                       isSpaceFilling=True),
            ColumnDefn("Album",
                       "center",
                       0,
                       valueGetter="AlbumName",
                       isSpaceFilling=True),
            ColumnDefn("Artist",
                       "center",
                       0,
                       valueGetter="ArtistName",
                       isSpaceFilling=True)
        ]
        columns[0].freeSpaceProportion = 2
        columns[1].freeSpaceProportion = columns[2].freeSpaceProportion = 1
        self.lst_results.SetColumns(columns)
        self.lst_results.SetObjects(self.results)
        self.lst_results.SetEmptyListMsg(emptylistmsg)
        self.lst_results._ResizeSpaceFillingColumns()
        self.lst_results.useAlternateBackColors = False
        columns = [
            ColumnDefn("Title",
                       "left",
                       160,
                       valueGetter="filename",
                       groupKeyGetter="album",
                       isSpaceFilling=True),
            ColumnDefn("Bitrate", "center", 60, valueGetter="bitrate"),
            ColumnDefn("Speed", "center", 75, valueGetter="speed"),
            ColumnDefn("Done/Total", "center", 100, valueGetter="size"),
            ColumnDefn("Progress", "center", 80, valueGetter="progress")
        ]
        self.lst_downloads.SetColumns(columns)
        self.lst_downloads.SetObjects(self.downloads)
        self.lst_downloads.SetEmptyListMsg("N/A")
        self.lst_downloads.SortBy(1)
        self.lst_downloads.useAlternateBackColors = False
        self.lst_downloads.putBlankLineBetweenGroups = False
        self.lst_downloads.SetShowGroups(False)
        columns = [
            ColumnDefn("Artist",
                       "center",
                       100,
                       valueGetter="name",
                       isSpaceFilling=True)
        ]
        self.lst_artists.SetColumns(columns)
        self.lst_artists.SetEmptyListMsg("N/A")
        self.lst_artists.useAlternateBackColors = False
        columns = [
            ColumnDefn("Album",
                       "center",
                       100,
                       valueGetter="name",
                       isSpaceFilling=True)
        ]
        self.lst_albums.SetColumns(columns)
        self.lst_albums.SetEmptyListMsg("N/A")
        self.lst_albums.useAlternateBackColors = False
        columns = [
            ColumnDefn("Song",
                       "center",
                       100,
                       valueGetter="Name",
                       isSpaceFilling=True)
        ]
        self.lst_songs.SetColumns(columns)
        self.lst_songs.SetEmptyListMsg("N/A")
        self.lst_songs.useAlternateBackColors = False
        for i in range(len(frame_statusbar_fields)):
            self.frame_statusbar.SetStatusText(frame_statusbar_fields[i], i)
        self.frame_statusbar.SetStatusStyles([wx.SB_FLAT])
        self.list_by_mode = self.lst_results

    def __do_layout(self):
        self.sizer_1 = wx.BoxSizer(wx.VERTICAL)
        self.sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
        self.sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
        self.sizer_2.Add(self.lbl_query, 0, wx.ALIGN_CENTER, 0)
        self.sizer_2.Add(self.txt_query, 2, 0, 0)
        self.sizer_2.Add(self.folder_chooser, 0, wx.ALIGN_CENTER, 0)
        self.sizer_2.Add(self.fb, 0, wx.ALIGN_CENTER, 0)
        self.sizer_1.Add(self.sizer_2, 0, wx.EXPAND, 0)
        self.sizer_1.Add(self.lst_results, 2, wx.EXPAND, 0)
        self.sizer_1.Add(self.sizer_3, 2, wx.EXPAND, 0)
        self.sizer_1.Add(self.lst_downloads, 1, wx.EXPAND, 0)
        self.sizer_3.Add(self.lst_artists, 1, wx.EXPAND, 0)
        self.sizer_3.Add(self.lst_albums, 1, wx.EXPAND, 0)
        self.sizer_3.Add(self.lst_songs, 2, wx.EXPAND, 0)
        self.SetSizer(self.sizer_1)
        self.sizer_1.Show(self.sizer_3, False)
        self.Layout()

    def _TextEnter(self, event):
        self.artists = []
        if self.lbl_query.GetLabel() == "  Artist:  ":
            self.lst_albums.DeleteAllItems()
            self.lst_songs.DeleteAllItems()
            search_thread = t_search_object(self, _query=event.GetString())
        elif self.lbl_query.GetLabel() == "  Song:  ":
            search_thread = t_search_flat(self, event.GetString())
        search_thread.start()

    def _ExecFunc(self, event):
        event.func(self, event)

    def _FBClick(self, event):
        webbrowser.open_new_tab('http://www.facebook.com/groove.dl')

    def _ResultsContext(self, event):
        menu = wx.Menu()
        menu.Append(ID_DOWNLOAD, "Download")
        wx.EVT_MENU(menu, ID_DOWNLOAD, self._ContextSelection)
        if self.lbl_query.GetLabel() == "  Song:  ":
            lst = self.lst_results
        elif self.lbl_query.GetLabel() == "  Artist:  ":
            lst = self.lst_songs
        self.PopupMenu(menu, event.GetPoint() + lst.GetPosition())
        menu.Destroy()

    def _DownloadsContext(self, event):
        menu = wx.Menu()
        for (id, title) in self.menu_downloads.items():
            menu.Append(id, title)
            wx.EVT_MENU(menu, id, self._ContextSelection)
        self.PopupMenu(menu,
                       event.GetPoint() + self.lst_downloads.GetPosition())
        menu.Destroy()

    def _DoubleClick(self, event):
        if event.GetEventObject() in [self.lst_results, self.lst_songs]:
            self._ContextSelection(ID_DOWNLOAD)
        elif event.GetEventObject() == self.lst_downloads:
            try:
                path = os.path.join(
                    dest,
                    self.lst_downloads.GetSelectedObjects()[0]["filename"])
                if sys.platform == 'win32': os.startfile(path)
                elif sys.platform == 'linux2':
                    subprocess.Popen(['xdg-open', path])
            except:
                pass

    def _ContextSelection(self, event, flag=None):
        if (event == ID_DOWNLOAD) or (event.GetId() == ID_DOWNLOAD):
            if self.lbl_query.GetLabel() == "  Song:  ":
                lst = self.lst_results
                name = 'SongName'
            elif self.lbl_query.GetLabel() == "  Artist:  ":
                lst = self.lst_songs
                name = 'Name'
            for song in lst.GetSelectedObjects():
                filename = format
                filename = filename.replace(
                    'artist', strip(song["ArtistName"], "<>:\"/\|?*"))
                filename = filename.replace('title',
                                            strip(song[name], "<>:\"/\|?*"))
                filename = filename.replace(
                    'album', strip(song["AlbumName"], "<>:\"/\|?*"))
                c = 2
                while os.path.exists(os.path.join(dest, filename + '.mp3')):
                    filename = filename + ' (%d)' % c
                    c += 1
                filename += '.mp3'
                t = t_download(self, song)
                t.download = {
                    "progress": "Initializing",
                    "thread": t,
                    "filename": filename,
                    "album": song["AlbumName"]
                }
                self.downloads.append(t.download)
                self.lst_downloads.SetObjects(self.downloads)
                t.start()
        elif (flag != None and flag.flag == ID_REMOVE) or (event.GetId()
                                                           == ID_REMOVE):
            for d in self.lst_downloads.GetSelectedObjects():
                d["thread"].cancelled = True
                self.downloads.remove(d)
            self.lst_downloads.RemoveObjects(
                self.lst_downloads.GetSelectedObjects())

    def _ChooseFolder(self, event):
        global dest
        dialog = wx.DirDialog(
            None, "Please choose the destination directory:",
            os.getenv('USERPROFILE')
            if sys.platform == 'win32' else os.getenv('HOME'))
        if dialog.ShowModal() == wx.ID_OK:
            dest = dialog.GetPath()
        dialog.Destroy()

    def _Tab(self, event):
        if event.GetKeyCode() == 9:
            if self.lbl_query.GetLabel() == "  Song:  ":
                self.sizer_1.Show(self.sizer_3, True)
                self.sizer_1.Show(self.lst_results, False)
                self.sizer_1.Layout()
                self.lbl_query.SetLabel("  Artist:  ")
                self.list_by_mode = self.lst_artists
                self.lst_downloads.SetShowGroups(True)
                self.lst_downloads._ResizeSpaceFillingColumns()
            elif self.lbl_query.GetLabel() == "  Artist:  ":
                self.sizer_1.Show(self.sizer_3, False)
                self.sizer_1.Show(self.lst_results, True)
                self.sizer_1.Layout()
                self.lbl_query.SetLabel("  Song:  ")
                self.list_by_mode = self.lst_results
                self.lst_downloads.SetShowGroups(False)
                self.lst_downloads._ResizeSpaceFillingColumns()
        event.Skip()

    def _ObjectSelected(self, event):
        if event.GetEventObject() == self.lst_artists:
            self.lst_albums.DeleteAllItems()
            self.lst_songs.DeleteAllItems()
            obj = self.lst_artists.GetSelectedObject()
            artist_thread = t_search_object(self, obj)
            artist_thread.start()
        elif event.GetEventObject() == self.lst_albums:
            self.lst_songs.SetObjects(
                self.lst_albums.GetSelectedObject().Songs)

    def _Close(self, event):
        l = 0
        for i in self.downloads:
            if i["progress"] != "Completed" and i["progress"] != "Error":
                l += 1
        if l > 0:
            if wx.MessageDialog(
                    self,
                    "There are currently %d active downloads. Are you sure you want to cancel them and exit ?"
                    % l, "Active downloads",
                    wx.YES_NO | wx.CENTRE).ShowModal() == wx.ID_NO:
                return
        print "BWAH"
        for d in self.downloads:
            d["thread"].cancelled = True
        config = ConfigParser.RawConfigParser()
        config.add_section("groove-dl")
        config.set("groove-dl", "dest", dest)
        print "BWAH"
        config.set("groove-dl", "format", format)
        config.write(open(os.path.join(conf, "settings.ini"), "wb"))
        sys.stdout.close()
        sys.stderr.close()
        while (threading.active_count() > 3):
            time.sleep(0.1)
        os._exit(0)
예제 #2
0
class SkeletonPanel(wx.Panel):
    """
    Skeleton panel widget
    """
    def __init__(self, parent):
        super().__init__(parent)

        self.db_name = ""
        self.skeleton_results = []
        self.session = None
        self.parent = parent
        # self.session = controller.connect_to_database()

        main_sizer = wx.BoxSizer(wx.VERTICAL)
        search_sizer = wx.BoxSizer(wx.HORIZONTAL)
        btn_sizer = wx.BoxSizer(wx.HORIZONTAL)
        font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL)

        # create the search related widgets
        categories = ["Site", "Location", "Observer", "Skeleton"]
        search_label = wx.StaticText(self, label=" Filter By:")
        search_label.SetFont(font)
        search_sizer.Add(search_label, 0,
                         wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT, 5)
        search_sizer.AddSpacer(5)

        if platform.system().lower() == 'linux':
            self.categories = wx.ComboBox(self,
                                          value="Skeleton",
                                          choices=categories,
                                          style=wx.CB_READONLY,
                                          size=(150, -1))
        else:
            self.categories = wx.ComboBox(self,
                                          value="Skeleton",
                                          choices=categories,
                                          style=wx.CB_READONLY)

        search_sizer.Add(self.categories, 0, wx.ALL, 5)

        search_sizer.AddSpacer(5)

        if platform.system().lower() == 'linux':
            self.search_ctrl = wx.SearchCtrl(self,
                                             style=wx.TE_PROCESS_ENTER,
                                             size=(200, 27))
        else:
            self.search_ctrl = wx.SearchCtrl(self,
                                             style=wx.TE_PROCESS_ENTER,
                                             size=(200, -1))

        # self.search_ctrl.ShowCancelButton(True)
        self.search_ctrl.SetDescriptiveText('Filter')
        self.search_ctrl.Bind(wx.EVT_TEXT_ENTER, self.search)
        search_sizer.Add(self.search_ctrl, 0, wx.ALIGN_CENTER_VERTICAL, 5)
        search_sizer.AddSpacer(5)

        self.show_all_btn = wx.Button(self, label="Show All")
        self.show_all_btn.Bind(wx.EVT_BUTTON, self.on_show_all)
        search_sizer.Add(self.show_all_btn, 0, wx.ALL, 5)

        lfont = self.GetFont()
        lfont.SetPointSize(10)
        self.skeleton_results_olv = ObjectListView(
            self, style=wx.LC_REPORT | wx.SUNKEN_BORDER | wx.LC_SINGLE_SEL)
        self.skeleton_results_olv.Bind(wx.EVT_LIST_ITEM_ACTIVATED,
                                       self.onDoubleClick)
        self.skeleton_results_olv.EnableBellOnNoMatch(on=False)
        self.skeleton_results_olv.SetFont(lfont)
        self.skeleton_results_olv.SetEmptyListMsg("No Records Found")
        self.update_skeleton_results()

        # create the button row
        self.add_record_btn = wx.Button(self, label="&Add")
        self.add_record_btn.Bind(wx.EVT_BUTTON, self.add_record)
        btn_sizer.Add(self.add_record_btn, 0, wx.ALL, 5)

        self.edit_record_btn = wx.Button(self, label="&Edit")
        self.edit_record_btn.Bind(wx.EVT_BUTTON, self.edit_record)
        btn_sizer.Add(self.edit_record_btn, 0, wx.ALL, 5)

        self.pre_record_btn = wx.Button(self, label="&Preservation")
        self.pre_record_btn.Bind(wx.EVT_BUTTON, self.edit_preservation)
        btn_sizer.Add(self.pre_record_btn, 0, wx.ALL, 5)

        self.delete_record_btn = wx.Button(self, label="&Delete")
        self.delete_record_btn.Bind(wx.EVT_BUTTON, self.delete_record)
        btn_sizer.Add(self.delete_record_btn, 0, wx.ALL, 5)

        self.report_btn = wx.Button(self, label="&Create a report")
        self.report_btn.Bind(wx.EVT_BUTTON, self.create_report)
        btn_sizer.Add(self.report_btn, 0, wx.ALL, 5)

        self.controls_state(False)

        main_sizer.Add(search_sizer)
        main_sizer.Add(self.skeleton_results_olv, 1, wx.ALL | wx.EXPAND, 5)
        main_sizer.Add(btn_sizer, 0, wx.CENTER)
        self.SetSizer(main_sizer)

    def controls_state(self, state):
        self.add_record_btn.Enable(state)
        self.edit_record_btn.Enable(state)
        self.pre_record_btn.Enable(state)
        self.delete_record_btn.Enable(state)
        self.report_btn.Enable(state)
        self.show_all_btn.Enable(state)
        self.search_ctrl.Enable(state)

    def on_open_file(self, event):
        wildcard = "DATABASE files (*.db)|*.db"
        with wx.FileDialog(self,
                           "Choose a file",
                           wildcard=wildcard,
                           style=wx.FD_OPEN | wx.FD_FILE_MUST_EXIST) as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                self.db_name = dialog.GetPath()
                # zapis w ostatnio używanych plikach
                self.parent.filehistory.AddFileToHistory(dialog.GetPath())
                self.parent.filehistory.Save(self.parent.config)
                self.parent.config.Flush()
                if self.session != None:
                    self.skeleton_results_olv.DeleteAllItems()
                    self.parent.SetTitle("{}: ".format(APP_NAME))
                    self.session.close()

                self.session = controller.connect_to_database(self.db_name)
                self.parent.SetTitle("{}: ".format(APP_NAME) + self.db_name)
                self.controls_state(True)
                self.show_all_records()

    def on_create_file(self, event):
        wildcard = "DATABASE files (*.db)|*.db"
        with wx.FileDialog(self,
                           "Create a file",
                           wildcard=wildcard,
                           style=wx.FD_SAVE
                           | wx.FD_OVERWRITE_PROMPT) as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                self.db_name = dialog.GetPath()
                # zapis w ostatnio używanych plikach
                self.parent.filehistory.AddFileToHistory(dialog.GetPath())
                self.parent.filehistory.Save(self.parent.config)
                self.parent.config.Flush()
                if self.session != None:
                    self.skeleton_results_olv.DeleteAllItems()
                    self.parent.SetTitle("{}: ".format(APP_NAME))
                    self.session.close()

                self.session = controller.connect_to_database(self.db_name)
                self.parent.SetTitle("{}: ".format(APP_NAME) + self.db_name)
                self.controls_state(True)
                self.show_all_records()

    def on_export_file(self, event):
        """ 
        export db to xlsx 
        """
        if self.session == None:
            dialogs.show_message('No data available for export.', 'Error')
            return

        wildcard = "XLSX files (*.xlsx)|*.xlsx"
        with wx.FileDialog(self,
                           "Export to XLSX",
                           wildcard=wildcard,
                           style=wx.FD_SAVE
                           | wx.FD_OVERWRITE_PROMPT) as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                self.xlsx_name = dialog.GetPath()
                result = controller.export_xlsx(self.session, self.xlsx_name)
                if result != '':
                    dialogs.show_message(result, 'Error')

        self.skeleton_results_olv.SetFocus()

    def add_record(self, event):
        """
        Add a record to the database
        """
        with dialogs.RecordDialog(self.session) as dlg:
            dlg.CenterOnScreen()
            dlg.ShowModal()
            if dlg.result == 1:
                data = {}
                data['skeleton_id'] = dlg.skeleton_id
                data['site'] = dlg.skeleton_dict['site']
                data['location'] = dlg.skeleton_dict['location']
                data['skeleton'] = dlg.skeleton_dict['skeleton']
                data['observer'] = dlg.skeleton_dict['observer']
                data['obs_date'] = dlg.skeleton_dict['obs_date']

                new_skeleton = olvSkeleton(data)
                self.skeleton_results_olv.AddObject(new_skeleton)
                idx = self.skeleton_results_olv.GetIndexOf(new_skeleton)
                self.skeleton_results_olv.Select(idx)
                self.skeleton_results_olv.SelectObject(new_skeleton)

        self.skeleton_results_olv.SetFocus()

    def edit_skeleton(self):
        selected_row = self.skeleton_results_olv.GetSelectedObject()
        active_row = self.skeleton_results_olv.GetIndexOf(selected_row)
        if selected_row is None:
            dialogs.show_message('No record selected!', 'Error')
            return

        with dialogs.RecordDialog(self.session,
                                  selected_row,
                                  title='Modify',
                                  addRecord=False) as dlg:
            dlg.CenterOnScreen()
            dlg.ShowModal()
            if dlg.result == 1:
                self.skeleton_results_olv.RefreshObject(selected_row)

        self.skeleton_results_olv.SetFocus()

    def edit_record(self, event):
        """
        Edit a record
        """
        self.edit_skeleton()

    def onDoubleClick(self, event):
        self.edit_skeleton()

    def delete_record(self, event):
        """
        Delete a record
        """
        selected_row = self.skeleton_results_olv.GetSelectedObject()
        row_index = self.skeleton_results_olv.GetIndexOf(selected_row)
        if selected_row is None:
            dialogs.show_message('No record selected!', 'Error')
            return

        info = 'Delete current record?\n\nSite: {}\nLocation: {}\nSkeleton: {}'.format(
            selected_row.site, selected_row.location, selected_row.skeleton)
        if dialogs.ask_message(info, 'Delete record'):
            controller.delete_record(self.session, selected_row.skeleton_id)
            self.skeleton_results_olv.RemoveObject(selected_row)
            if row_index > 0:
                row_index -= 1

        self.skeleton_results_olv.Select(row_index)
        self.skeleton_results_olv.SetFocus()

    def edit_preservation(self, event):
        selected_row = self.skeleton_results_olv.GetSelectedObject()
        active_row = self.skeleton_results_olv.GetIndexOf(selected_row)
        if selected_row is None:
            dialogs.show_message('No record selected!', 'Error')
            return

        with dialogs.PreservationDialog(self.session, selected_row) as dlg:
            dlg.CenterOnScreen()
            dlg.ShowModal()

        self.skeleton_results_olv.SetFocus()

    def show_all_records(self, active_row=0):
        """
        Updates the record list to show all of them
        """
        self.skeleton_results = controller.get_all_records(self.session)
        self.update_skeleton_results(active_row)

    def create_report(self, event):
        """ select report """
        dlg = wx.SingleChoiceDialog(self, 'Select report:', 'Create report', [
            'Skull report', 'Skull report - SVG', 'Inventory sheet',
            'Full report'
        ], wx.CHOICEDLG_STYLE)

        if dlg.ShowModal() == wx.ID_OK:
            selected = dlg.GetStringSelection()
        else:
            selected = ''

        dlg.Destroy()

        if selected == '':
            return

        if selected == 'Skull report':
            self.create_report_skull()
        elif selected == 'Skull report - SVG':
            self.create_report_skull_svg()
        else:
            dialogs.show_message(
                'Sorry, report "{}" not ready yet.'.format(selected), 'Error')

    def create_report_skull(self):
        """
        generating a skeleton report
        """

        filename = ""
        wildcard = "PDF files (*.pdf)|*.pdf"
        with wx.FileDialog(self,
                           "Create a report",
                           wildcard=wildcard,
                           style=wx.FD_SAVE
                           | wx.FD_OVERWRITE_PROMPT) as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                filename = dialog.GetPath()

        if filename == "":
            return

        my_id = self.skeleton_results_olv.GetSelectedObject().skeleton_id
        rekord = controller.find_skeleton(self.session, my_id)
        if rekord == None:
            dialogs.show_message('No record was found', 'Error')
            return

        data = {}
        data['site'] = rekord.site
        data['location'] = rekord.location
        data['skeleton'] = rekord.skeleton
        data['observer'] = rekord.observer
        data['obs_date'] = rekord.obs_date
        # rekord.frontal if rekord.frontal != None else 0
        data['frontal'] = rekord.frontal
        data['sphenoid'] = rekord.sphenoid
        data['mandible'] = rekord.mandible
        data['ethmoid'] = rekord.ethmoid
        data['parietal_l'] = rekord.parietal_l
        data['parietal_r'] = rekord.parietal_r
        data['nasal_l'] = rekord.nasal_l
        data['nasal_r'] = rekord.nasal_r
        data['palatine_l'] = rekord.palatine_l
        data['palatine_r'] = rekord.palatine_r
        data['thyroid'] = rekord.thyroid
        data['occipital'] = rekord.occipital
        data['maxilla_l'] = rekord.maxilla_l
        data['maxilla_r'] = rekord.maxilla_r
        data['lacrimal_l'] = rekord.lacrimal_l
        data['lacrimal_r'] = rekord.lacrimal_r
        data['hyoid'] = rekord.hyoid
        data['temporal_l'] = rekord.temporal_l
        data['temporal_r'] = rekord.temporal_r
        data['zygomatic_l'] = rekord.zygomatic_l
        data['zygomatic_r'] = rekord.zygomatic_r
        data['orbit_l'] = rekord.orbit_l
        data['orbit_r'] = rekord.orbit_r
        data['calotte'] = rekord.calotte

        report = SheetExport()
        result = report.export_sheet(filename, data)
        if result != '':
            dialogs.show_message(
                'Problems occurred during the creation of the report:\n{}'.
                format(result), 'Error')

        self.skeleton_results_olv.SetFocus()

    def create_report_skull_svg(self):
        """
        generating a skull picture
        """

        filename = ""
        wildcard = "SVG files (*.svg)|*.svg"
        with wx.FileDialog(self,
                           "Create a picture",
                           wildcard=wildcard,
                           style=wx.FD_SAVE
                           | wx.FD_OVERWRITE_PROMPT) as dialog:
            if dialog.ShowModal() == wx.ID_OK:
                filename = dialog.GetPath()

        if filename == "":
            return

        my_id = self.skeleton_results_olv.GetSelectedObject().skeleton_id
        rekord = controller.find_skeleton(self.session, my_id)
        if rekord == None:
            dialogs.show_message('No record was found', 'Error')
            return

        data = {}
        data['site'] = rekord.site
        data['location'] = rekord.location
        data['skeleton'] = rekord.skeleton
        data['observer'] = rekord.observer
        data['obs_date'] = rekord.obs_date
        data['frontal'] = rekord.frontal
        data['sphenoid'] = rekord.sphenoid
        data['mandible'] = rekord.mandible
        data['ethmoid'] = rekord.ethmoid
        data['parietal_l'] = rekord.parietal_l
        data['parietal_r'] = rekord.parietal_r
        data['nasal_l'] = rekord.nasal_l
        data['nasal_r'] = rekord.nasal_r
        data['palatine_l'] = rekord.palatine_l
        data['palatine_r'] = rekord.palatine_r
        data['thyroid'] = rekord.thyroid
        data['occipital'] = rekord.occipital
        data['maxilla_l'] = rekord.maxilla_l
        data['maxilla_r'] = rekord.maxilla_r
        data['lacrimal_l'] = rekord.lacrimal_l
        data['lacrimal_r'] = rekord.lacrimal_r
        data['hyoid'] = rekord.hyoid
        data['temporal_l'] = rekord.temporal_l
        data['temporal_r'] = rekord.temporal_r
        data['zygomatic_l'] = rekord.zygomatic_l
        data['zygomatic_r'] = rekord.zygomatic_r
        data['orbit_l'] = rekord.orbit_l
        data['orbit_r'] = rekord.orbit_r
        data['calotte'] = rekord.calotte

        report = SheetExport()
        result = report.export_skull_svg(filename, data)
        if result != '':
            dialogs.show_message(
                'Problems occurred during the creation of the picture:\n{}'.
                format(result), 'Error')

        self.skeleton_results_olv.SetFocus()

    def search(self, event):
        """
        Searches database based on the user's filter
        choice and keyword
        """
        filter_choice = self.categories.GetValue()
        keyword = self.search_ctrl.GetValue()
        self.skeleton_results = controller.search_records(
            self.session, filter_choice, keyword)
        self.update_skeleton_results()

    def on_show_all(self, event):
        """
        Updates the record list to show all the records
        """
        self.show_all_records()

    def update_skeleton_results(self, active_row=0):
        """
        Updates the ObjectListView's contents
        """
        self.skeleton_results_olv.SetColumns([
            ColumnDefn("Site",
                       "left",
                       350,
                       "site",
                       isSpaceFilling=True,
                       minimumWidth=50),
            ColumnDefn("Location",
                       "left",
                       150,
                       "location",
                       isSpaceFilling=True,
                       minimumWidth=50),
            ColumnDefn("Skeleton",
                       "left",
                       150,
                       "skeleton",
                       isSpaceFilling=True,
                       minimumWidth=50),
            ColumnDefn("Observer",
                       "left",
                       150,
                       "observer",
                       isSpaceFilling=True,
                       minimumWidth=50),
            ColumnDefn("Observation date",
                       "center",
                       80,
                       "obs_date",
                       isSpaceFilling=True,
                       minimumWidth=50)
        ])
        self.skeleton_results_olv.SetObjects(self.skeleton_results)
        if self.skeleton_results_olv.GetItemCount() > 0:
            self.skeleton_results_olv.Select(active_row)
        self.skeleton_results_olv.SetFocus()
예제 #3
0
파일: gui.py 프로젝트: amy-tabb/3dmcap
class PCapMainFrame(wx.Frame):

    FRAME_VIEW_WIDTH = 480
    FRAME_VIEW_HEIGHT = 270

    def __init__(self, controller, resources_path):
        wx.Frame.__init__(self, None)

        self.control = controller
        self.resources_path = resources_path
        self.cam_pos = None
        self.cam_ray = None
        self.cam_pos_lock = RLock()
        self.pointer = 0
        self.SetTitle("3-Demeter PlantCapture")
        self.status_bar = self.CreateStatusBar()
        self.is_mvs_on = False
        self.map_points = None
        self._update_counter = 0

        # Creating menus
        filemenu = wx.Menu()
        menuAbout = filemenu.Append(wx.ID_ABOUT, "&About",
                                    " Information about this program")
        menuExit = filemenu.Append(wx.ID_EXIT, "E&xit",
                                   " Terminate the program")

        menuBar = wx.MenuBar()
        menuBar.Append(filemenu, "&File")

        setmenu = wx.Menu()
        device_menu_item = setmenu.Append(
            0, "&Camera device", " Choose an \
        available camera for capturing")
        scale_menu_item = setmenu.Append(1, "&Scale correction", " Look for a\
        scale pattern")

        menuBar.Append(setmenu, "S&ettings")

        self.SetMenuBar(menuBar)

        # Tools
        actions = {
            'cap_new': ('New capture', 'image_add.svg',
                        'Start new image acquisition', self.OnNewAcq),
            'cap_continue': ('Continue', 'image_run.svg', 'Resume acquisition',
                             self.OnResumeAcq),
            'cap_pause':
            ('Pause', 'image_pause.svg', 'Pause acquisition', self.OnPauseAcq),
            'cap_finish': ('Finish capture', 'image_stop.svg',
                           'Finish acquisition', self.OnFinishAcq),
            'dir_save_to':
            ('Save as...', 'folder_downloads.svg',
             'Save capture files to a new directory', self.OnSave2Dir),
            'dir_open': ('Open...', 'folder_image.svg',
                         'Open a directory with previously captured frames',
                         self.OnOpenDir),
            'mvs_export':
            ('Export to MVS', 'download.svg',
             'Export files to the MVS subsystem', self.OnExportMVS),
            'mvs_run': ('Multiple View Stereo', 'tree.svg',
                        'Start 3-D reconstruction', self.OnMVS),
            'norm': ('Normalize', 'size_height_accept.svg',
                     'Normalize scale and orientation', self.OnNormalize),
            'exit': ('Quit', 'logout.svg', 'Exit application', self.OnExit)
        }

        # Creating the toolbar
        self._toolbar = self.CreateToolBar()
        self._tools = {}

        tools_list = [
            'cap_new', 'cap_continue', 'cap_pause', 'cap_finish', '|',
            'dir_save_to', 'dir_open', 'mvs_export', 'mvs_run', 'norm', '|',
            'exit'
        ]
        for t in tools_list:
            if t is '|':
                self._toolbar.AddSeparator()
            else:
                label, icon, help, command = actions[t]
                bitmap_path = self.resources_path + '/picol/' + icon
                bitmap = wx.Bitmap(bitmap_path)
                self._tools[t] = self._toolbar.AddLabelTool(wx.ID_ANY,
                                                            label,
                                                            bitmap,
                                                            shortHelp=help)
                self.Bind(wx.EVT_TOOL, command, self._tools[t])

        self._toolbar.Realize()

        # Creating the main window
        self.main_window = wx.SplitterWindow(self, wx.ID_ANY)
        self.left_pane = wx.Panel(self.main_window, wx.ID_ANY)
        self.right_pane = wx.Panel(self.main_window, wx.ID_ANY)
        self.main_window.SplitVertically(self.left_pane,
                                         self.right_pane,
                                         sashPosition=256)

        self.main_vsizer = wx.BoxSizer(wx.VERTICAL)
        self.main_vsizer.Add(self.main_window, 1, wx.EXPAND)

        # Adding frame list
        self.keyframes = []
        self.frame_list = ObjectListView(self, wx.ID_ANY, style=wx.LC_REPORT)
        self.frame_list.SetColumns([
            ColumnDefn("#", "left", 30, "num"),
            ColumnDefn("Frame", "left", 100, "frame"),
            ColumnDefn("Path", "left", 130, "path")
        ])

        self.updateKeyFrames()

        lsizer = wx.BoxSizer(wx.VERTICAL)
        lsizer.Add(self.frame_list, 1, wx.EXPAND)
        self.left_pane.SetSizer(lsizer)
        lsizer.Fit(self.left_pane)

        rsizer = wx.BoxSizer(wx.VERTICAL)
        # Adding frame display
        self.frame_image = None
        self.bitmap = wx.EmptyBitmap(PCapMainFrame.FRAME_VIEW_WIDTH,
                                     PCapMainFrame.FRAME_VIEW_HEIGHT)
        pnl_f = wx.Panel(self.right_pane)
        sb = wx.StaticBox(pnl_f, label='Camera frame')
        sbs = wx.StaticBoxSizer(sb, orient=wx.HORIZONTAL)
        sbs.AddSpacer(11)

        self.frame_view = wx.StaticBitmap(pnl_f, bitmap=self.bitmap)
        sbs.Add(self.frame_view, 0,
                wx.ALIGN_CENTER_HORIZONTAL | wx.ADJUST_MINSIZE, 10)
        sbs.AddSpacer(11)
        pnl_f.SetSizer(sbs)

        # Adding Mayavi view
        pnl_m = wx.Panel(self.right_pane)
        sb = wx.StaticBox(pnl_m, label='3-D Viewer')
        sbs = wx.StaticBoxSizer(sb, orient=wx.HORIZONTAL)
        sbs.AddSpacer(11)
        self.mayavi_view = MayaviView()
        traits_ui = self.mayavi_view.edit_traits(parent=pnl_m, kind='subpanel')
        self.mayavi_control = traits_ui.control
        sbs.Add(self.mayavi_control, 1, wx.CENTER | wx.EXPAND)
        sbs.AddSpacer(11)
        pnl_m.SetSizer(sbs)

        rsizer.Add(pnl_f, 0, wx.LEFT)
        rsizer.Add(pnl_m, 1, wx.CENTER | wx.EXPAND)
        self.right_pane.SetSizer(rsizer)
        rsizer.Fit(self.right_pane)

        # Set events:
        self.Bind(wx.EVT_MENU, self.OnAbout, menuAbout)
        self.Bind(wx.EVT_MENU, self.OnExit, menuExit)
        self.Bind(wx.EVT_MENU, self.OnSetDevice, device_menu_item)
        self.Bind(wx.EVT_MENU, self.OnSetScaleCor, scale_menu_item)
        self.frame_list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnFrameSelected)

        self.SetSizer(self.main_vsizer)
        self.SetAutoLayout(1)
        self.main_vsizer.Fit(self)
        self.SetSize((900, 800))

        logo_path = self.resources_path + '/splash-logo.png'
        logo = cv2.imread(logo_path)[:, :, (2, 1, 0)]
        self.updateFrame(logo, 0)

        self.viewer_updater = MayaviUpdater(self)

    def updateFrame(self, frame, frame_num):
        """Update the bitmap to the frame from new frame event."""
        w, h = PCapMainFrame.FRAME_VIEW_WIDTH, PCapMainFrame.FRAME_VIEW_HEIGHT
        thumbnail = cv2.resize(frame, (w, h))
        self.frame_image = wx.ImageFromData(w, h, thumbnail.tostring())
        self.bitmap = wx.BitmapFromImage(self.frame_image)
        self.frame_view.SetBitmap(self.bitmap)
        if frame_num > 0:
            h, w, _ = frame.shape
            msg = 'Frame %d (%d x %d)' % (frame_num, w, h)
            self.status_bar.SetStatusText(msg)

    def updateOdometry(self, Tcw):
        """Add the new odometry data and refresh the 3-D viewer."""
        with self.cam_pos_lock:
            cam_center = Tcw[0:3, 3]
            cam_center.shape = 1, 3
            cam_p_ray = np.dot(Tcw[0:3, 0:3], np.array([0, 0, 1.]))
            if self.cam_pos is None:
                self.cam_pos = cam_center.copy()
                self.cam_ray = cam_p_ray.copy()
            else:
                self.cam_pos = np.vstack((self.cam_pos, cam_center))
                self.cam_ray = np.vstack((self.cam_ray, cam_p_ray))

    def appendKeyFrame(self, frame_num, frame_path, map_points=None):
        n = len(self.keyframes) + 1
        self.keyframes.append({
            'num': n,
            'frame': 'Frame %.5d' % frame_num,
            'path': frame_path
        })
        self.updateKeyFrames()

        if map_points is not None:
            self.map_points = map_points

    def updateKeyFrames(self):
        self.frame_list.SetObjects(self.keyframes)

    def update3DViewer(self):
        with self.cam_pos_lock:
            self._update_counter += 1
            if self.cam_pos is not None and self.cam_pos.shape[0] > 3:
                self.mayavi_view.scene.disable_render = True
                # Update path plot
                ms = self.mayavi_view.cam_path_plot.mlab_source
                ms.reset(x=self.cam_pos[:, 0],
                         y=self.cam_pos[:, 1],
                         z=self.cam_pos[:, 2],
                         scalars=np.arange(self.cam_pos.shape[0]))

                # Update quiver plot (current camera position)
                ms = self.mayavi_view.cam_pos_plot.mlab_source
                ms.reset(x=self.cam_pos[-1, 0],
                         y=self.cam_pos[-1, 1],
                         z=self.cam_pos[-1, 2],
                         u=self.cam_ray[-1, 0],
                         v=self.cam_ray[-1, 1],
                         w=self.cam_ray[-1, 2])

                # Update the map once each 30 updates
                if self._update_counter % 30 == 0 \
                        and self.map_points is not None:
                    ms = self.mayavi_view.map_plot.mlab_source
                    ms.reset(x=self.map_points[:, 0],
                             y=self.map_points[:, 1],
                             z=self.map_points[:, 2])

                    if self._update_counter == 30:
                        self.mayavi_view.scene.reset_zoom()

                mlab = self.mayavi_view.scene.mlab
                dist = la.norm(self.cam_pos[-1] - self.cam_pos[-2])
                self.mayavi_view.scene.disable_render = False

    def loadPLY(self, ply_path, clear_previous=False):
        self.mayavi_view.scene.disable_render = True
        with open(ply_path, 'r') as fp:
            line_num = 0
            line = 'X'
            while len(line) > 0:
                line = fp.readline()
                line_num += 1
                if line.startswith('end_header'):
                    break
        data = np.loadtxt(ply_path, skiprows=line_num)
        X = data[:, 0:3]
        color = data[:, 6:]
        s = np.max(color, axis=1)
        mlab = self.mayavi_view.scene.mlab
        if clear_previous:
            mlab.clf()
        mlab.points3d(X[:, 0],
                      X[:, 1],
                      X[:, 2],
                      s,
                      colormap='gray',
                      mode='point')
        self.mayavi_view.scene.reset_zoom()
        self.mayavi_view.scene.disable_render = False

    def loadOdometry(self, filename):
        with open(filename, 'r') as f:
            params = [line.split() for line in f.readlines()]

        kf_ts = [int(float(p[0])) for p in params]

        # Translation vectors
        t = [np.array([float(v) for v in p[1:4]]) for p in params]
        for ti in t:
            ti.shape = 3, 1

        # q for quaternions
        q = [np.array([float(v) for v in p[4:]]) for p in params]

        # Get Tcw
        Tcw = []
        pr = []
        for (qx, qy, qz, qw), t_ts in zip(q, t):
            R = np.array([[
                1 - 2 * qy**2 - 2 * qz**2, 2 * qx * qy - 2 * qz * qw,
                2 * qx * qz + 2 * qy * qw
            ],
                          [
                              2 * qx * qy + 2 * qz * qw,
                              1 - 2 * qx**2 - 2 * qz**2,
                              2 * qy * qz - 2 * qx * qw
                          ],
                          [
                              2 * qx * qz - 2 * qy * qw,
                              2 * qy * qz + 2 * qx * qw,
                              1 - 2 * qx**2 - 2 * qy**2
                          ]])

            T_ts = np.hstack((R, t_ts))
            pr_ts = np.dot(R, np.array([0, 0, 1.]))
            Tcw.append(T_ts)
            pr.append(pr_ts)

        self.mayavi_view.scene.mlab.clf()
        self.mayavi_view.scene.mlab.quiver3d([T[0, 3] for T in Tcw],
                                             [T[1, 3] for T in Tcw],
                                             [T[2, 3] for T in Tcw],
                                             [p[0]
                                              for p in pr], [p[1] for p in pr],
                                             [p[2] for p in pr],
                                             opacity=0.5,
                                             color=(1, 0, 0),
                                             mode='2darrow')
        if self.map_points is not None:
            mlab = self.mayavi_view.scene.mlab
            mlab.points3d(self.map_points[:, 0],
                          self.map_points[:, 1],
                          self.map_points[:, 2],
                          color=(0, 1, 0.2),
                          mode='point')

        work_dir = os.path.dirname(filename)
        fpaths = glob.glob(work_dir + os.sep + '*.jpg')
        fpaths.sort()
        fnames = [os.path.basename(fpath) for fpath in fpaths]
        fnums = [re.match('frame\-0*(\d+)\.jpg', fn).group(1) for fn in fnames]
        fnames = ['Frame %s' % n for n in fnums]

        self.keyframes = [{
            'num': i + 1,
            'frame': fn,
            'path': fp
        } for i, (fn, fp) in enumerate(zip(fnames, fpaths))]
        self.frame_list.DeleteAllItems()
        self.updateKeyFrames()

    def OnAbout(self, e):
        dlg = wx.MessageDialog(self, "Create 3-D models for plants.",
                               "About 3-Demeter PlantCapture", wx.OK)
        dlg.ShowModal()
        dlg.Destroy()

    def OnSetDevice(self, e):

        args = ['v4l2-ctl', '--list-devices']
        l_cams = subprocess.check_output(args).split('\n')
        l_cams = [u.strip() for u in l_cams if len(u) > 0]
        cams = {l_cams[i]: l_cams[i + 1] for i in range(0, len(l_cams), 2)}
        dialog = wx.SingleChoiceDialog(self, "Select camera device:", "Camera",
                                       cams.keys())
        if dialog.ShowModal() == wx.ID_OK:
            sel_device = dialog.GetStringSelection()
            self.control.set_cap_device(cams[sel_device])

        dialog.Destroy()

    def OnSetScaleCor(self, e):

        options = {
            'Look for scale correction pattern': True,
            'Do not perform scale correction': False
        }
        dialog = wx.SingleChoiceDialog(self, "Scale correction:", "Options",
                                       options.keys())
        if dialog.ShowModal() == wx.ID_OK:
            sel_opt = dialog.GetStringSelection()
            self.control.setScaleCor(options[sel_opt])

        dialog.Destroy()

    def OnError(self, message):
        dialog = wx.MessageDialog(self, message, "Error", wx.OK)
        dialog.ShowModal()
        dialog.Destroy()

    def OnNewAcq(self, e):
        self.viewer_updater.updating = True
        self.viewer_updater.start()
        self.control.new_acquisition()

    def OnResumeAcq(self, e):
        self.viewer_updater = MayaviUpdater(self)
        self.viewer_updater.updating = True
        self.viewer_updater.start()
        self.control.resume_acquisition()

    def OnPauseAcq(self, e):
        self.viewer_updater.updating = False
        self.control.pause_acquisition()

    def OnFinishAcq(self, e):

        for t in ['cap_new', 'cap_continue', 'cap_pause', 'cap_finish']:
            self._tools[t].Enable(False)
        self._toolbar.Realize()

        self.control.finish_acquisition()
        self.viewer_updater.updating = False

    def OnSave2Dir(self, e):
        dlg = wx.DirDialog(self, message="Choose a directory")
        if dlg.ShowModal() == wx.ID_OK:
            full_path = dlg.GetPath()
            self.control.save_capture(full_path)

        dlg.Destroy()

    def OnOpenDir(self, e):
        dlg = wx.DirDialog(self,
                           message="Choose an existing directory",
                           style=wx.DD_DIR_MUST_EXIST)
        if dlg.ShowModal() == wx.ID_OK:
            dir_path = dlg.GetPath()
            self.control.open_cap_dir(dir_path)

        dlg.Destroy()

    def OnExportMVS(self, e):
        self.control.export_to_mvs()

    def OnMVS(self, e):
        self.is_mvs_on = True
        dialog = pp.PyProgress(self,
                               -1,
                               "3-D Reconstruction",
                               "Running PMVS...",
                               agwStyle=wx.PD_APP_MODAL | wx.PD_ELAPSED_TIME)

        dialog.SetGaugeProportion(0.2)
        dialog.SetGaugeSteps(50)
        dialog.SetGaugeBackground(wx.WHITE)
        dialog.SetFirstGradientColour(wx.WHITE)
        dialog.SetSecondGradientColour(wx.BLACK)

        self.control.start_mvs()

        while self.is_mvs_on:
            wx.MilliSleep(100)
            dialog.UpdatePulse()

        dialog.Destroy()

    def MVSFinished(self):
        self.is_mvs_on = False

    def notify(message, msg_type):
        if msg_type == 'error':
            wx.MessageBox(message, 'Error', wx.OK | wx.ICON_ERROR)
        elif msg_type == 'info':
            wx.MessageBox(message, 'Info', wx.OK | wx.ICON_INFORMATION)

    def OnNormalize(self, e):
        self.control.normalize()

    def OnExit(self, e):
        self.Close(True)  # Close the frame.

    def OnFrameSelected(self, event):
        i = event.GetIndex()
        kf_data = self.keyframes[i]

        frame = cv2.imread(kf_data['path'])

        squares = scale.preprocess_and_find_squares(frame)
        mapping = scale.detect_markers(frame, squares)

        frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        pts = [s.reshape((-1, 1, 2)) for s, _ in mapping.values()]
        frame_rgb = cv2.polylines(frame_rgb,
                                  pts,
                                  True, (255, 0, 0),
                                  thickness=3,
                                  lineType=cv2.LINE_AA)

        for k, (pt, _) in mapping.iteritems():
            x, y = pt.mean(axis=0)
            pos = (int(x), int(y))
            cv2.putText(frame_rgb, '%d' % (k), pos, cv2.FONT_ITALIC, 2,
                        (255, 0, 0), 2, cv2.LINE_AA)

        w, h = PCapMainFrame.FRAME_VIEW_WIDTH, PCapMainFrame.FRAME_VIEW_HEIGHT
        thumbnail = cv2.resize(frame_rgb, (w, h))
        self.frame_image = wx.ImageFromData(w, h, thumbnail.tostring())
        self.bitmap = wx.BitmapFromImage(self.frame_image)
        self.frame_view.SetBitmap(self.bitmap)
        self.status_bar.SetStatusText('Frame %d' % kf_data['num'])

    def SetStatus(self, message):
        self.status_bar.SetStatusText(message)
class BooksDBPanel(wx.Panel):
    """
    A panel for Books database construction.
    """
    def __init__(self, parent):

        self.engine = None
        if not os.path.exists("books.db"):
            self.CreateDB("books.db")
        else:
            self.engine = create_engine("sqlite:///books.db")
        self.session = sqlafuns.getsqlsess(self.engine)

        super().__init__(parent)
        vsizer = VBoxSizer()

        hsizer1 = wx.BoxSizer()
        combolab = wx.StaticText(self, label="Pick a table:")
        self.tablenames = [BookTable.__tablename__, SeriesTable.__tablename__]
        self.tablecombo = wx.Choice(self, choices=self.tablenames)
        self.tablecombo.SetSelection(0)
        self.tablecombo.Bind(wx.EVT_CHOICE, self.OnChoice)
        self.current_table = self.tablecombo.GetStringSelection()
        hsizer1.Add(combolab)
        hsizer1.Add(self.tablecombo)
        vsizer.Add(hsizer1, 0, wx.CENTER)

        self.olvtable = ObjectListView(self, style=wx.LC_REPORT)
        vsizer.Add(self.olvtable, 1, wx.EXPAND)

        hsizer2 = wx.BoxSizer()
        addbtn = wx.Button(self, label="Add a row")
        addbtn.Bind(wx.EVT_BUTTON, self.OnAdd)
        hsizer2.Add(addbtn)
        editbtn = wx.Button(self, label="Edit a row")
        editbtn.Bind(wx.EVT_BUTTON, self.OnEdit)
        hsizer2.Add(editbtn)
        delbtn = wx.Button(self, label="Delete a row")
        delbtn.Bind(wx.EVT_BUTTON, self.OnDelete)
        hsizer2.Add(delbtn)
        vsizer.Add(hsizer2, 0, wx.CENTER)

        self.SetSizer(vsizer)

        self.AddCols("book")

    def CreateDB(self, dbfilename):

        self.engine = create_engine(f"sqlite:///{dbfilename}")
        Base.metadata.create_all(self.engine)

    def AddCols(self, current_table):

        self.olvtable.ClearAll()
        if current_table == "book":
            self.olvtable.SetColumns([
                ColumnDefn("Book Id", "left", 50, "book_id"),
                ColumnDefn("Title", "left", 200, "title"),
                ColumnDefn("Author", "left", 200, "author"),
                ColumnDefn("Copyright Year", 'left', 200, "copyright_year"),
                ColumnDefn("Series", "left", 200, "seriesname")
            ])
        elif current_table == "series":
            self.olvtable.SetColumns([
                ColumnDefn("Series Id", "left", 50, "series_id"),
                ColumnDefn("Series Name", "left", 200, "seriesname"),
                ColumnDefn("Books Total", "left", 200, "bookstotal")
            ])
        self.ShowAll(current_table)

    def ShowAll(self, current_table):

        self.olvtable.DeleteAllItems()
        if current_table == "book":
            result = self.session.query(
                BookTable.book_id, BookTable.title, BookTable.author,
                BookTable.copyright_year,
                SeriesTable.seriesname).join(SeriesTable)
            for row in result:
                rowinstance = OlvBookTable(row.book_id, row.title, row.author,
                                           row.copyright_year, row.seriesname)
                self.olvtable.AddObject(rowinstance)
        elif current_table == "series":
            result = self.session.query(SeriesTable)
            for row in result:
                rowinstance = OlvSeriesTable(row.series_id, row.seriesname,
                                             row.bookstotal)
                self.olvtable.AddObject(rowinstance)

    def OnChoice(self, event):

        self.current_table = self.tablecombo.GetStringSelection()
        self.AddCols(self.current_table)
        event.Skip()

    def OnAdd(self, event):

        if self.current_table == "book":
            AddRowtoBookDBDialog(self).ShowModal()
        elif self.current_table == "series":
            AddRowtoSeriesDBDialog(self).ShowModal()
        self.ShowAll(self.current_table)
        event.Skip()

    def OnEdit(self, event):

        rowobj = self.olvtable.GetSelectedObject()
        if self.current_table == "book":
            EditBookRowDialog(self, rowobj=rowobj).ShowModal()
        elif self.current_table == "series":
            EditSeriesRowDialog(self, rowobj=rowobj).ShowModal()
        self.ShowAll(self.current_table)
        event.Skip()

    def OnDelete(self, event):

        rowobj = self.olvtable.GetSelectedObject()
        if self.current_table == "book":
            target = self.session.query(BookTable).filter_by(
                book_id=rowobj.book_id).one()
            self.session.delete(target)
            self.session.commit()
            self.session.close()
        if self.current_table == "series":
            target = self.session.query(SeriesTable).filter_by(
                book_id=rowobj.book_id).one()
            self.session.delete(target)
            self.session.commit()
            self.session.close()
        self.ShowAll(self.current_table)
        event.Skip()
예제 #5
0
class PanelLogs(wx.Panel):
    lock = threading.RLock()

    def __init__(self, parentNotebook, frame_myr, size=None, style=wx.BORDER_DEFAULT):
        wx.Panel.__init__(self, parent=parentNotebook, size=size, id=wx.ID_ANY, style=style)
        self.parentNotebook = parentNotebook
        self.frame_myr = frame_myr

        self.logPath = self.frame_myr.notebook.getTempConfigParam("logPath")

        self.wvLogs = webview.WebView.New(self)
        self.selection = None


        #scrollPanel = wx.Panel(self)
        self.listLogs = ObjectListView(self, size=(108, -1), style=wx.LC_REPORT, sortable=False)
        self.listLogs.oddRowsBackColor = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOW)

        self.listLogs.SetColumns([
            ColumnDefn("Log File", "center", 94, "log")
        ])

        self.listLogs.SetFont(wx.Font(8.5, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False))

        self.loadList()

        self.listLogs.Bind(wx.EVT_LIST_ITEM_SELECTED, self.onLogSelected)
        self.listLogs.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick)
        self.wvLogs.Bind(webview.EVT_WEBVIEW_TITLE_CHANGED, self.onFocusLost)

        sizer = wx.BoxSizer(wx.HORIZONTAL)

        self.wvLogs.SetPage('<html><body style="background-color: #111111;"></body></html>', "")

        sizer.Add(self.wvLogs, 1, wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.TOP, -3)
        sizer.Add(self.listLogs, 0, wx.EXPAND | wx.LEFT, 0)

        self.SetSizer(sizer)

    def onFocusLost(self, event):
        self.listLogs.SetFocus()
        event.Skip()

    def loadList(self):
        with self.lock:
            self.logPath = self.frame_myr.notebook.getTempConfigParam("logPath")

            if not self.logPath or not os.path.isdir(self.logPath):
                self.listLogs.DeleteAllItems()
                return

            logFiles = [ {"log": os.path.splitext(f)[0] } for f in reversed(listdir(self.logPath)) if isfile(join(self.logPath, f)) and f.endswith('.html') ]

            self.listLogs.DeleteAllItems()

            self.listLogs.SetObjects(logFiles)

            if self.selection is not None:
                try:
                    self.listLogs.SelectObjects([self.selection])

                except IndexError:
                    self.selection = None

                self.listLogs.SetFocus()

    def onLogSelected(self, event):
        self.selection = self.listLogs.GetObjects()[event.GetEventObject().GetFirstSelected()]
        self.onLogSelectedIndex(self.selection)

        self.listLogs.SetFocus()

        event.Skip()

    def onLogSelectedIndex(self, selectedObj):
        #logFile = event.GetEventObject().GetValue(self.selection, 0)
        #logFile = self.listLogs.GetValue(index, 0)
        logFile = selectedObj['log']
        self.loadLogFile(logFile)

    def loadLogFile(self, logFile):
        f = open(self.logPath + "/" + logFile + ".html")
        html = f.read()
        f.close()
        self.onLog(html)

    def onLog(self, html):
        self.wvLogs.SetPage(html, "")
        self.wvLogs.Reload()

    def reloadLog(self):
        #self.wvLogs.Reload()
        if self.selection:
            self.loadLogFile(self.selection['log'])

    def OnRightClick(self, event):
        #self.log.WriteText("OnRightClick %s\n" % self.list.GetItemText(self.currentItem))

        # only do this part the first time so the events are only bound once
        if not hasattr(self, "popupID1"):
            self.popupOpenLocation = wx.NewId()
            self.popupDelete = wx.NewId()

            self.Bind(wx.EVT_MENU, self.onPopUpOpenLocation, id=self.popupOpenLocation)
            self.Bind(wx.EVT_MENU, self.onPopUpDelete, id=self.popupDelete)

        # make a menu
        menu = wx.Menu()
        # add some items
        menu.Append(self.popupOpenLocation, "Open file location")
        menu.Append(self.popupDelete, "Delete files...")

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(menu)
        menu.Destroy()

    def onPopUpOpenLocation(self, event):
        if os.name == "nt":
            #os.spawnl(os.P_NOWAIT, os.getenv('windir') + '\\explorer.exe', '.', '/n,/e,/select,"%s"'%self.logPath+"\\")
            psutil.Popen('explorer ' + '"' + self.logPath + '"')

        if os.name == "posix":
            pass

    def onPopUpDelete(self, event):
        question = "Are you sure you want to delete those files?"
        dlg = GMD.GenericMessageDialog(self, question, "Confirm deletion", wx.YES_NO | wx.NO_DEFAULT | wx.ICON_WARNING)
        result = dlg.ShowModal() == wx.ID_YES
        dlg.Destroy()

        if result:
            selected = self.listLogs.GetSelectedObjects()
            for file in selected:
                os.remove(self.logPath + '/' + file['log'] + '.html')

            self.loadList()