Exemple #1
0
 def __init__(self, parent):
     wx.Dialog.__init__(self, parent)
     conf = Config()
     boxSizer = wx.BoxSizer(wx.HORIZONTAL)
     b = BucketConfigPanel(self, conf.getBuckets().keys(), self.onOkBtn)
     boxSizer.Add(b, 1, wx.EXPAND)
     self.Layout()
     self.Center()
Exemple #2
0
 def __init__(self, parent):
     wx.Dialog.__init__(self, parent)
     conf = Config()
     boxSizer = wx.BoxSizer(wx.HORIZONTAL)
     b = BucketConfigPanel(self,
                           conf.getBuckets().keys(), self.onOkBtn)
     boxSizer.Add(b, 1, wx.EXPAND)
     self.Layout()
     self.Center()
Exemple #3
0
class MainFrame(framework.XFrame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1, u'七牛文件管理('+VERSION+')', size=(800, 640))

        self.conf = Config()
        ak, sk = self.conf.getKeys()
        self.__auth = qiniu.Auth(ak, sk)

        self.SetIcon(libs.icons.desktop().GetIcon())
        #self.SetWindowStyle((self.GetWindowStyle() | wx.STAY_ON_TOP))

        self.createSplitter()
        self.createMenuBar(self.menuData())
        self.createToolBar(self.toolbarData())
        self.createStatusBar([-1, 100, 140, 70])
        self.createTaskBarIcon(self.taskMenuData())
        self.Bind(wx.EVT_CLOSE, self.onHideEvent)
        self.Center()

        for bucket in self.conf.getBuckets():
            self._bucketPanel.setBucketName(bucket)
            return

    def bucketMenuData(self):
        bucketsMenu = []
        for bucket in self.conf.getBuckets():
            bucketsMenu.append((bucket, bucket, self.onBucketChangedEvent, wx.ITEM_RADIO))

        bucketsMenu.append("---")
        bucketsMenu.append((u"新建空间", u"新建空间",self.onCreateBucketEvent))
        return (u"空间", bucketsMenu)

    def menuData(self):
        return [
            (u"文件", [
                (u"上传", u"上传文件到当前空间", self.onUploadFileEvent),
                "---",
                (u"最小化", u"最小化到系统托盘", self.onHideEvent),
                (u"退出", u"退出系统", self.onExitEvent)
            ]),
            (u"视图", [
                (u"查看方式", [
                    ([u"详细信息", u"列表", u"大图标", u"小图标"], "", self.onViewChangedEvent, wx.ITEM_RADIO)
                ]),
                "---",
                (u"排序方式", [
                    ([u"名称",u"大小",u"时间"], "", self.onSortChangedEvent, wx.ITEM_RADIO)
                ])
                ,"---"
                , (u"系统设置", u"系统运行视图参数设置", self.onConfigEvent)
            ]),
            self.bucketMenuData(),
            (u"关于", [
                (u"检查更新", u"连接服务器检测是否更新", self.onUploadEvent),
                (u"关于软件", u"关于软件简介", self.onAboutSoftEvent),
                (u"关于作者", u"作者简介", self.onAboutUserEvent)
            ])
        ]

    def toolbarData(self):
        return [
            (u"上传", u"上传文件到当前空间", "upload.png", self.onUploadFileEvent),
            ((ID.ID_TOOLBAR_DOWNLOAD, u"下载"), u"下载选中文件", ["download.png","download.dis.png"], self.onDownloadFileEvent, False),
            "---",
            ((ID.ID_TOOLBAR_TRASH, u"删除"), u"删除选中文件", ["trash.png","trash.dis.png"], self._bucketPanel.onDeleteEvent, False),
            "---",
            ((ID.ID_TOOLBAR_PREV_PAGE, U"上一页"), u"加载上一页文件", ["prev.png", "prev.dis.png"], self._bucketPanel.onPrevPageEvent, False),
            ((ID.ID_TOOLBAR_NEXT_PAGE, U"下一页"), u"加载下一页文件", ["next.png", "next.dis.png"], self._bucketPanel.onNextPageEvent, False),
            "---",
            (u"刷新", u"刷新当前页" , "refresh.png",self._bucketPanel.onRefreshEvent),
            "---",
            ((ID.ID_TOOLBAR_LIMIT,u"显示个数:"),["10","20","50","100","200","500"],self._bucketPanel.onPageLimitEvent),
            "---",
            ((ID.ID_TOOLBAR_SEARCH_TEXT, u"搜索关键字"), (u"", u"文件前缀"), {wx.EVT_KEY_DOWN:self._bucketPanel.onSearchEvent}),
            (u"搜索", u"在当前空间搜索", "search.png", self._bucketPanel.onSearchEvent),
        ]

    def taskMenuData(self):
        return [
            (u"显示", u"", self.onShowEvent),
            "-",
            (u"关于软件", u"关于软件简介", self.onAboutSoftEvent),
            "-",
            (u"退出", u"", self.onExitEvent)
        ]

    def createSplitter(self):
        self._splitter = wx.SplitterWindow(self)
        self._items = self.createBucketsPanel(self._splitter)

        self._uploadify = wx.Panel(self._splitter, style=wx.BORDER_SIMPLE)
        self._uploadify.SetSizer(wx.BoxSizer(wx.VERTICAL))

        self._splitter.Initialize(self._items)
        return self._splitter

    def createBucketsPanel(self, parent):
        self._bucketPanel = BucketPanel(parent, self.__auth)
        self.SetDropTarget(FileDropUpLoadTarget(self.uploadFile))
        return self._bucketPanel

    def onScheduleFinally(self, panel=None, status=True):
        """上传动作结束(正确上传,上传错误,。。。)均会调用"""
        if status and panel:
            self._uploadify.GetSizer().Hide(panel)
            self._uploadify.GetSizer().Remove(panel)
            self._uploadify.RemoveChild(panel)

        children = len(self._uploadify.GetChildren())
        if children == 0 :
            self.__switchSplitWindow(False)

        self._uploadify.Layout()

    def onUploadFileEvent(self, event):
        wildcard = u"所有文件 (*.*) | *.*"
        result = dialogs.fileDialog(parent=self._uploadify, title=u'选择文件', filename='', wildcard=wildcard, style=wx.OPEN)
        if result.accepted:
            for file_path in result.paths:
                if os.path.isdir(file_path) :
                    continue
                self.uploadFile(file_path)
        event.Skip()

    def onDownloadFileEvent(self, event):
        self.__switchSplitWindow(True)

        folder = ""
        results = dialogs.dirDialog(self, u"选择下载位置")
        if results.accepted:
            folder = results.path
            files = self._bucketPanel.getSelectedFiles()
            for file in files :
                dnPanel = DownloadPanel(folder, file, self.onScheduleFinally, self._uploadify)
                boxSizer = self._uploadify.GetSizer()
                boxSizer.Add(dnPanel, flag=wx.EXPAND)
            self._uploadify.Layout()
            event.Skip()
        else:
            self.onScheduleFinally(None,False)

    def uploadFile(self,file_path):
        self.__switchSplitWindow(True)

        bucketName = self._bucketPanel.getBucketName()
        up = UploadifyPanel(self.__auth, bucketName, file_path, self.onScheduleFinally, self._uploadify)
        boxSizer = self._uploadify.GetSizer()
        boxSizer.Add(up, flag=wx.EXPAND)

        #self._uploadify.GetSizer().Fit(self._uploadify)
        #self._uploadify.GetSizer().SetSizeHints(self._uploadify)
        self._uploadify.Layout()

    def __switchSplitWindow(self,open=True):
        """选择上传下载队列窗口状态"""
        if open:
            if not self._splitter.IsSplit() :
                rect = self.GetScreenRect()
                self._splitter.SplitVertically(self._items, self._uploadify, rect.width - 370)
        else:
            if self._splitter.IsSplit():
                self._splitter.Unsplit()
            #self._bucketPanel.setBucketName(self._bucketPanel.getBucketName())

    def onBucketChangedEvent(self, event):
        item = event.EventObject.FindItemById(event.GetId())
        bucketName = item.GetText()
        self._bucketPanel.setBucketName(bucketName)

    def onViewChangedEvent(self, event):
        item = event.EventObject.FindItemById(event.GetId())
        text = item.GetText()
        wx.MessageBox(u"首先感谢您的支持!视图查看功能此版本不包含。该项功能正在加紧开发。",u"抱歉")

    def onSortChangedEvent(self, event):
        item = event.EventObject.FindItemById(event.GetId())
        text = item.GetText()
        self._bucketPanel.sortBy(text)

    def onCreateBucketEvent(self, event):
        wx.MessageBox(VERSION+u"版暂不支持此功能!",u"抱歉")

    def onConfigEvent(self, event):
        from libs.login import BucketConfigPanel

        class ConfigDialog(wx.Dialog):
            def __init__(self, parent):
                wx.Dialog.__init__(self, parent)
                conf = Config()
                boxSizer = wx.BoxSizer(wx.HORIZONTAL)
                b = BucketConfigPanel(self, conf.getBuckets().keys(), self.onOkBtn)
                boxSizer.Add(b, 1, wx.EXPAND)
                self.Layout()
                self.Center()

            def onOkBtn(self):
                self.Hide()
                self.Destroy()

        ConfigDialog(self).ShowModal()

    def onUploadEvent(self, event):
        webbrowser.open_new("http://github.com/ihaiker/QiniuAdminGui")

    def onAboutUserEvent(self, event):
        self.onUploadEvent(event)

    def onAboutSoftEvent(self, event):
        self.onUploadEvent(event)
