def _showWebMenu(self, pos): """显示网页右键菜单 :param pos: 点击位置 """ hit = self.webViewContent.page().currentFrame().hitTestContent(pos) url = hit.linkUrl() if url.isValid(): path = url.toLocalFile().strip().replace('\\', '/') names = path.split('Markdown/') if len(names) == 1: return path = os.path.abspath(os.path.join( Constants.DirCurrent, names[1])) AppLog.debug('path: {}'.format(path)) AppLog.debug('isdir: {}'.format(os.path.isdir(path))) self._webviewactRun.setData(path) self._webviewactView.setData(path) self._webviewactFolder.setData(path) if os.path.exists(path) and os.path.isdir(path): self._webviewactRun.setVisible(False) self._webviewactView.setVisible(False) self._webviewactFolder.setVisible(True) elif os.path.exists(path) and os.path.isfile(path): self._webviewactRun.setVisible(True) self._webviewactView.setVisible(True) self._webviewactFolder.setVisible(True) self._webviewMenu.exec_(QCursor.pos())
def initCatalog(self): """初始化本地仓库结构树 """ AppLog.debug('') if not os.path.exists(Constants.DirProjects): return pitem = self._dmodel.invisibleRootItem() # 只遍历根目录 for name in os.listdir(Constants.DirProjects): file = os.path.join(Constants.DirProjects, name).replace('\\', '/') if os.path.isfile(file): # 跳过文件 continue if name.startswith( '.') or name == 'Donate' or name == 'Test': # 不显示.开头的文件夹 continue items = self.findItems(name) if items: item = items[0] else: item = QStandardItem(name) # 添加自定义的数据 # 用于绘制进度条的item标识 item.setData(True, Constants.RoleRoot) # 目录或者文件的绝对路径 item.setData( os.path.abspath(os.path.join(Constants.DirProjects, name)), Constants.RolePath) pitem.appendRow(item) # 遍历子目录 self.listSubDir(item, file) # 排序 self._fmodel.sort(0, Qt.AscendingOrder)
def onLoginErrored(self, message): AppLog.debug('onLoginErrored') self._isLogin = False self.buttonLogin.showWaiting(False) self.setEnabled(True) AppLog.error(message) if message: self.labelNotice.setText(message)
def onReadChannelFinished(self): process = self.sender() message = process.readAllStandardError().data().decode() if process.exitCode() != 0 and len(message.strip()) > 0: file = str(process.property('file')) reqfile = os.path.abspath(os.path.join( os.path.dirname(file), 'requirements.txt')) AppLog.debug('reqfile: {}'.format(reqfile)) dialog = ErrorDialog(message, self, reqfile=reqfile) dialog.exec_()
def createRequest(self, op, originalReq, outgoingData): """创建请求 :param op: 操作类型见http://doc.qt.io/qt-5/qnetworkaccessmanager.html#Operation-enum :param originalReq: 原始请求 :param outgoingData: 输出数据 """ url = originalReq.url() surl = url.toString() AppLog.debug('access url: {}'.format(surl)) if surl.endswith('Donate'): # 点击了打赏 originalReq.setUrl(QUrl()) return super(NetworkAccessManager, self).createRequest(op, originalReq, outgoingData) elif surl.endswith('k=5QVVEdF'): # 点击了QQ群链接 webbrowser.open(Constants.UrlGroup) originalReq.setUrl(QUrl()) return super(NetworkAccessManager, self).createRequest(op, originalReq, outgoingData) if url.scheme() == 'tencent': # 调用tx的app webbrowser.open(surl) originalReq.setUrl(QUrl()) elif url.scheme() == 'file': # 本地文件,比如一些图片文件等 names = surl.split('Markdown/') if len(names) > 1: rname = names[1] path = os.path.join(Constants.DirCurrent, rname).replace('\\', '/') if os.path.exists(path) and os.path.isfile(path): if rname[-3:] == '.py': originalReq.setUrl(QUrl()) # 运行py文件 Signals.runExampled.emit(path) else: originalReq.setUrl(QUrl.fromLocalFile(path)) elif os.path.exists(path) and os.path.isdir(path): if rname.count('/') == 0: # 跳转到左侧目录树 originalReq.setUrl(QUrl()) Signals.itemJumped.emit(rname) else: # 只加载文件,不加载其它网页 if not mimetypes.guess_type(url.fileName())[0]: originalReq.setUrl(QUrl()) # 调用系统打开网页 webbrowser.open_new_tab(surl) return super(NetworkAccessManager, self).createRequest(op, originalReq, outgoingData)
def onDoubleClicked(self, modelIndex): """Item双击 :param modelIndex: 此处是代理模型中的QModelIndex, 并不是真实的 """ root = modelIndex.data(Constants.RoleRoot) path = modelIndex.data(Constants.RolePath) AppLog.debug('is root: {}'.format(root)) AppLog.debug('path: {}'.format(path)) if not root and os.path.isfile(path): # 运行代码 Signals.runExampled.emit(path)
def renderReadme(self, path=''): """加载README.md并显示 """ path = path.replace('\\', '/') if not path: path = os.path.join(Constants.DirProjects, 'README.md') Constants.CurrentReadme = '' elif path.count('/') == 0: path = os.path.join(Constants.DirCurrent, path, 'README.md') Constants.CurrentReadme = path elif not path.endswith('README.md'): path = path + '/README.md' Constants.CurrentReadme = path if not os.path.exists(path): AppLog.debug('{} not exists'.format(path)) self._runJs('updateText("");') return if not os.path.isfile(path): AppLog.warn('file {} not exists'.format(path)) return Constants.DirCurrent = os.path.dirname(path).replace('\\', '/') AppLog.debug('DirCurrent change to: {}'.format(Constants.DirCurrent)) AppLog.debug('render: {}'.format(path)) Constants.CurrentReadme = path # 记录打开的路径防止重复加载 AppLog.debug('readme dir: {}'.format(Constants.DirCurrent)) content = repr(open(path, 'rb').read().decode()) self._runJs("updateText({});".format(content))
def run(self): try: req = requests.get( UrlGetAppsByCategory.format(category=self.category, pageno=1, count=20, time=time())) content = req.json() errno = content.get('errno', 0) AppLog.debug('errno: %s', errno) AppLog.debug('msg: %s', content.get('msg', '')) if errno != 0: return content = content.get('data', {}) AppLog.debug('total_count: %s', content.get('total_count', '')) AppLog.debug('total_page: %s', content.get('total_page', '')) items = content.get('list', []) for i, item in enumerate(items): title = item.get('title', '') url = item.get('image', None) if not url: continue self.download(i, title, url) QThread.msleep(200) QThread.yieldCurrentThread() except Exception as e: AppLog.exception(e) Signals.pictureDownFinished.emit(self.widget)
def run(self): AppLog.info('start login github') try: req = requests.get(self.Url, auth=HTTPBasicAuth( self.account, self.password)) retval = req.json() if retval.get('message', '') == 'Bad credentials': Signals.loginErrored.emit(QCoreApplication.translate( 'Repository', 'Incorrect account or password')) AppLog.warn('Incorrect account or password') LoginThread.quit() return if 'login' not in retval: Signals.loginErrored.emit(QCoreApplication.translate( 'Repository', 'Login failed, Unknown reason')) AppLog.warn('Login failed, Unknown reason') LoginThread.quit() return # 用户ID uid = retval.get('id', 0) AppLog.debug('user id: {}'.format(uid)) # 用户昵称 name = retval.get('name', 'Unknown') AppLog.debug('user name: {}'.format(name)) # 用户头像地址 avatar_url = retval.get('avatar_url', '') if avatar_url: # 获取头像 self.get_avatar(uid, avatar_url) Signals.loginSuccessed.emit(str(uid), name) except ConnectTimeout as e: Signals.loginErrored.emit(QCoreApplication.translate( 'Repository', 'Connect Timeout')) AppLog.exception(e) except ConnectionError as e: Signals.loginErrored.emit(QCoreApplication.translate( 'Repository', 'Connection Error')) AppLog.exception(e) except Exception as e: Signals.loginErrored.emit(QCoreApplication.translate( 'Repository', 'Unknown Error')) AppLog.exception(e) AppLog.info('login thread end') LoginThread.quit()
def _initUi(self): """初始UI""" self.setupUi(self) # 隐藏还原按钮 self.buttonNormal.setVisible(False) # 隐藏目录树的滑动条 self.treeViewCatalogs.verticalScrollBar().setVisible(False) # 加载鼠标样式 ThemeManager.loadCursor(self.widgetMain) ThemeManager.setPointerCursors([ self.buttonHead, # 主界面头像 self.buttonClear, # 主界面清空按钮 self.buttonGithub, # Github按钮 self.buttonQQ, # QQ按钮 self.buttonGroup, # 群按钮 self.buttonBackToUp, # 返回顶部按钮 self.buttonHome # 显示主页readme ]) # 安装事件过滤器用于还原鼠标样式 self.widgetMain.installEventFilter(self) # 绑定返回顶部提示框 ToolTip.bind(self.buttonBackToUp) ToolTip.bind(self.buttonHome) # 头像提示控件 ToolTip.bind(self.buttonHead) # 加载主题 colourful = Setting.value('colourful') picture = Setting.value('picture', '', str) AppLog.debug('colourful: %s', str(colourful)) AppLog.debug('picture: %s', picture) if picture: ThemeManager.loadFont() ThemeManager.loadPictureTheme(picture) elif colourful: ThemeManager.loadFont() if isinstance(picture, QColor): ThemeManager.loadColourfulTheme(colourful) else: # json数据转渐变 ThemeManager.loadColourfulTheme( GradientUtils.toGradient(colourful)) else: ThemeManager.loadTheme()
def onClicked(self, modelIndex): """Item单击 :param modelIndex: 此处是代理模型中的QModelIndex, 并不是真实的 """ root = modelIndex.data(Constants.RoleRoot) path = modelIndex.data(Constants.RolePath) code = modelIndex.data(Constants.RoleCode) AppLog.debug('is root: {}'.format(root)) AppLog.debug('path: {}'.format(path)) if not root and os.path.isfile(path) and code: # 右侧显示代码 Signals.showCoded.emit(code) if root and os.path.isdir(path): if self.isExpanded(modelIndex): self.collapse(modelIndex) else: self.expand(modelIndex) # 显示readme Signals.showReadmed.emit(os.path.join(path, 'README.md'))
def onLoginSuccessed(self, uid, name): AppLog.debug('onLoginSuccessed') self._isLogin = False self.buttonLogin.showWaiting(False) self.setEnabled(True) # 用账号密码实例化github访问对象 account = self.lineEditAccount.text().strip() password = self.lineEditPassword.text().strip() Constants._Account = account Constants._Password = password Constants._Username = name # 储存账号密码 Setting.setValue('account', account) if account not in self._accounts: # 更新账号数组 self._accounts[account] = [ uid, base64.b85encode(password.encode()).decode()] Setting.setValue('accounts', self._accounts) self.accept()
def get_avatar(self, uid, avatar_url): try: req = requests.get(avatar_url) if req.status_code == 200: imgformat = req.headers.get( 'content-type', 'image/jpg').split('/')[1] Constants.ImageAvatar = os.path.join( Constants.ImageDir, str(uid)).replace('\\', '/') + '.jpg' AppLog.debug('image type: {}'.format(imgformat)) AppLog.debug( 'content length: {}'.format(len(req.content))) image = QImage() if image.loadFromData(req.content): # 缩放图片 if not image.isNull(): image = image.scaled(130, 130, Qt.IgnoreAspectRatio, Qt.SmoothTransformation) AppLog.debug('save to: {}'.format( Constants.ImageAvatar)) image.save(Constants.ImageAvatar) else: AppLog.warn('avatar image is null') else: AppLog.warn('can not load from image data') except Exception as e: AppLog.exception(e)
def download(self, file, url): AppLog.debug('start download {}'.format(url)) with closing(requests.get(url, stream=True)) as response: # 单次请求最大值 chunk_size = 1024 # 内容体总大小 content_size = int(response.headers['content-length']) data_count = 0 Signals.updateProgressChanged.emit(0, 0, content_size) AppLog.debug('content_size: {}'.format(content_size)) with open(file, 'wb') as fp: for data in response.iter_content(chunk_size=chunk_size): fp.write(data) data_count = data_count + len(data) if content_size > 0: Signals.updateProgressChanged.emit( data_count, 0, content_size) # 解压 self.unzip(file) AppLog.debug('download {} end'.format(file))
def transfer_progress(self, stats): Signals.progressUpdated.emit( stats.received_objects, stats.total_objects) AppLog.debug('total: {}, received: {}'.format( stats.total_objects, stats.received_objects))