Exemple #4
0
class BucketPanel(wx.Panel, wx.lib.mixins.listctrl.ColumnSorterMixin):
    def __init__(self, parent, auth):
        wx.Panel.__init__(self, parent)
        self.__frame = self.GetParent().GetParent()

        self.__auth = auth
        self.__bucketManger = qiniu.BucketManager(self.__auth)
        self.__conf = Config()

        self.__bucketName = ""
        self.__download_url = None
        self.__prefix = ""
        self.__marker = None
        self.__limit = LIMIT

        self.__initImages()

        self.__boxSizer = wx.BoxSizer()
        self.__dataList = self.__initList()
        self.__boxSizer.Add(self.__dataList, 1, wx.EXPAND)

        self.__initPopMenu()

        self.SetSizer(self.__boxSizer)

        # init column sorter
        wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self, LIMIT)

    def GetListCtrl(self):
        return self.__dataList

    def GetSortImages(self):
        return (self.down, self.up)

    def OnSortOrderChanged(self):
        self.__downloadButtonAndDeleteButtonStatus()

    def setBucketName(self, bucketName):

        ## 之所以放在这是因为,在初始化此面板的时候还未初始化toolbar
        self.__toolbar = self.__frame._toolbar

        self.__bucketName = bucketName  # 当前空间名称
        self.__download_url = self.__conf.getBuckets()[self.__bucketName]
        self.__resetStartLoad()

    def setPrefix(self, prefix):
        self.__prefix = prefix
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_BTN, False)
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_TEXT, False)
        self.__resetStartLoad()

    def setLimit(self, limit):
        self.__limit = limit
        self.__enableToolbar(ID.ID_TOOLBAR_LIMIT, False)
        self.__resetStartLoad()

    def getBucketName(self):
        return self.__bucketName

    def __resetStartLoad(self):
        """从头开始重新加载"""
        self.__marker = None  # 下一页marker,加载下一页的时候需要
        self.__store = Store()  # 保存数据
        self.__dataList.DeleteAllItems()
        AsynchronousThread(self.__loadData).start()

    def __initImages(self):
        # load some images into an image list
        self.__images_16x = wx.ImageList(16, 16, False)

        self.__icons = []
        for types, image in libs.mimetype.typeImage:
            self.__images_16x.Add(icons.mimeType('16x', image).GetBitmap())
            self.__icons.append(image)

        self.up = self.__images_16x.AddWithColourMask(
            icons.get("/sorter/up.png").GetBitmap(), "blue")
        self.down = self.__images_16x.AddWithColourMask(
            icons.get("/sorter/down.png").GetBitmap(), "blue")

    def __initList(self):
        list = wx.ListCtrl(self,
                           -1,
                           style=wx.LC_REPORT | wx.LC_SORT_ASCENDING
                           | wx.BORDER_SUNKEN)
        # assign the image list to it
        list.AssignImageList(self.__images_16x, wx.IMAGE_LIST_SMALL)

        # Add some columns
        for col, text in enumerate([u"路径", u"类型", u"大小", u"上传时间"]):
            list.InsertColumn(col, text, wx.CENTER)

        # set the width of the columns in various ways
        list.SetColumnWidth(0, 320)
        list.SetColumnWidth(1, 120)
        list.SetColumnWidth(2, 80)
        list.SetColumnWidth(3, 140)

        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.__onTreeSelected, list)
        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.__onTreeSelected, list)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.__onTreeSelected, list)

        # rename event
        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.__onEditNameStart, list)
        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.__onEditNameEnd, list)
        # key up event (rename & delete)
        list.Bind(wx.EVT_KEY_UP, self.__onListKeyUp)

        #drop to download, bug bug
        #self.Bind(wx.EVT_LIST_BEGIN_DRAG, self._startDragEvent, list)

        return list

    def _startDragEvent(self, e):
        # create temp folder
        # folder = libs.config.WORK_PATH + "/temp"
        # libs.config.mkdirs(folder)

        text = self.__dataList.GetItem(e.GetIndex()).GetText()
        text = text if text[0] == "/" else "/" + text
        # temp_file = os.path.join(folder, os.path.basename(text if text[0] == "/" else "/" + text))

        # Create drag data
        data = wx.FileDataObject()
        data.AddFile(text)

        # Create drop source and begin drag-and-drop.
        dropSource = wx.DropSource(self.__dataList)
        dropSource.SetData(data)

        # Get Source
        res = dropSource.DoDragDrop(flags=wx.Drag_AllowMove)
        if res == wx.DragMove or res == wx.DragCopy:
            ## 下载
            print("DragMove & DragCopy")

        return text

    def __onTreeSelected(self, event):
        self.__downloadButtonAndDeleteButtonStatus()

    def __pageButtonStatus(self):
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_BTN, True)
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_TEXT, True)
        self.__enableToolbar(ID.ID_TOOLBAR_LIMIT, True)

        self.__enableToolbar(ID.ID_TOOLBAR_NEXT_PAGE,
                             self.__store.hasNext() or self.__marker != None)
        self.__enableToolbar(ID.ID_TOOLBAR_PREV_PAGE, self.__store.hasPrev())
        self.__updateStatus()
        self.__downloadButtonAndDeleteButtonStatus()

    def __downloadButtonAndDeleteButtonStatus(self):
        selected = self.__dataList.GetSelectedItemCount() > 0
        self.__enableToolbar(
            ID.ID_TOOLBAR_DOWNLOAD, selected and self.__download_url != None
            and self.__download_url != "")
        self.__enableToolbar(ID.ID_TOOLBAR_TRASH, selected)

    def __loadNextData(self):
        if self.__store.hasNext():
            self.__showData(self.__store.next())
            self.__pageButtonStatus()
        elif self.__marker != None:
            AsynchronousThread(self.__loadData).start()

    def __loadPrevData(self):
        if self.__store.hasPrev():
            self.__showData(self.__store.prev())
        self.__pageButtonStatus()

    def __loadData(self):
        ret, eof, info = self.__bucketManger.list(bucket=self.__bucketName,
                                                  marker=self.__marker,
                                                  limit=self.__limit,
                                                  prefix=self.__prefix)
        if info.ok():
            items = ret.get("items")
            self.__store.add(items)
            wx.CallAfter(self.__showData, items)
            if not eof:
                self.__marker = ret.get("marker")
            else:
                self.__marker = None
        else:
            if self.__marker != None:
                self.__enableToolbar(ID.ID_TOOLBAR_NEXT_PAGE, True)
            wx.MessageBox(info.error)

        self.__pageButtonStatus()

    def __showData(self, items):
        self.itemDataMap = {}
        for row, item in enumerate(items):
            name = item.get(u"key")
            fsize = libs.config.fileSizeShow(item.get(u"fsize"))
            putTime = time.strftime(
                '%Y-%m-%d %H:%M:%S',
                time.localtime(round(item.get("putTime") / 10000 / 1000)))
            mimeType = item.get(u"mimeType")
            image = libs.mimetype.showType(mimeType, name)

            index = self.__dataList.InsertStringItem(sys.maxint, name)
            self.__dataList.SetStringItem(index, 1, mimeType)
            self.__dataList.SetStringItem(index, 2, fsize)
            self.__dataList.SetStringItem(index, 3, putTime)
            self.__dataList.SetItemData(index, row)

            # sort data
            self.itemDataMap[index] = (name, mimeType, item.get("fsize"),
                                       item.get("putTime"))

            # 设置图标
            self.__dataList.SetItemImage(index, self.__icons.index(image))

    def __initPopMenu(self):
        self.popupMenu = wx.Menu()

        urlMenu = self.popupMenu.Append(-1, u"复制地址", u"复制地址")
        self.Bind(wx.EVT_MENU, self.onCopyUrlEvent, urlMenu)

        self.popupMenu.AppendSeparator()

        deleteMenu = self.popupMenu.Append(-1, u"删除", u"删除选中文件")
        self.Bind(wx.EVT_MENU, self.onDeleteEvent, deleteMenu)

        refreshMenu = self.popupMenu.Append(-1, u"更新", u"强制更新缓存,保证上传的文件可以显示最新")
        self.Bind(wx.EVT_MENU, self.onRefreshCacheEvent, refreshMenu)

        renameMenu = self.popupMenu.Append(-1, u"重命名", u"重命名")
        self.Bind(wx.EVT_MENU, self.onRenameEvent, renameMenu)

        downloadMenu = self.popupMenu.Append(-1, u"下载", u"下载选中文件")
        self.Bind(wx.EVT_MENU, self.__frame.onDownloadFileEvent, downloadMenu)

        self.Bind(wx.EVT_CONTEXT_MENU, self.__onShowPopup)

    def __onShowPopup(self, event):
        if len(self.getSelectedFiles()) != 0:
            pos = event.GetPosition()
            pos = self.ScreenToClient(pos)
            self.PopupMenu(self.popupMenu, pos)
        else:
            ##没有选中文件,不可操作
            pass

    def __onPopupItemSelected(self, event):
        item = self.popupMenu.FindItemById(event.GetId())
        text = item.GetText()
        wx.MessageBox("You selected item '%s'" % text)

    def __onListKeyUp(self, event):
        keyCode = event.GetKeyCode()
        if keyCode == wx.WXK_DELETE:
            self.onDeleteEvent(event)

        elif keyCode == wx.WXK_F2:
            if len(self.getSelectedFiles()) == 1:
                self.onRenameEvent(event)

        elif event.ControlDown() and keyCode == 67:
            self.onCopyUrlEvent(event)

        elif event.ControlDown() and keyCode == 65:
            for index in range(self.__dataList.GetItemCount()):
                self.__dataList.Select(index, True)

        event.Skip()

    def __onEditNameStart(self, event):
        print("重命名开始")

    def __onEditNameEnd(self, event):
        print("重命名结束")

    def getSelectedFiles(self):
        files = []
        index = self.__dataList.GetFirstSelected()
        while index != -1:
            item = self.__dataList.GetItem(index)
            key = item.GetText()
            mimeType = self.itemDataMap[index][1]
            fileSize = self.itemDataMap[index][2]
            base_url = 'http://%s/%s' % (self.__download_url, key)
            private_url = self.__auth.private_download_url(base_url,
                                                           expires=3600)
            files.append((private_url, key, mimeType, fileSize))
            index = self.__dataList.GetNextSelected(index)

        return files

    def onRefreshEvent(self, event):
        self.__resetStartLoad()

    def onNextPageEvent(self, event):
        self.__dataList.DeleteAllItems()
        self.__enableToolbar(ID.ID_TOOLBAR_NEXT_PAGE)
        self.__loadNextData()

    def onPrevPageEvent(self, event):
        self.__dataList.DeleteAllItems()
        self.__enableToolbar(ID.ID_TOOLBAR_PREV_PAGE)
        self.__loadPrevData()

    def onCopyUrlEvent(self, event):
        files = self.getSelectedFiles()
        value = ""
        for url, key, mimeType, fileSize in files:
            value += url + "\n"

        data = wx.TextDataObject()
        data.SetText(value)
        if wx.TheClipboard.Open():
            wx.TheClipboard.SetData(data)
            wx.TheClipboard.Close()
        else:
            wx.MessageBox(u"不能打开剪切板!", u"复制错误")

    def onDeleteEvent(self, event):
        """删除文件"""
        self.__enableToolbar(ID.ID_TOOLBAR_TRASH, False)
        message = u"您确定删除以下文件?\n"
        files = []
        index = self.__dataList.GetFirstSelected()
        while index != -1:
            item = self.__dataList.GetItem(index)
            key = item.GetText()
            message += key + "\n"
            files.append(key)
            index = self.__dataList.GetNextSelected(index)

        results = dialogs.messageDialog(self, message, "Sure?")
        if results.accepted:
            AsynchronousThread((self.deleteSelectedFile, files)).start()
        else:
            self.__downloadButtonAndDeleteButtonStatus()

    def deleteSelectedFile(self, files):
        ops = build_batch_delete(self.__bucketName, files)
        ret, info = self.__bucketManger.batch(ops)
        if info.ok():
            wx.CallAfter(wx.MessageBox, u"删除成功", u"提示")
            wx.CallAfter(self.setBucketName, self.__bucketName)
        else:
            wx.CallAfter(wx.MessageBox, info.error)

    def onRefreshCacheEvent(self, event):
        """刷新缓存"""
        files = self.getSelectedFiles()
        for url, key, mimeType, fileSize in files:
            self.__bucketManger.prefetch(self.__bucketName, key)

        wx.MessageBox(u"更新成功", u"Note")

    def onRenameEvent(self, event):
        """重命名"""
        selected = len(self.getSelectedFiles())
        if selected == 1:
            # self.__onEditNameStart(event)
            index = self.__dataList.GetFirstSelected()
            key = self.itemDataMap[index][0]
            results = dialogs.textEntryDialog(self, u"请输入修改的名字", u"重命名", key)
            if results.accepted:
                newKey = results.text
                try:
                    ret, info = self.__bucketManger.rename(
                        self.__bucketName, key, newKey)
                    if info.ok():
                        wx.MessageBox(u"重命名成功!", u"成功")
                    else:
                        wx.MessageBox(info.error, u"错误")
                except:
                    wx.MessageBox(u"名字错误,查阅七牛文档!", u"错误")
        else:
            wx.MessageBox(u"不能同时重命名多个文件!", u"错误")

    def onSearchEvent(self, event):
        if isinstance(event, wx.KeyEvent):
            keycode = event.GetKeyCode()
            if keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER:
                pass
            else:
                event.Skip()
                return True

        textCtrl = self.__frame._toolbar.FindById(
            ID.ID_TOOLBAR_SEARCH_TEXT).GetControl()
        self.setPrefix(textCtrl.GetValue())

    def onPageLimitEvent(self, event):
        limit = int(event.EventObject.GetStringSelection(), 10)
        self.setLimit(limit)
        event.Skip()

    def sortBy(self, type):
        dict = {u"名称": 0, u"大小": 2, u"时间": 3}
        idx = dict[type]

        def compare_func(row1, row2):
            val1 = self.itemDataMap[row1][idx]
            val2 = self.itemDataMap[row2][idx]
            if val1 < val2:
                return -1
            elif val1 > val2:
                return 1
            else:
                return 0

        self.__dataList.SortItems(compare_func)

    def __enableToolbar(self, id, enable=False):
        """禁用或者启用某个菜单"""
        self.__toolbar.EnableTool(id, enable)

    def __updateStatus(self):
        moreMark = "+"
        if self.__marker == None:
            moreMark = ""
        statusText = (u"空间:%s" % (self.__bucketName))
        self.__frame.SetStatusText(statusText, 2)
        statusText = (u"页码:%d/%d%s" %
                      (self.__store.page(), self.__store.length(), moreMark))
        self.__frame.SetStatusText(statusText, 3)
Exemple #5
0
class MainFrame(framework.XFrame):
    def __init__(self):
        wx.Frame.__init__(self,
                          None,
                          -1,
                          u'七牛文件管理(' + VERSION + ')',
                          size=(800, 640))

        self.conf = Config()
        ak, sk = self.conf.getKeys()
        self.__auth = qiniu.Auth(ak, sk)

        self.SetIcon(libs.icons.desktop().GetIcon())
        #self.SetWindowStyle((self.GetWindowStyle() | wx.STAY_ON_TOP))

        self.createSplitter()
        self.createMenuBar(self.menuData())
        self.createToolBar(self.toolbarData())
        self.createStatusBar([-1, 100, 140, 70])
        self.createTaskBarIcon(self.taskMenuData())
        self.Bind(wx.EVT_CLOSE, self.onHideEvent)
        self.Center()

        for bucket in self.conf.getBuckets():
            self._bucketPanel.setBucketName(bucket)
            return

    def bucketMenuData(self):
        bucketsMenu = []
        for bucket in self.conf.getBuckets():
            bucketsMenu.append(
                (bucket, bucket, self.onBucketChangedEvent, wx.ITEM_RADIO))

        bucketsMenu.append("---")
        bucketsMenu.append((u"新建空间", u"新建空间", self.onCreateBucketEvent))
        return (u"空间", bucketsMenu)

    def menuData(self):
        return [(u"文件", [(u"上传", u"上传文件到当前空间", self.onUploadFileEvent), "---",
                         (u"最小化", u"最小化到系统托盘", self.onHideEvent),
                         (u"退出", u"退出系统", self.onExitEvent)]),
                (u"视图", [(u"查看方式", [([u"详细信息", u"列表", u"大图标",
                                      u"小图标"], "", self.onViewChangedEvent,
                                     wx.ITEM_RADIO)]), "---",
                         (u"排序方式", [([u"名称", u"大小", u"时间"], "",
                                     self.onSortChangedEvent, wx.ITEM_RADIO)]),
                         "---", (u"系统设置", u"系统运行视图参数设置", self.onConfigEvent)]),
                self.bucketMenuData(),
                (u"关于", [(u"检查更新", u"连接服务器检测是否更新", self.onUploadEvent),
                         (u"关于软件", u"关于软件简介", self.onAboutSoftEvent),
                         (u"关于作者", u"作者简介", self.onAboutUserEvent)])]

    def toolbarData(self):
        return [
            (u"上传", u"上传文件到当前空间", "upload.png", self.onUploadFileEvent),
            ((ID.ID_TOOLBAR_DOWNLOAD, u"下载"), u"下载选中文件",
             ["download.png",
              "download.dis.png"], self.onDownloadFileEvent, False),
            "---",
            ((ID.ID_TOOLBAR_TRASH, u"删除"), u"删除选中文件",
             ["trash.png",
              "trash.dis.png"], self._bucketPanel.onDeleteEvent, False),
            "---",
            ((ID.ID_TOOLBAR_PREV_PAGE, U"上一页"), u"加载上一页文件",
             ["prev.png",
              "prev.dis.png"], self._bucketPanel.onPrevPageEvent, False),
            ((ID.ID_TOOLBAR_NEXT_PAGE, U"下一页"), u"加载下一页文件",
             ["next.png",
              "next.dis.png"], self._bucketPanel.onNextPageEvent, False),
            "---",
            (u"刷新", u"刷新当前页", "refresh.png", self._bucketPanel.onRefreshEvent),
            "---",
            ((ID.ID_TOOLBAR_LIMIT, u"显示个数:"),
             ["10", "20", "50", "100", "200",
              "500"], self._bucketPanel.onPageLimitEvent),
            "---",
            ((ID.ID_TOOLBAR_SEARCH_TEXT, u"搜索关键字"), (u"", u"文件前缀"), {
                wx.EVT_KEY_DOWN: self._bucketPanel.onSearchEvent
            }),
            (u"搜索", u"在当前空间搜索", "search.png", self._bucketPanel.onSearchEvent),
        ]

    def taskMenuData(self):
        return [(u"显示", u"", self.onShowEvent), "-",
                (u"关于软件", u"关于软件简介", self.onAboutSoftEvent), "-",
                (u"退出", u"", self.onExitEvent)]

    def createSplitter(self):
        self._splitter = wx.SplitterWindow(self)
        self._items = self.createBucketsPanel(self._splitter)

        self._uploadify = wx.Panel(self._splitter, style=wx.BORDER_SIMPLE)
        self._uploadify.SetSizer(wx.BoxSizer(wx.VERTICAL))

        self._splitter.Initialize(self._items)
        return self._splitter

    def createBucketsPanel(self, parent):
        self._bucketPanel = BucketPanel(parent, self.__auth)
        self.SetDropTarget(FileDropUpLoadTarget(self.uploadFile))
        return self._bucketPanel

    def onScheduleFinally(self, panel=None, status=True):
        """上传动作结束(正确上传,上传错误,。。。)均会调用"""
        if status and panel:
            self._uploadify.GetSizer().Hide(panel)
            self._uploadify.GetSizer().Remove(panel)
            self._uploadify.RemoveChild(panel)

        children = len(self._uploadify.GetChildren())
        if children == 0:
            self.__switchSplitWindow(False)

        self._uploadify.Layout()

    def onUploadFileEvent(self, event):
        wildcard = u"所有文件 (*.*) | *.*"
        result = dialogs.fileDialog(parent=self._uploadify,
                                    title=u'选择文件',
                                    filename='',
                                    wildcard=wildcard,
                                    style=wx.OPEN)
        if result.accepted:
            for file_path in result.paths:
                if os.path.isdir(file_path):
                    continue
                self.uploadFile(file_path)
        event.Skip()

    def onDownloadFileEvent(self, event):
        self.__switchSplitWindow(True)

        folder = ""
        results = dialogs.dirDialog(self, u"选择下载位置")
        if results.accepted:
            folder = results.path
            files = self._bucketPanel.getSelectedFiles()
            for file in files:
                dnPanel = DownloadPanel(folder, file, self.onScheduleFinally,
                                        self._uploadify)
                boxSizer = self._uploadify.GetSizer()
                boxSizer.Add(dnPanel, flag=wx.EXPAND)
            self._uploadify.Layout()
            event.Skip()
        else:
            self.onScheduleFinally(None, False)

    def uploadFile(self, file_path):
        self.__switchSplitWindow(True)

        bucketName = self._bucketPanel.getBucketName()
        up = UploadifyPanel(self.__auth, bucketName, file_path,
                            self.onScheduleFinally, self._uploadify)
        boxSizer = self._uploadify.GetSizer()
        boxSizer.Add(up, flag=wx.EXPAND)

        #self._uploadify.GetSizer().Fit(self._uploadify)
        #self._uploadify.GetSizer().SetSizeHints(self._uploadify)
        self._uploadify.Layout()

    def __switchSplitWindow(self, open=True):
        """选择上传下载队列窗口状态"""
        if open:
            if not self._splitter.IsSplit():
                rect = self.GetScreenRect()
                self._splitter.SplitVertically(self._items, self._uploadify,
                                               rect.width - 370)
        else:
            if self._splitter.IsSplit():
                self._splitter.Unsplit()
            #self._bucketPanel.setBucketName(self._bucketPanel.getBucketName())

    def onBucketChangedEvent(self, event):
        item = event.EventObject.FindItemById(event.GetId())
        bucketName = item.GetText()
        self._bucketPanel.setBucketName(bucketName)

    def onViewChangedEvent(self, event):
        item = event.EventObject.FindItemById(event.GetId())
        text = item.GetText()
        wx.MessageBox(u"首先感谢您的支持!视图查看功能此版本不包含。该项功能正在加紧开发。", u"抱歉")

    def onSortChangedEvent(self, event):
        item = event.EventObject.FindItemById(event.GetId())
        text = item.GetText()
        self._bucketPanel.sortBy(text)

    def onCreateBucketEvent(self, event):
        wx.MessageBox(VERSION + u"版暂不支持此功能!", u"抱歉")

    def onConfigEvent(self, event):
        from libs.login import BucketConfigPanel

        class ConfigDialog(wx.Dialog):
            def __init__(self, parent):
                wx.Dialog.__init__(self, parent)
                conf = Config()
                boxSizer = wx.BoxSizer(wx.HORIZONTAL)
                b = BucketConfigPanel(self,
                                      conf.getBuckets().keys(), self.onOkBtn)
                boxSizer.Add(b, 1, wx.EXPAND)
                self.Layout()
                self.Center()

            def onOkBtn(self):
                self.Hide()
                self.Destroy()

        ConfigDialog(self).ShowModal()

    def onUploadEvent(self, event):
        webbrowser.open_new("http://github.com/ihaiker/QiniuAdminGui")

    def onAboutUserEvent(self, event):
        self.onUploadEvent(event)

    def onAboutSoftEvent(self, event):
        self.onUploadEvent(event)
Exemple #6
0
class BucketPanel(wx.Panel, wx.lib.mixins.listctrl.ColumnSorterMixin):
    def __init__(self, parent, auth):
        wx.Panel.__init__(self, parent)
        self.__frame = self.GetParent().GetParent()

        self.__auth = auth
        self.__bucketManger = qiniu.BucketManager(self.__auth)
        self.__conf = Config()

        self.__bucketName = ""
        self.__download_url = None
        self.__prefix = ""
        self.__marker = None
        self.__limit = LIMIT

        self.__initImages()

        self.__boxSizer = wx.BoxSizer()
        self.__dataList = self.__initList()
        self.__boxSizer.Add(self.__dataList, 1, wx.EXPAND)

        self.__initPopMenu()

        self.SetSizer(self.__boxSizer)

        # init column sorter
        wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self, LIMIT)

    def GetListCtrl(self):
        return self.__dataList

    def GetSortImages(self):
        return (self.down, self.up)

    def OnSortOrderChanged(self):
        self.__downloadButtonAndDeleteButtonStatus()

    def setBucketName(self, bucketName):

        ## 之所以放在这是因为,在初始化此面板的时候还未初始化toolbar
        self.__toolbar = self.__frame._toolbar

        self.__bucketName = bucketName  # 当前空间名称
        self.__download_url = self.__conf.getBuckets()[self.__bucketName]
        self.__resetStartLoad()

    def setPrefix(self, prefix):
        self.__prefix = prefix
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_BTN,False)
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_TEXT,False)
        self.__resetStartLoad()

    def setLimit(self, limit):
        self.__limit = limit
        self.__enableToolbar(ID.ID_TOOLBAR_LIMIT,False)
        self.__resetStartLoad()

    def getBucketName(self):
        return self.__bucketName

    def __resetStartLoad(self):
        """从头开始重新加载"""
        self.__marker = None    # 下一页marker,加载下一页的时候需要
        self.__store = Store()  # 保存数据
        self.__dataList.DeleteAllItems()
        AsynchronousThread(self.__loadData).start()

    def __initImages(self):
        # load some images into an image list
        self.__images_16x = wx.ImageList(16, 16, False)

        self.__icons = []
        for types, image in libs.mimetype.typeImage:
            self.__images_16x.Add(icons.mimeType('16x',image).GetBitmap())
            self.__icons.append(image)

        self.up = self.__images_16x.AddWithColourMask(icons.get("/sorter/up.png").GetBitmap(),"blue")
        self.down = self.__images_16x.AddWithColourMask(icons.get("/sorter/down.png").GetBitmap(),"blue")

    def __initList(self):
        list = wx.ListCtrl(self, -1, style=wx.LC_REPORT | wx.LC_SORT_ASCENDING | wx.BORDER_SUNKEN)
        # assign the image list to it
        list.AssignImageList(self.__images_16x, wx.IMAGE_LIST_SMALL)

        # Add some columns
        for col, text in enumerate([u"路径", u"类型", u"大小", u"上传时间"]):
            list.InsertColumn(col, text, wx.CENTER)

        # set the width of the columns in various ways
        list.SetColumnWidth(0, 320)
        list.SetColumnWidth(1, 120)
        list.SetColumnWidth(2, 80)
        list.SetColumnWidth(3, 140)

        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.__onTreeSelected, list)
        self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.__onTreeSelected, list)
        self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.__onTreeSelected, list)

        # rename event
        self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.__onEditNameStart, list)
        self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.__onEditNameEnd, list)
        # key up event (rename & delete)
        list.Bind(wx.EVT_KEY_UP, self.__onListKeyUp)

        #drop to download, bug bug
        #self.Bind(wx.EVT_LIST_BEGIN_DRAG, self._startDragEvent, list)

        return list

    def _startDragEvent(self, e):
        # create temp folder
        # folder = libs.config.WORK_PATH + "/temp"
        # libs.config.mkdirs(folder)

        text = self.__dataList.GetItem(e.GetIndex()).GetText()
        text = text if text[0] == "/" else "/" + text
        # temp_file = os.path.join(folder, os.path.basename(text if text[0] == "/" else "/" + text))

        # Create drag data
        data = wx.FileDataObject()
        data.AddFile(text)

        # Create drop source and begin drag-and-drop.
        dropSource = wx.DropSource(self.__dataList)
        dropSource.SetData(data)

        # Get Source
        res = dropSource.DoDragDrop(flags=wx.Drag_AllowMove)
        if res == wx.DragMove or res == wx.DragCopy:
            ## 下载
            print("DragMove & DragCopy")

        return text


    def __onTreeSelected(self, event):
        self.__downloadButtonAndDeleteButtonStatus()

    def __pageButtonStatus(self):
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_BTN,True)
        self.__enableToolbar(ID.ID_TOOLBAR_SEARCH_TEXT,True)
        self.__enableToolbar(ID.ID_TOOLBAR_LIMIT,True)

        self.__enableToolbar(ID.ID_TOOLBAR_NEXT_PAGE, self.__store.hasNext() or self.__marker != None)
        self.__enableToolbar(ID.ID_TOOLBAR_PREV_PAGE, self.__store.hasPrev())
        self.__updateStatus()
        self.__downloadButtonAndDeleteButtonStatus()

    def __downloadButtonAndDeleteButtonStatus(self):
        selected = self.__dataList.GetSelectedItemCount() > 0
        self.__enableToolbar(ID.ID_TOOLBAR_DOWNLOAD,
                             selected and self.__download_url != None and self.__download_url != "")
        self.__enableToolbar(ID.ID_TOOLBAR_TRASH, selected)

    def __loadNextData(self):
        if self.__store.hasNext():
            self.__showData(self.__store.next())
            self.__pageButtonStatus()
        elif self.__marker != None:
            AsynchronousThread(self.__loadData).start()

    def __loadPrevData(self):
        if self.__store.hasPrev():
            self.__showData(self.__store.prev())
        self.__pageButtonStatus()

    def __loadData(self):
        ret, eof, info = self.__bucketManger.list(bucket=self.__bucketName, marker=self.__marker,limit=self.__limit, prefix=self.__prefix)
        if info.ok():
            items = ret.get("items")
            self.__store.add(items)
            wx.CallAfter(self.__showData,items)
            if not eof:
                self.__marker = ret.get("marker")
            else:
                self.__marker = None
        else:
            if self.__marker != None:
                self.__enableToolbar(ID.ID_TOOLBAR_NEXT_PAGE, True)
            wx.MessageBox(info.error)

        self.__pageButtonStatus()

    def __showData(self, items):
        self.itemDataMap = {}
        for row, item in enumerate(items):
            name = item.get(u"key")
            fsize = libs.config.fileSizeShow(item.get(u"fsize"))
            putTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(round(item.get("putTime") / 10000 / 1000)))
            mimeType = item.get(u"mimeType")
            image = libs.mimetype.showType(mimeType, name)

            index = self.__dataList.InsertStringItem(sys.maxint, name)
            self.__dataList.SetStringItem(index, 1, mimeType)
            self.__dataList.SetStringItem(index, 2, fsize)
            self.__dataList.SetStringItem(index, 3, putTime)
            self.__dataList.SetItemData(index, row)

            # sort data
            self.itemDataMap[index] = (name, mimeType, item.get("fsize"), item.get("putTime"))

            # 设置图标
            self.__dataList.SetItemImage(index, self.__icons.index(image))

    def __initPopMenu(self):
        self.popupMenu = wx.Menu()

        urlMenu = self.popupMenu.Append(-1, u"复制地址", u"复制地址")
        self.Bind(wx.EVT_MENU, self.onCopyUrlEvent, urlMenu)

        self.popupMenu.AppendSeparator()

        deleteMenu = self.popupMenu.Append(-1, u"删除",u"删除选中文件")
        self.Bind(wx.EVT_MENU, self.onDeleteEvent, deleteMenu)

        refreshMenu = self.popupMenu.Append(-1, u"更新", u"强制更新缓存,保证上传的文件可以显示最新")
        self.Bind(wx.EVT_MENU, self.onRefreshCacheEvent, refreshMenu)

        renameMenu = self.popupMenu.Append(-1, u"重命名", u"重命名")
        self.Bind(wx.EVT_MENU, self.onRenameEvent, renameMenu)

        downloadMenu = self.popupMenu.Append(-1, u"下载", u"下载选中文件")
        self.Bind(wx.EVT_MENU, self.__frame.onDownloadFileEvent, downloadMenu)

        self.Bind(wx.EVT_CONTEXT_MENU, self.__onShowPopup)

    def __onShowPopup(self, event):
        if len(self.getSelectedFiles()) != 0 :
            pos = event.GetPosition()
            pos = self.ScreenToClient(pos)
            self.PopupMenu(self.popupMenu, pos)
        else:
            ##没有选中文件,不可操作
            pass

    def __onPopupItemSelected(self, event):
        item = self.popupMenu.FindItemById(event.GetId())
        text = item.GetText()
        wx.MessageBox("You selected item '%s'" % text)

    def __onListKeyUp(self, event):
        keyCode = event.GetKeyCode()
        if keyCode == wx.WXK_DELETE:
            self.onDeleteEvent(event)

        elif keyCode == wx.WXK_F2:
            if len(self.getSelectedFiles()) == 1:
                self.onRenameEvent(event)

        elif event.ControlDown() and keyCode == 67:
            self.onCopyUrlEvent(event)

        elif event.ControlDown() and keyCode == 65:
            for index in range(self.__dataList.GetItemCount()):
                self.__dataList.Select(index, True)

        event.Skip()

    def __onEditNameStart(self, event):
        print("重命名开始")

    def __onEditNameEnd(self, event):
        print("重命名结束")

    def getSelectedFiles(self):
        files = []
        index = self.__dataList.GetFirstSelected()
        while index != -1:
            item = self.__dataList.GetItem(index)
            key = item.GetText()
            mimeType = self.itemDataMap[index][1]
            fileSize = self.itemDataMap[index][2]
            base_url = 'http://%s/%s' % (self.__download_url, key)
            private_url = self.__auth.private_download_url(base_url, expires=3600)
            files.append((private_url,key,mimeType,fileSize))
            index = self.__dataList.GetNextSelected(index)

        return files

    def onRefreshEvent(self,event):
        self.__resetStartLoad()

    def onNextPageEvent(self, event):
        self.__dataList.DeleteAllItems()
        self.__enableToolbar(ID.ID_TOOLBAR_NEXT_PAGE)
        self.__loadNextData()

    def onPrevPageEvent(self, event):
        self.__dataList.DeleteAllItems()
        self.__enableToolbar(ID.ID_TOOLBAR_PREV_PAGE)
        self.__loadPrevData()

    def onCopyUrlEvent(self, event):
        files = self.getSelectedFiles()
        value = ""
        for url, key, mimeType, fileSize in files:
            value += url + "\n"

        data = wx.TextDataObject()
        data.SetText(value)
        if wx.TheClipboard.Open():
            wx.TheClipboard.SetData(data)
            wx.TheClipboard.Close()
        else:
            wx.MessageBox(u"不能打开剪切板!", u"复制错误")

    def onDeleteEvent(self, event):
        """删除文件"""
        self.__enableToolbar(ID.ID_TOOLBAR_TRASH,False)
        message = u"您确定删除以下文件?\n"
        files = []
        index = self.__dataList.GetFirstSelected()
        while index != -1:
            item = self.__dataList.GetItem(index)
            key = item.GetText()
            message += key + "\n"
            files.append(key)
            index = self.__dataList.GetNextSelected(index)

        results = dialogs.messageDialog(self,message,"Sure?")
        if results.accepted :
            AsynchronousThread((self.deleteSelectedFile,files)).start()
        else:
            self.__downloadButtonAndDeleteButtonStatus()

    def deleteSelectedFile(self,files):
        ops = build_batch_delete(self.__bucketName, files)
        ret, info = self.__bucketManger.batch(ops)
        if info.ok() :
            wx.CallAfter(wx.MessageBox,u"删除成功",u"提示")
            wx.CallAfter(self.setBucketName, self.__bucketName)
        else:
            wx.CallAfter(wx.MessageBox,info.error)

    def onRefreshCacheEvent(self, event):
        """刷新缓存"""
        files = self.getSelectedFiles()
        for url,key,mimeType,fileSize in files :
            self.__bucketManger.prefetch(self.__bucketName, key)

        wx.MessageBox(u"更新成功",u"Note")

    def onRenameEvent(self, event):
        """重命名"""
        selected = len(self.getSelectedFiles())
        if selected == 1:
            # self.__onEditNameStart(event)
            index = self.__dataList.GetFirstSelected()
            key = self.itemDataMap[index][0]
            results = dialogs.textEntryDialog(self, u"请输入修改的名字", u"重命名", key)
            if results.accepted :
                newKey = results.text
                try:
                    ret, info = self.__bucketManger.rename(self.__bucketName, key, newKey)
                    if info.ok():
                        wx.MessageBox(u"重命名成功!", u"成功")
                    else:
                        wx.MessageBox(info.error, u"错误")
                except:
                    wx.MessageBox(u"名字错误,查阅七牛文档!", u"错误")
        else:
            wx.MessageBox(u"不能同时重命名多个文件!", u"错误")


    def onSearchEvent(self, event):
        if isinstance(event,wx.KeyEvent):
            keycode = event.GetKeyCode()
            if keycode == wx.WXK_RETURN or keycode == wx.WXK_NUMPAD_ENTER :
                pass
            else:
                event.Skip()
                return True

        textCtrl = self.__frame._toolbar.FindById(ID.ID_TOOLBAR_SEARCH_TEXT).GetControl()
        self.setPrefix(textCtrl.GetValue())

    def onPageLimitEvent(self, event):
        limit = int(event.EventObject.GetStringSelection(), 10)
        self.setLimit(limit)
        event.Skip()

    def sortBy(self, type):
        dict = {u"名称": 0, u"大小": 2, u"时间": 3}
        idx = dict[type]
        def compare_func(row1, row2):
            val1 = self.itemDataMap[row1][idx]
            val2 = self.itemDataMap[row2][idx]
            if val1 < val2:
                return -1
            elif val1 > val2:
                return 1
            else:
                return 0

        self.__dataList.SortItems(compare_func)

    def __enableToolbar(self, id, enable=False):
        """禁用或者启用某个菜单"""
        self.__toolbar.EnableTool(id, enable)

    def __updateStatus(self):
        moreMark = "+"
        if self.__marker == None:
            moreMark = ""
        statusText = (u"空间:%s" % (self.__bucketName))
        self.__frame.SetStatusText(statusText, 2)
        statusText = (u"页码:%d/%d%s" % (self.__store.page(), self.__store.length(),moreMark))
        self.__frame.SetStatusText(statusText, 3)
Exemple #7
0
class BucketConfigPanel(wx.Panel):
    def __init__(self, parent, buckets, onConfigSuccess):
        wx.Panel.__init__(self, parent, style=wx.BORDER_SIMPLE)
        self.frame = parent
        self.onConfigSuccess = onConfigSuccess
        self.buckets = buckets
        self.conf = Config()

        self.startConfigBucket()

    def startConfigBucket(self):
        mainSizer = wx.BoxSizer(wx.VERTICAL)

        title = wx.StaticText(self, -1, u"配置空间下载域名")
        title.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD))

        mainSizer.Add((0, 10))
        mainSizer.Add(title, 0, wx.CENTER | wx.TOP | wx.BOTTOM, 10)
        mainSizer.Add((0, 10))
        mainSizer.Add(wx.StaticLine(self), 0, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)

        configBuckets = self.conf.getBuckets()

        self.bucketsSizer = wx.FlexGridSizer(cols=3, hgap=3, vgap=3)
        for idx, bucket in enumerate(self.buckets):
            domain = configBuckets.get(bucket) or ""
            bucketName = wx.StaticText(self, -1, bucket)
            self.bucketsSizer.Add(bucketName, 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL)

            bucketDomain = wx.TextCtrl(self, -1, domain, size=(160,25))
            bucketDomain.SetHint(u"未配置部分功能不可使用")
            self.bucketsSizer.Add(bucketDomain, 2, wx.EXPAND)

            bmp = libs.icons.get("/status/question.png").GetBitmap()
            button = wx.BitmapButton(self, -1, bmp)
            self.bucketsSizer.Add(button, 0, wx.EXPAND)

        self.bucketsSizer.AddGrowableCol(1)
        mainSizer.Add(self.bucketsSizer, 0, wx.EXPAND | wx.ALL, 5)

        okBtn = wx.Button(self, -1, u"确定")
        okBtn.Bind(wx.EVT_BUTTON, self.endConfigBucket)

        exitBtn = wx.Button(self, -1, u"退出")
        exitBtn.Bind(wx.EVT_BUTTON, self.OnExit)

        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add((50, 20))
        btnSizer.Add(okBtn,1)
        btnSizer.Add((50, 20))
        btnSizer.Add(exitBtn,1)
        btnSizer.Add((50, 20))
        mainSizer.Add(btnSizer, 0, wx.EXPAND | wx.ALL, 10)
        self.SetSizer(mainSizer)

    def endConfigBucket(self, event):
        items = self.bucketsSizer.GetChildren()
        buffers = {}
        for idx in range(0, len(items) / 3):
            if idx * 3 + 1 < len(items):
                input = items[idx * 3 + 1]
                bucketName = items[idx*3].GetWindow().GetLabelText()
                oldDomain = input.GetWindow().GetLabelText()
                domain = input.GetWindow().GetValue()
                if oldDomain != domain:
                    print(u"检查【%s】下载地址: http://%s"%(bucketName,domain))

                buffers[bucketName] = domain

        self.conf.setBuckets(buffers)
        self.onConfigSuccess()

    def OnExit(self, evt):
        self.frame.Hide()
        self.frame.Destroy()