class WeCaseWindow(QtGui.QMainWindow, Ui_frm_MainWindow): client = None uid = None imageLoaded = QtCore.pyqtSignal(str) tabTextChanged = QtCore.pyqtSignal(int, str) def __init__(self, client, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.myView] self.client = client self.setupModels() self.init_account() self.setupMyUi() self.loadConfig() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] def init_account(self): self.get_uid() def loadConfig(self): self.config = ConfigParser() self.config.read(const.config_path) if not self.config.has_section("main"): self.config["main"] = {} self.main_config = self.config["main"] self.timer_interval = int(self.main_config.get("notify_interval", 30)) self.notify_timeout = int(self.main_config.get("notify_timeout", 5)) self.remindMentions = self.main_config.getboolean("remind_mentions", 1) self.remindComments = self.main_config.getboolean("remind_comments", 1) def applyConfig(self): try: self.timer.stop_event.set() except AttributeError: pass self.timer = WTimer(self.timer_interval, self.show_notify) self.timer.start() self.notify.timeout = self.notify_timeout def setupMyUi(self): for tweetView in self.tweetViews: tweetView.setResizeMode(tweetView.SizeRootObjectToView) tweetView.setSource(QtCore.QUrl.fromLocalFile(const.myself_path + "/ui/TweetList.qml")) tweetView.rootContext().setContextProperty("mainWindow", self) @QtCore.pyqtSlot() def load_more(self): model = self.get_current_model() model.next() def setupModels(self): self.all_timeline = TweetCommonModel(TweetItem(), self.client.statuses.home_timeline, self) self.all_timeline.load() self.homeView.rootContext().setContextProperty("mymodel", self.all_timeline) self.mentions = TweetCommonModel(TweetItem(), self.client.statuses.mentions, self) self.mentions.load() self.mentionsView.rootContext().setContextProperty("mymodel", self.mentions) self.comment_to_me = TweetCommentModel(TweetItem(), self.client.comments.to_me, self) self.comment_to_me.load() self.commentsView.rootContext().setContextProperty("mymodel", self.comment_to_me) self.my_timeline = TweetCommonModel(TweetItem(), self.client.statuses.user_timeline, self) self.my_timeline.load() self.myView.rootContext().setContextProperty("mymodel", self.my_timeline) def reset_remind(self): if self.tabWidget.currentIndex() == 0: self.tabWidget.setTabText(0, self.tr("Weibo")) elif self.tabWidget.currentIndex() == 1: self.client.remind.set_count.post(type="mention_status") self.tabWidget.setTabText(1, self.tr("@Me")) elif self.tabWidget.currentIndex() == 2: self.client.remind.set_count.post(type="cmt") self.tabWidget.setTabText(2, self.tr("Comments")) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" reminds = self.client.remind.unread_count.get(uid=uid) return reminds def get_uid(self): """How can I get my uid? here it is""" try: self.uid = self.client.account.get_uid.get().uid except AttributeError: return None def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid) msg = self.tr("You have:") + "\n" num_msg = 0 if reminds["status"] != 0: # Note: do NOT send notify here, or users will crazy. self.tabTextChanged.emit(0, self.tr("Weibo(%d)") % reminds["status"]) if reminds["mention_status"] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds["mention_status"] + "\n" self.tabTextChanged.emit(1, self.tr("@Me(%d)") % reminds["mention_status"]) num_msg += 1 if reminds["cmt"] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds["cmt"] + "\n" self.tabTextChanged.emit(2, self.tr("Comments(%d)") % reminds["cmt"]) num_msg += 1 if num_msg: return self.notify.showMessage(self.tr("WeCase"), msg) def setTabText(self, index, string): self.tabWidget.setTabText(index, string) def moveToTop(self): self.get_current_tweetView().rootObject().positionViewAtBeginning() def setLoaded(self, tweetid): self.get_current_tweetView().rootObject().imageLoaded(tweetid) def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow() wecase_login.exec_() def postTweet(self): wecase_new = NewpostWindow() wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str) def comment(self, idstr): wecase_new = NewpostWindow(action="comment", id=int(idstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def repost(self, idstr, text): wecase_new = NewpostWindow(action="retweet", id=int(idstr), text=text) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, result=int) def favorite(self, idstr): try: self.client.favorites.create.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, result=bool) def un_favorite(self, idstr): try: self.client.favorites.destroy.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, str) def reply(self, idstr, cidstr): wecase_new = NewpostWindow(action="reply", id=int(idstr), cid=int(cidstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def look_orignal_pic(self, thumbnail_pic, tweetid): threading.Thread(group=None, target=self.fetch_open_original_pic, args=(thumbnail_pic, tweetid)).start() def fetch_open_original_pic(self, thumbnail_pic, tweetid): """Fetch and open original pic from thumbnail pic url. Pictures will stored in cache directory. If we already have a same name in cache directory, just open it. If we don't, then download it first.""" if tweetid in self.download_lock: return self.download_lock.append(tweetid) original_pic = thumbnail_pic.replace("thumbnail", "large") # A simple trick ... ^_^ localfile = const.cache_path + original_pic.split("/")[-1] if not os.path.exists(localfile): urllib.request.urlretrieve(original_pic, localfile) self.download_lock.remove(tweetid) os.popen("xdg-open " + localfile) # xdg-open is common? self.imageLoaded.emit(tweetid) def refresh(self): model = self.get_current_model() model.timelineLoaded.connect(self.moveToTop) # model.clear() # model.load() model.new() self.reset_remind() def get_current_tweetView(self): tweetViews = {0: self.homeView, 1: self.mentionsView, 2: self.commentsView, 3: self.myView} return tweetViews[self.tabWidget.currentIndex()] def get_current_model(self): models = {0: self.all_timeline, 1: self.mentions, 2: self.comment_to_me, 3: self.my_timeline} return models[self.tabWidget.currentIndex()] def get_current_function(self): functions = { 0: self.get_all_timeline, 1: self.get_mentions_timeline, 2: self.get_comment_to_me, 3: self.get_my_timeline, } return functions[self.tabWidget.currentIndex()] def closeEvent(self, event): self.timer.stop_event.set()
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): image = None apiError = QtCore.pyqtSignal(Exception) commonError = QtCore.pyqtSignal(str, str) sendSuccessful = QtCore.pyqtSignal() userClicked = QtCore.pyqtSignal(UserItem, bool) tagClicked = QtCore.pyqtSignal(str, bool) tweetRefreshed = QtCore.pyqtSignal() tweetRejected = QtCore.pyqtSignal() def __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage) self.errorWindow = APIErrorWindow(self) if self.action not in ["new", "reply"]: self.tweetRefreshed.connect(self._create_tweetWidget) self.tweetRejected.connect(lambda: self.pushButton_send.setEnabled(False)) self._refresh() def setupUi(self, widget): super(NewpostWindow, self).setupUi(widget) self.sendAction = QtGui.QAction(self) self.sendAction.triggered.connect(self.send) self.sendAction.setShortcut(QtGui.QKeySequence("Ctrl+Return")) self.addAction(self.sendAction) self.checkChars() self.setupButtons() def setupButtons(self): # Disabled is the default state of buttons self.pushButton_picture.setEnabled(False) self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) if self.action == "new": assert (not self.tweet) # Shouldn't have a tweet object. self.pushButton_picture.setEnabled(True) elif self.action == "retweet": self.chk_comment.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.textEdit.setText(self.tweet.append_existing_replies()) self.chk_comment_original.setEnabled(True) elif self.action == "comment": self.chk_repost.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) elif self.action == "reply": self.chk_repost.setEnabled(True) if self.tweet.original.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) else: assert False @async def _refresh(self): # The read count is not a real-time value. So refresh it now. try: self.tweet.refresh() except APIError as e: self.errorWindow.raiseException.emit(e) self.tweetRejected.emit() return self.tweetRefreshed.emit() def _create_tweetWidget(self): if self.action == "comment" and self.tweet.comments_count: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) self.replyModel = TweetUnderCommentModel(self.client.api("comments/show"), self.tweet.id, self) elif self.action == "retweet" and self.tweet.retweets_count: if self.tweet: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) elif self.tweet.original: self.tweetWidget = SingleTweetWidget(self.tweet.original, ["image", "original"], self) self.replyModel = TweetRetweetModel(self.client.api("statuses/repost_timeline"), self.tweet.id, self) else: return self.replyModel.load() self.splitter = QtGui.QSplitter(self) self.splitter.setOrientation(QtCore.Qt.Vertical) self.verticalLayout.insertWidget(0, self.splitter) self.tweetWidget.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.splitter.addWidget(self.tweetWidget) self.commentsWidget = TweetListWidget(self, ["image", "original"]) self.commentsWidget.setModel(self.replyModel) self.commentsWidget.scrollArea.setMinimumSize(20, 200) self.commentsWidget.userClicked.connect(self.userClicked) self.commentsWidget.tagClicked.connect(self.tagClicked) self.splitter.addWidget(self.commentsWidget) self.splitter.addWidget(self.textEdit) def mentions_suggest(self, text): ret_users = [] try: word = text.split(' ')[-1] word = word.split('@')[-1] except IndexError: return [] if not word.strip(): return [] users = self.client.api("search/suggestions/at_users").get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def sent(self): self._sent = True self.close() def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": self.new() elif self.action == "retweet": self.retweet() elif self.action == "comment": self.comment() elif self.action == "reply": self.reply() else: # If action is in other types, it must be a mistake. assert False @async def retweet(self): text = self.textEdit.toPlainText() comment = int(self.chk_comment.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.retweet(text, comment, comment_ori) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() @async def comment(self): text = self.textEdit.toPlainText() retweet = int(self.chk_repost.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.comment(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() @async def reply(self): text = self.textEdit.toPlainText() comment_ori = int(self.chk_comment_original.isChecked()) retweet = int(self.chk_repost.isChecked()) try: self.tweet.reply(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() @async def new(self): text = self.textEdit.toPlainText() try: if self.image: try: if getsize(self.image) > const.MAX_IMAGE_BYTES: raise ValueError with open(self.image, "rb") as image: self.client.api("statuses/upload").post(status=text, pic=image) except (OSError, IOError): self.commonError.emit(self.tr("File not found"), self.tr("No such file: %s") % self.image) self.addImage() # In fact, remove image... return except ValueError: self.commonError.emit(self.tr("Too large size"), self.tr("This image is too large to upload: %s") % self.image) self.addImage() # In fact, remove image... return else: self.client.api("statuses/update").post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(e) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.jpeg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("&Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) self.textEdit.setFocus() def showException(self, e): if "Text too long" in str(e): QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: self.errorWindow.raiseException.emit(e) self.pushButton_send.setEnabled(True) def showErrorMessage(self, title, text): QtGui.QMessageBox.warning(self, title, text) def showSmiley(self): wecase_smiley = FaceWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.faceName) self.textEdit.setFocus() def checkChars(self): """Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.""" text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens)) def reject(self): self.close() def closeEvent(self, event): # We have unsend text. if (not self._sent) and (self.textEdit.toPlainText()): choice = QtGui.QMessageBox.question( self, self.tr("Close?"), self.tr("All unpost text will lost."), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if choice == QtGui.QMessageBox.No: event.ignore() else: self.setParent(None)
class WeCaseWindow(QtGui.QMainWindow): client = None uid = None timelineLoaded = QtCore.pyqtSignal(int) imageLoaded = QtCore.pyqtSignal(str) tabBadgeChanged = QtCore.pyqtSignal(int, int) tabAvatarFetched = QtCore.pyqtSignal(str) def __init__(self, username, parent=None): super(WeCaseWindow, self).__init__(parent) self.username = username LoginInfo().add_account(self.username) self.errorWindow = APIErrorWindow(self) self.setAttribute(QtCore.Qt.WA_QuitOnClose, True) self._iconPixmap = {} self.setupUi(self) self._setupSysTray() self.tweetViews = [ self.homeView, self.mentionsView, self.commentsView, self.commentsMentionsTab ] self.info = WeRuntimeInfo() self.client = const.client self.loadConfig() self.init_account() self.setupModels() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] self._last_reminds_count = 0 self._setupUserTab(self.uid(), False, True) def _setupTab(self, view): tab = QtGui.QWidget() layout = QtGui.QGridLayout(tab) layout.addWidget(view) view.setParent(tab) return tab def _setupCommonTab(self, timeline, view, switch=True, protect=False): self._prepareTimeline(timeline) view.setModel(timeline) view.userClicked.connect(self.userClicked) view.tagClicked.connect(self.tagClicked) tab = self._setupTab(view) self.tabWidget.addTab(tab, "") if switch: self.tabWidget.setCurrentWidget(tab) if protect: self.tabWidget.tabBar().setProtectTab(tab, True) return tab def _getSameTab(self, attr, value): for i in range(self.tabWidget.count()): try: tab = self.tabWidget.widget(i).layout().itemAt(0).widget() _value = getattr(tab.model(), attr)() if _value == value: return i except AttributeError: pass return False def _setupUserTab(self, uid, switch=True, myself=False): index = self._getSameTab("uid", uid) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() _timeline = TweetUserModel(self.client.api("statuses/user_timeline"), uid, view) timeline = TweetFilterModel(_timeline) timeline.setModel(_timeline) tab = self._setupCommonTab(timeline, view, switch, myself) def setAvatar(f): self._setTabIcon(tab, WObjectCache().open(QtGui.QPixmap, f)) fetcher = AsyncFetcher("".join( (path.cache_path, str(self.info["uid"])))) fetcher.addTask( self.client.api("users/show").get(uid=uid)["profile_image_url"], setAvatar) def _setupTopicTab(self, topic, switch=True): index = self._getSameTab("topic", topic) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() timeline = TweetTopicModel(self.client.api("search/topics"), topic, view) tab = self._setupCommonTab(timeline, view, switch, protect=False) self._setTabIcon( tab, WObjectCache().open(QtGui.QPixmap, ":/IMG/img/topic.jpg")) def userClicked(self, userItem, openAtBackend): try: self._setupUserTab(userItem.id, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def tagClicked(self, str, openAtBackend): try: self._setupTopicTab(str, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def setupUi(self, mainWindow): mainWindow.setWindowIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) mainWindow.setDocumentMode(False) mainWindow.setDockOptions(QtGui.QMainWindow.AllowTabbedDocks | QtGui.QMainWindow.AnimatedDocks) self.centralwidget = QtGui.QWidget(mainWindow) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.tabWidget = QtGui.QTabWidget(self.centralwidget) self.tabWidget.setTabBar(WTabBar(self.tabWidget)) self.tabWidget.setTabPosition(QtGui.QTabWidget.West) self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded) self.tabWidget.setDocumentMode(False) self.tabWidget.setMovable(True) self.tabWidget.tabCloseRequested.connect(self.closeTab) self.homeView = TweetListWidget() self.homeView.userClicked.connect(self.userClicked) self.homeView.tagClicked.connect(self.tagClicked) self.homeTab = self._setupTab(self.homeView) self.tabWidget.addTab(self.homeTab, "") self.tabWidget.tabBar().setProtectTab(self.homeTab, True) self.mentionsView = TweetListWidget() self.mentionsView.userClicked.connect(self.userClicked) self.mentionsView.tagClicked.connect(self.tagClicked) self.mentionsTab = self._setupTab(self.mentionsView) self.tabWidget.addTab(self.mentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.mentionsTab, True) self.commentsView = TweetListWidget() self.commentsView.userClicked.connect(self.userClicked) self.commentsView.tagClicked.connect(self.tagClicked) self.commentsTab = self._setupTab(self.commentsView) self.tabWidget.addTab(self.commentsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsTab, True) self.commentsMentionsView = TweetListWidget() self.commentsMentionsView.userClicked.connect(self.userClicked) self.commentsMentionsView.tagClicked.connect(self.tagClicked) self.commentsMentionsTab = self._setupTab(self.commentsMentionsView) self.tabWidget.addTab(self.commentsMentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsMentionsTab, True) self.verticalLayout.addWidget(self.tabWidget) self.widget = QtGui.QWidget(self.centralwidget) self.verticalLayout.addWidget(self.widget) mainWindow.setCentralWidget(self.centralwidget) self.aboutAction = QtGui.QAction(mainWindow) self.refreshAction = QtGui.QAction(mainWindow) self.logoutAction = QtGui.QAction(mainWindow) self.exitAction = QtGui.QAction(mainWindow) self.settingsAction = QtGui.QAction(mainWindow) self.aboutAction.setIcon( QtGui.QIcon(QtGui.QPixmap("./IMG/img/where_s_my_weibo.svg"))) self.exitAction.setIcon( QtGui.QIcon(QtGui.QPixmap(":/IMG/img/application-exit.svg"))) self.settingsAction.setIcon( QtGui.QIcon(QtGui.QPixmap(":/IMG/img/preferences-other.png"))) self.refreshAction.setIcon( QtGui.QIcon(QtGui.QPixmap(":/IMG/img/refresh.png"))) self.menubar = QtGui.QMenuBar(mainWindow) self.menubar.setEnabled(True) self.menubar.setDefaultUp(False) mainWindow.setMenuBar(self.menubar) self.mainMenu = QtGui.QMenu(self.menubar) self.helpMenu = QtGui.QMenu(self.menubar) self.optionsMenu = QtGui.QMenu(self.menubar) self.mainMenu.addAction(self.refreshAction) self.mainMenu.addSeparator() self.mainMenu.addAction(self.logoutAction) self.mainMenu.addAction(self.exitAction) self.helpMenu.addAction(self.aboutAction) self.optionsMenu.addAction(self.settingsAction) self.menubar.addAction(self.mainMenu.menuAction()) self.menubar.addAction(self.optionsMenu.menuAction()) self.menubar.addAction(self.helpMenu.menuAction()) self.exitAction.triggered.connect(mainWindow.close) self.aboutAction.triggered.connect(mainWindow.showAbout) self.settingsAction.triggered.connect(mainWindow.showSettings) self.logoutAction.triggered.connect(mainWindow.logout) self.refreshAction.triggered.connect(mainWindow.refresh) self.pushButton_refresh = QtGui.QPushButton(self.widget) self.pushButton_new = QtGui.QPushButton(self.widget) self.pushButton_refresh.clicked.connect(mainWindow.refresh) self.pushButton_new.clicked.connect(mainWindow.postTweet) self.timelineLoaded.connect(self.moveToTop) self.tabBadgeChanged.connect(self.drawNotifyBadge) self.refreshAction.setShortcut(QtGui.QKeySequence("F5")) self.pushButton_refresh.setIcon(QtGui.QIcon(":/IMG/img/refresh.png")) self.pushButton_new.setIcon(QtGui.QIcon(":/IMG/img/new.png")) if self.isGlobalMenu(): self._setupToolBar() else: self._setupButtonWidget() self._setTabIcon(self.homeTab, QtGui.QPixmap(":/IMG/img/sina.png")) self._setTabIcon(self.mentionsTab, QtGui.QPixmap(":/IMG/img/mentions.png")) self._setTabIcon(self.commentsTab, QtGui.QPixmap(":/IMG/img/comments2.png")) self._setTabIcon(self.commentsMentionsTab, QtGui.QPixmap(":/IMG/img/mentions_comments.svg")) self.retranslateUi(mainWindow) def isGlobalMenu(self): if os.environ.get("TOOLBAR") == "1": return True elif os.environ.get("TOOLBAR") == "0": return False elif os.environ.get('DESKTOP_SESSION') in ["ubuntu", "ubuntu-2d"]: if not os.environ.get("UBUNTU_MENUPROXY"): return False elif os.environ.get("APPMENU_DISPLAY_BOTH"): return False else: return True elif os.environ.get( "DESKTOP_SESSION" ) == "kde-plasma" and platform.linux_distribution()[0] == "Ubuntu": return True elif platform.system() == "Darwin": return True return False def _setupToolBar(self): self.toolBar = QtGui.QToolBar() self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) empty = QtGui.QWidget() empty.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) self.toolBar.addWidget(empty) self.toolBar.addAction(self.refreshAction) newAction = self.toolBar.addAction(QtGui.QIcon(":/IMG/img/new.png"), "New") newAction.triggered.connect(self.pushButton_new.clicked) self.addToolBar(self.toolBar) def _setupButtonWidget(self): self.buttonWidget = QtGui.QWidget(self) self.buttonLayout = QtGui.QHBoxLayout(self.buttonWidget) self.horizontalSpacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.buttonLayout.addSpacerItem(self.horizontalSpacer) self.buttonLayout.addWidget(self.pushButton_refresh) self.buttonLayout.addWidget(self.pushButton_new) def resizeEvent(self, event): # This is a hack!!! if self.isGlobalMenu(): return self.buttonWidget.resize(self.menubar.sizeHint().width(), self.menubar.sizeHint().height() + 12) self.buttonWidget.move(self.width() - self.buttonWidget.width(), self.menubar.geometry().topRight().y() - 5) def retranslateUi(self, frm_MainWindow): frm_MainWindow.setWindowTitle(self.tr("WeCase")) self.mainMenu.setTitle(self.tr("&WeCase")) self.helpMenu.setTitle(self.tr("&Help")) self.optionsMenu.setTitle(self.tr("&Options")) self.aboutAction.setText(self.tr("&About...")) self.refreshAction.setText(self.tr("Refresh")) self.logoutAction.setText(self.tr("&Log out")) self.exitAction.setText(self.tr("&Exit")) self.settingsAction.setText(self.tr("&Settings")) def _setupSysTray(self): self.systray = QtGui.QSystemTrayIcon() self.systray.activated.connect(self.clickedSystray) self.systray.setToolTip("WeCase") self.systray.setIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) self.systray.show() self.visibleAction = QtGui.QAction(self) self.visibleAction.setText(self.tr("&Hide")) self.visibleAction.triggered.connect(self._switchVisibility) self.sysMenu = QtGui.QMenu(self) self.sysMenu.addAction(self.visibleAction) self.sysMenu.addAction(self.logoutAction) self.sysMenu.addAction(self.exitAction) self.systray.setContextMenu(self.sysMenu) def clickedSystray(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self._switchVisibility() elif reason == QtGui.QSystemTrayIcon.Context: pass def _switchVisibility(self): if self.isVisible(): self.hide() self.visibleAction.setText(self.tr("&Show")) else: self.show() self.visibleAction.setText(self.tr("&Hide")) def _setTabIcon(self, tab, icon): pixmap = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(pixmap) self._iconPixmap[icon.cacheKey()] = pixmap self.tabWidget.setTabIcon(self.tabWidget.indexOf(tab), icon) self.tabWidget.setIconSize(QtCore.QSize(24, 24)) def _prepareTimeline(self, timeline): try: timeline.setUsersBlacklist(self.usersBlacklist) timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) timeline.setWordWarKeywords(self.wordWarKeywords) timeline.setBlockWordwars(self.blockWordwars) timeline.setKeywordsAsRegexs(self.keywordsAsRegex) except AttributeError: pass timeline.load() def closeTab(self, index): widget = self.tabWidget.widget(index) self.tabWidget.removeTab(index) widget.deleteLater() def init_account(self): self.uid() def loadConfig(self): self.config = WConfigParser(path.myself_path + "WMetaConfig", path.config_path, "main") self.notify_interval = self.config.notify_interval self.notify_timeout = self.config.notify_timeout self.usersBlacklist = self.config.usersBlacklist self.tweetKeywordsBlacklist = self.config.tweetsKeywordsBlacklist self.remindMentions = self.config.remind_mentions self.remindComments = self.config.remind_comments self.wordWarKeywords = self.config.wordWarKeywords self.blockWordwars = self.config.blockWordwars self.maxRetweets = self.config.maxRetweets self.maxTweetsPerUser = self.config.maxTweetsPerUser self.mainWindow_geometry = self.config.mainwindow_geometry self.keywordsAsRegex = self.config.keywordsAsRegex def applyConfig(self): try: self.timer.stop() except AttributeError: pass self.timer = WTimer(self.show_notify, self.notify_interval) self.timer.start() self.notify.timeout = self.notify_timeout setGeometry(self, self.mainWindow_geometry) def setupModels(self): self._all_timeline = TweetCommonModel( self.client.api("statuses/home_timeline"), self) self.all_timeline = TweetFilterModel(self._all_timeline) self.all_timeline.setModel(self._all_timeline) self._prepareTimeline(self.all_timeline) # extra rules self.all_timeline.setMaxRetweets(self.maxRetweets) self.all_timeline.setMaxTweetsPerUser(self.maxTweetsPerUser) self.homeView.setModel(self.all_timeline) self._mentions = TweetCommonModel(self.client.api("statuses/mentions"), self) self.mentions = TweetFilterModel(self._mentions) self.mentions.setModel(self._mentions) self._prepareTimeline(self.mentions) self.mentionsView.setModel(self.mentions) self._comment_to_me = TweetCommentModel( self.client.api("comments/to_me"), self) self.comment_to_me = TweetFilterModel(self._comment_to_me) self.comment_to_me.setModel(self._comment_to_me) self._prepareTimeline(self.comment_to_me) self.commentsView.setModel(self.comment_to_me) self._comment_mentions = TweetCommentModel( self.client.api("comments/mentions"), self) self.comment_mentions = TweetFilterModel(self._comment_mentions) self.comment_mentions.setModel(self._comment_mentions) self._prepareTimeline(self.comment_mentions) self.commentsMentionsView.setModel(self.comment_mentions) @async def reset_remind(self): typ = "" if self.currentTweetView() == self.homeView: self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.mentionsView: typ = "mention_status" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsView: typ = "cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsMentionsView: typ = "mention_cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) if typ: self.client.api("remind/set_count").post(type=typ) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" reminds = self.client.api("remind/unread_count").get(uid=uid) return reminds def uid(self): """How can I get my uid? here it is""" if not self.info.get("uid"): self.info["uid"] = self.client.api("account/get_uid").get().uid return self.info["uid"] def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid()) msg = self.tr("You have:") + "\n" reminds_count = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.homeTab), reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), reminds['mention_status']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), 0) if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), reminds['cmt']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), 0) if reminds["mention_cmt"] and self.remindMentions: msg += self.tr( "%d unread @ME comment(s)") % reminds["mention_cmt"] + "\n" self.tabBadgeChanged.emit( self.tabWidget.indexOf(self.commentsMentionsTab), reminds["mention_cmt"]) reminds_count += 1 else: self.tabBadgeChanged.emit( self.tabWidget.indexOf(self.commentsMentionsTab), 0) if reminds_count and reminds_count != self._last_reminds_count: self.notify.showMessage(self.tr("WeCase"), msg) self._last_reminds_count = reminds_count def drawNotifyBadge(self, index, count): tabIcon = self.tabWidget.tabIcon(index) _tabPixmap = self._iconPixmap[tabIcon.cacheKey()] tabPixmap = _tabPixmap.transformed(QtGui.QTransform().rotate(-90)) icon = NotifyBadgeDrawer().draw(tabPixmap, str(count)) icon = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(icon) self._iconPixmap[icon.cacheKey()] = _tabPixmap self.tabWidget.setTabIcon(index, icon) def moveToTop(self): self.currentTweetView().moveToTop() def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow(allow_auto_login=False) wecase_login.exec_() def postTweet(self): self.wecase_new = NewpostWindow() self.wecase_new.userClicked.connect(self.userClicked) self.wecase_new.tagClicked.connect(self.tagClicked) self.wecase_new.show() def refresh(self): tweetView = self.currentTweetView() tweetView.model().timelineLoaded.connect(self.moveToTop) tweetView.refresh() self.reset_remind() def currentTweetView(self): # The most tricky part of MainWindow. return self.tabWidget.currentWidget().layout().itemAt(0).widget() def saveConfig(self): self.config.mainwindow_geometry = getGeometry(self) self.config.save() def closeEvent(self, event): self.systray.hide() self.hide() self.saveConfig() self.timer.stop(True) # Reset uid when the thread exited. self.info["uid"] = None LoginInfo().remove_account(self.username) logging.info("Die")
class WeCaseWindow(QtGui.QMainWindow): client = None uid = None timelineLoaded = QtCore.pyqtSignal(int) imageLoaded = QtCore.pyqtSignal(str) tabBadgeChanged = QtCore.pyqtSignal(int, int) tabAvatarFetched = QtCore.pyqtSignal(str) def __init__(self, parent=None): super(WeCaseWindow, self).__init__(parent) self.errorWindow = APIErrorWindow(self) self.setAttribute(QtCore.Qt.WA_QuitOnClose, True) self._iconPixmap = {} self.setupUi(self) self._setupSysTray() self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.commentsMentionsTab] self.info = WeRuntimeInfo() self.client = const.client self.loadConfig() self.init_account() self.setupModels() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] self._last_reminds_count = 0 self._setupUserTab(self.uid(), False, True) def _setupTab(self, view): tab = QtGui.QWidget() layout = QtGui.QGridLayout(tab) layout.addWidget(view) view.setParent(tab) return tab def _setupCommonTab(self, timeline, view, switch=True, protect=False): self._prepareTimeline(timeline) view.setModel(timeline) view.userClicked.connect(self.userClicked) view.tagClicked.connect(self.tagClicked) tab = self._setupTab(view) self.tabWidget.addTab(tab, "") if switch: self.tabWidget.setCurrentWidget(tab) if protect: self.tabWidget.tabBar().setProtectTab(tab, True) return tab def _getSameTab(self, attr, value): for i in range(self.tabWidget.count()): try: tab = self.tabWidget.widget(i).layout().itemAt(0).widget() _value = getattr(tab.model(), attr)() if _value == value: return i except AttributeError: pass return False def _setupUserTab(self, uid, switch=True, myself=False): index = self._getSameTab("uid", uid) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() _timeline = TweetUserModel(self.client.statuses.user_timeline, uid, view) timeline = TweetFilterModel(_timeline) timeline.setModel(_timeline) tab = self._setupCommonTab(timeline, view, switch, myself) def setAvatar(f): self._setTabIcon(tab, WObjectCache().open(QtGui.QPixmap, f)) fetcher = AsyncFetcher("".join((path.cache_path, str(self.info["uid"])))) fetcher.addTask(self.client.users.show.get(uid=uid)["profile_image_url"], setAvatar) def _setupTopicTab(self, topic, switch=True): index = self._getSameTab("topic", topic) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() timeline = TweetTopicModel(self.client.search.topics, topic, view) tab = self._setupCommonTab(timeline, view, switch, protect=False) self._setTabIcon(tab, WObjectCache().open( QtGui.QPixmap, ":/IMG/img/topic.jpg" )) def userClicked(self, userItem, openAtBackend): try: self._setupUserTab(userItem.id, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def tagClicked(self, str, openAtBackend): try: self._setupTopicTab(str, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def setupUi(self, mainWindow): mainWindow.setWindowIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) mainWindow.setDocumentMode(False) mainWindow.setDockOptions(QtGui.QMainWindow.AllowTabbedDocks | QtGui.QMainWindow.AnimatedDocks) self.centralwidget = QtGui.QWidget(mainWindow) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.tabWidget = QtGui.QTabWidget(self.centralwidget) self.tabWidget.setTabBar(WTabBar(self.tabWidget)) self.tabWidget.setTabPosition(QtGui.QTabWidget.West) self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded) self.tabWidget.setDocumentMode(False) self.tabWidget.setMovable(True) self.tabWidget.tabCloseRequested.connect(self.closeTab) self.homeView = TweetListWidget() self.homeView.userClicked.connect(self.userClicked) self.homeView.tagClicked.connect(self.tagClicked) self.homeTab = self._setupTab(self.homeView) self.tabWidget.addTab(self.homeTab, "") self.tabWidget.tabBar().setProtectTab(self.homeTab, True) self.mentionsView = TweetListWidget() self.mentionsView.userClicked.connect(self.userClicked) self.mentionsView.tagClicked.connect(self.tagClicked) self.mentionsTab = self._setupTab(self.mentionsView) self.tabWidget.addTab(self.mentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.mentionsTab, True) self.commentsView = TweetListWidget() self.commentsView.userClicked.connect(self.userClicked) self.commentsView.tagClicked.connect(self.tagClicked) self.commentsTab = self._setupTab(self.commentsView) self.tabWidget.addTab(self.commentsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsTab, True) self.commentsMentionsView = TweetListWidget() self.commentsMentionsView.userClicked.connect(self.userClicked) self.commentsMentionsView.tagClicked.connect(self.tagClicked) self.commentsMentionsTab = self._setupTab(self.commentsMentionsView) self.tabWidget.addTab(self.commentsMentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsMentionsTab, True) self.verticalLayout.addWidget(self.tabWidget) self.widget = QtGui.QWidget(self.centralwidget) self.verticalLayout.addWidget(self.widget) mainWindow.setCentralWidget(self.centralwidget) self.aboutAction = QtGui.QAction(mainWindow) self.refreshAction = QtGui.QAction(mainWindow) self.logoutAction = QtGui.QAction(mainWindow) self.exitAction = QtGui.QAction(mainWindow) self.settingsAction = QtGui.QAction(mainWindow) self.aboutAction.setIcon(QtGui.QIcon(QtGui.QPixmap("./IMG/img/where_s_my_weibo.svg"))) self.exitAction.setIcon(QtGui.QIcon(QtGui.QPixmap(":/IMG/img/application-exit.svg"))) self.settingsAction.setIcon(QtGui.QIcon(QtGui.QPixmap(":/IMG/img/preferences-other.png"))) self.refreshAction.setIcon(QtGui.QIcon(QtGui.QPixmap(":/IMG/img/refresh.png"))) self.menubar = QtGui.QMenuBar(mainWindow) self.menubar.setEnabled(True) self.menubar.setDefaultUp(False) mainWindow.setMenuBar(self.menubar) self.mainMenu = QtGui.QMenu(self.menubar) self.helpMenu = QtGui.QMenu(self.menubar) self.optionsMenu = QtGui.QMenu(self.menubar) self.mainMenu.addAction(self.refreshAction) self.mainMenu.addSeparator() self.mainMenu.addAction(self.logoutAction) self.mainMenu.addAction(self.exitAction) self.helpMenu.addAction(self.aboutAction) self.optionsMenu.addAction(self.settingsAction) self.menubar.addAction(self.mainMenu.menuAction()) self.menubar.addAction(self.optionsMenu.menuAction()) self.menubar.addAction(self.helpMenu.menuAction()) self.exitAction.triggered.connect(mainWindow.close) self.aboutAction.triggered.connect(mainWindow.showAbout) self.settingsAction.triggered.connect(mainWindow.showSettings) self.logoutAction.triggered.connect(mainWindow.logout) self.refreshAction.triggered.connect(mainWindow.refresh) self.pushButton_refresh = QtGui.QPushButton(self.widget) self.pushButton_new = QtGui.QPushButton(self.widget) self.pushButton_refresh.clicked.connect(mainWindow.refresh) self.pushButton_new.clicked.connect(mainWindow.postTweet) self.timelineLoaded.connect(self.moveToTop) self.tabBadgeChanged.connect(self.drawNotifyBadge) self.refreshAction.setShortcut(QtGui.QKeySequence("F5")) self.pushButton_refresh.setIcon(QtGui.QIcon(":/IMG/img/refresh.png")) self.pushButton_new.setIcon(QtGui.QIcon(":/IMG/img/new.png")) if self.isGlobalMenu(): self._setupToolBar() else: self._setupButtonWidget() self._setTabIcon(self.homeTab, QtGui.QPixmap(":/IMG/img/sina.png")) self._setTabIcon(self.mentionsTab, QtGui.QPixmap(":/IMG/img/mentions.png")) self._setTabIcon(self.commentsTab, QtGui.QPixmap(":/IMG/img/comments2.png")) self._setTabIcon(self.commentsMentionsTab, QtGui.QPixmap(":/IMG/img/mentions_comments.svg")) self.retranslateUi(mainWindow) def isGlobalMenu(self): if os.environ.get("TOOLBAR") == "1": return True elif os.environ.get("TOOLBAR") == "0": return False elif os.environ.get('DESKTOP_SESSION') in ["ubuntu", "ubuntu-2d"]: if not os.environ.get("UBUNTU_MENUPROXY"): return False elif os.environ.get("APPMENU_DISPLAY_BOTH"): return False else: return True elif os.environ.get("DESKTOP_SESSION") == "kde-plasma" and platform.linux_distribution()[0] == "Ubuntu": return True elif platform.system() == "Darwin": return True return False def _setupToolBar(self): self.toolBar = QtGui.QToolBar() self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) empty = QtGui.QWidget() empty.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) self.toolBar.addWidget(empty) self.toolBar.addAction(self.refreshAction) newAction = self.toolBar.addAction(QtGui.QIcon(":/IMG/img/new.png"), "New") newAction.triggered.connect(self.pushButton_new.clicked) self.addToolBar(self.toolBar) def _setupButtonWidget(self): self.buttonWidget = QtGui.QWidget(self) self.buttonLayout = QtGui.QHBoxLayout(self.buttonWidget) self.horizontalSpacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.buttonLayout.addSpacerItem(self.horizontalSpacer) self.buttonLayout.addWidget(self.pushButton_refresh) self.buttonLayout.addWidget(self.pushButton_new) def resizeEvent(self, event): # This is a hack!!! if self.isGlobalMenu(): return self.buttonWidget.resize(self.menubar.sizeHint().width(), self.menubar.sizeHint().height() + 12) self.buttonWidget.move(self.width() - self.buttonWidget.width(), self.menubar.geometry().topRight().y() - 5) def retranslateUi(self, frm_MainWindow): frm_MainWindow.setWindowTitle(self.tr("WeCase")) self.mainMenu.setTitle(self.tr("&WeCase")) self.helpMenu.setTitle(self.tr("&Help")) self.optionsMenu.setTitle(self.tr("&Options")) self.aboutAction.setText(self.tr("&About...")) self.refreshAction.setText(self.tr("Refresh")) self.logoutAction.setText(self.tr("&Log out")) self.exitAction.setText(self.tr("&Exit")) self.settingsAction.setText(self.tr("&Settings")) def _setupSysTray(self): self.systray = QtGui.QSystemTrayIcon() self.systray.activated.connect(self.clickedSystray) self.systray.setToolTip("WeCase") self.systray.setIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) self.systray.show() self.visibleAction = QtGui.QAction(self) self.visibleAction.setText(self.tr("&Hide")) self.visibleAction.triggered.connect(self._switchVisibility) self.sysMenu = QtGui.QMenu(self) self.sysMenu.addAction(self.visibleAction) self.sysMenu.addAction(self.logoutAction) self.sysMenu.addAction(self.exitAction) self.systray.setContextMenu(self.sysMenu) def clickedSystray(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self._switchVisibility() elif reason == QtGui.QSystemTrayIcon.Context: pass def _switchVisibility(self): if self.isVisible(): self.hide() self.visibleAction.setText(self.tr("&Show")) else: self.show() self.visibleAction.setText(self.tr("&Hide")) def _setTabIcon(self, tab, icon): pixmap = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(pixmap) self._iconPixmap[icon.cacheKey()] = pixmap self.tabWidget.setTabIcon(self.tabWidget.indexOf(tab), icon) self.tabWidget.setIconSize(QtCore.QSize(24, 24)) def _prepareTimeline(self, timeline): try: timeline.setUsersBlacklist(self.usersBlacklist) timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) timeline.setWordWarKeywords(self.wordWarKeywords) timeline.setBlockWordwars(self.blockWordwars) except AttributeError: pass timeline.load() def closeTab(self, index): widget = self.tabWidget.widget(index) self.tabWidget.removeTab(index) widget.deleteLater() def init_account(self): self.uid() def loadConfig(self): self.config = WConfigParser(path.myself_path + "WMetaConfig", path.config_path, "main") self.notify_interval = self.config.notify_interval self.notify_timeout = self.config.notify_timeout self.usersBlacklist = self.config.usersBlacklist self.tweetKeywordsBlacklist = self.config.tweetsKeywordsBlacklist self.remindMentions = self.config.remind_mentions self.remindComments = self.config.remind_comments self.wordWarKeywords = self.config.wordWarKeywords self.blockWordwars = self.config.blockWordwars self.maxRetweets = self.config.maxRetweets self.maxTweetsPerUser = self.config.maxTweetsPerUser self.mainWindow_geometry = self.config.mainwindow_geometry def applyConfig(self): try: self.timer.stop() except AttributeError: pass self.timer = WTimer(self.show_notify, self.notify_interval) self.timer.start() self.notify.timeout = self.notify_timeout setGeometry(self, self.mainWindow_geometry) def setupModels(self): self._all_timeline = TweetCommonModel(self.client.statuses.home_timeline, self) self.all_timeline = TweetFilterModel(self._all_timeline) self.all_timeline.setModel(self._all_timeline) self._prepareTimeline(self.all_timeline) # extra rules self.all_timeline.setMaxRetweets(self.maxRetweets) self.all_timeline.setMaxTweetsPerUser(self.maxTweetsPerUser) self.homeView.setModel(self.all_timeline) self._mentions = TweetCommonModel(self.client.statuses.mentions, self) self.mentions = TweetFilterModel(self._mentions) self.mentions.setModel(self._mentions) self._prepareTimeline(self.mentions) self.mentionsView.setModel(self.mentions) self._comment_to_me = TweetCommentModel(self.client.comments.to_me, self) self.comment_to_me = TweetFilterModel(self._comment_to_me) self.comment_to_me.setModel(self._comment_to_me) self._prepareTimeline(self.comment_to_me) self.commentsView.setModel(self.comment_to_me) self._comment_mentions = TweetCommentModel(self.client.comments.mentions, self) self.comment_mentions = TweetFilterModel(self._comment_mentions) self.comment_mentions.setModel(self._comment_mentions) self._prepareTimeline(self.comment_mentions) self.commentsMentionsView.setModel(self.comment_mentions) @async def reset_remind(self): typ = "" if self.currentTweetView() == self.homeView: self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.mentionsView: typ = "mention_status" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsView: typ = "cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsMentionsView: typ = "mention_cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) if typ: self.client.remind.set_count.post(type=typ) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" reminds = self.client.remind.unread_count.get(uid=uid) return reminds def uid(self): """How can I get my uid? here it is""" if not self.info.get("uid"): self.info["uid"] = self.client.account.get_uid.get().uid return self.info["uid"] def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid()) msg = self.tr("You have:") + "\n" reminds_count = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.homeTab), reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), reminds['mention_status']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), 0) if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), reminds['cmt']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), 0) if reminds["mention_cmt"] and self.remindMentions: msg += self.tr("%d unread @ME comment(s)") % reminds["mention_cmt"] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsMentionsTab), reminds["mention_cmt"]) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsMentionsTab), 0) if reminds_count and reminds_count != self._last_reminds_count: self.notify.showMessage(self.tr("WeCase"), msg) self._last_reminds_count = reminds_count def drawNotifyBadge(self, index, count): tabIcon = self.tabWidget.tabIcon(index) _tabPixmap = self._iconPixmap[tabIcon.cacheKey()] tabPixmap = _tabPixmap.transformed(QtGui.QTransform().rotate(-90)) icon = NotifyBadgeDrawer().draw(tabPixmap, str(count)) icon = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(icon) self._iconPixmap[icon.cacheKey()] = _tabPixmap self.tabWidget.setTabIcon(index, icon) def moveToTop(self): self.currentTweetView().moveToTop() def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow(allow_auto_login=False) wecase_login.exec_() def postTweet(self): self.wecase_new = NewpostWindow() self.wecase_new.userClicked.connect(self.userClicked) self.wecase_new.tagClicked.connect(self.tagClicked) self.wecase_new.show() def refresh(self): tweetView = self.currentTweetView() tweetView.model().timelineLoaded.connect(self.moveToTop) tweetView.refresh() self.reset_remind() def currentTweetView(self): # The most tricky part of MainWindow. return self.tabWidget.currentWidget().layout().itemAt(0).widget() def saveConfig(self): self.config.mainwindow_geometry = getGeometry(self) self.config.save() def closeEvent(self, event): self.systray.hide() self.hide() self.saveConfig() self.timer.stop(True) # Reset uid when the thread exited. self.info["uid"] = None logging.info("Die")
class WeCaseWindow(QtGui.QMainWindow, Ui_frm_MainWindow): client = None uid = None imageLoaded = QtCore.pyqtSignal(str) tabTextChanged = QtCore.pyqtSignal(int, str) def __init__(self, client, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.tweetViews = [ self.homeView, self.mentionsView, self.commentsView, self.myView ] self.client = client self.setupModels() self.init_account() self.setupMyUi() self.loadConfig() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] def init_account(self): self.get_uid() def loadConfig(self): self.config = ConfigParser() self.config.read(const.config_path) if not self.config.has_section('main'): self.config['main'] = {} self.main_config = self.config['main'] self.timer_interval = int(self.main_config.get('notify_interval', 30)) self.notify_timeout = int(self.main_config.get('notify_timeout', 5)) self.remindMentions = self.main_config.getboolean('remind_mentions', 1) self.remindComments = self.main_config.getboolean('remind_comments', 1) def applyConfig(self): try: self.timer.stop_event.set() except AttributeError: pass self.timer = WTimer(self.timer_interval, self.show_notify) self.timer.start() self.notify.timeout = self.notify_timeout def setupMyUi(self): for tweetView in self.tweetViews: tweetView.setResizeMode(tweetView.SizeRootObjectToView) tweetView.setSource( QtCore.QUrl.fromLocalFile(const.myself_path + "/ui/TweetList.qml")) tweetView.rootContext().setContextProperty("mainWindow", self) @QtCore.pyqtSlot() def load_more(self): model = self.get_current_model() model.next() def setupModels(self): self.all_timeline = TweetCommonModel( TweetItem(), self.client.statuses.home_timeline, self) self.all_timeline.load() self.homeView.rootContext().setContextProperty("mymodel", self.all_timeline) self.mentions = TweetCommonModel(TweetItem(), self.client.statuses.mentions, self) self.mentions.load() self.mentionsView.rootContext().setContextProperty( "mymodel", self.mentions) self.comment_to_me = TweetCommentModel(TweetItem(), self.client.comments.to_me, self) self.comment_to_me.load() self.commentsView.rootContext().setContextProperty( "mymodel", self.comment_to_me) self.my_timeline = TweetCommonModel(TweetItem(), self.client.statuses.user_timeline, self) self.my_timeline.load() self.myView.rootContext().setContextProperty("mymodel", self.my_timeline) def reset_remind(self): if self.tabWidget.currentIndex() == 0: self.tabWidget.setTabText(0, self.tr("Weibo")) elif self.tabWidget.currentIndex() == 1: self.client.remind.set_count.post(type="mention_status") self.tabWidget.setTabText(1, self.tr("@Me")) elif self.tabWidget.currentIndex() == 2: self.client.remind.set_count.post(type="cmt") self.tabWidget.setTabText(2, self.tr("Comments")) def get_remind(self, uid): '''this function is used to get unread_count from Weibo API. uid is necessary.''' reminds = self.client.remind.unread_count.get(uid=uid) return reminds def get_uid(self): '''How can I get my uid? here it is''' try: self.uid = self.client.account.get_uid.get().uid except AttributeError: return None def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid) msg = self.tr("You have:") + "\n" num_msg = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabTextChanged.emit(0, self.tr("Weibo(%d)") % reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabTextChanged.emit( 1, self.tr("@Me(%d)") % reminds['mention_status']) num_msg += 1 if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabTextChanged.emit(2, self.tr("Comments(%d)") % reminds['cmt']) num_msg += 1 if num_msg: return self.notify.showMessage(self.tr("WeCase"), msg) def setTabText(self, index, string): self.tabWidget.setTabText(index, string) def moveToTop(self): self.get_current_tweetView().rootObject().positionViewAtBeginning() def setLoaded(self, tweetid): self.get_current_tweetView().rootObject().imageLoaded(tweetid) def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow() wecase_login.exec_() def postTweet(self): wecase_new = NewpostWindow() wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str) def comment(self, idstr): wecase_new = NewpostWindow(action="comment", id=int(idstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def repost(self, idstr, text): wecase_new = NewpostWindow(action="retweet", id=int(idstr), text=text) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, result=int) def favorite(self, idstr): try: self.client.favorites.create.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, result=bool) def un_favorite(self, idstr): try: self.client.favorites.destroy.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, str) def reply(self, idstr, cidstr): wecase_new = NewpostWindow(action="reply", id=int(idstr), cid=int(cidstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def look_orignal_pic(self, thumbnail_pic, tweetid): threading.Thread(group=None, target=self.fetch_open_original_pic, args=(thumbnail_pic, tweetid)).start() def fetch_open_original_pic(self, thumbnail_pic, tweetid): """Fetch and open original pic from thumbnail pic url. Pictures will stored in cache directory. If we already have a same name in cache directory, just open it. If we don't, then download it first.""" if tweetid in self.download_lock: return self.download_lock.append(tweetid) original_pic = thumbnail_pic.replace("thumbnail", "large") # A simple trick ... ^_^ localfile = const.cache_path + original_pic.split("/")[-1] if not os.path.exists(localfile): urllib.request.urlretrieve(original_pic, localfile) self.download_lock.remove(tweetid) os.popen("xdg-open " + localfile) # xdg-open is common? self.imageLoaded.emit(tweetid) def refresh(self): model = self.get_current_model() model.timelineLoaded.connect(self.moveToTop) #model.clear() #model.load() model.new() self.reset_remind() def get_current_tweetView(self): tweetViews = { 0: self.homeView, 1: self.mentionsView, 2: self.commentsView, 3: self.myView } return tweetViews[self.tabWidget.currentIndex()] def get_current_model(self): models = { 0: self.all_timeline, 1: self.mentions, 2: self.comment_to_me, 3: self.my_timeline } return models[self.tabWidget.currentIndex()] def get_current_function(self): functions = { 0: self.get_all_timeline, 1: self.get_mentions_timeline, 2: self.get_comment_to_me, 3: self.get_my_timeline } return functions[self.tabWidget.currentIndex()] def closeEvent(self, event): self.timer.stop_event.set()
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): image = None apiError = QtCore.pyqtSignal(Exception) commonError = QtCore.pyqtSignal(str, str) sendSuccessful = QtCore.pyqtSignal() userClicked = QtCore.pyqtSignal(UserItem, bool) tagClicked = QtCore.pyqtSignal(str, bool) tweetRefreshed = QtCore.pyqtSignal() tweetRejected = QtCore.pyqtSignal() def __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage) self.errorWindow = APIErrorWindow(self) if self.action not in ["new", "reply"]: self.tweetRefreshed.connect(self._create_tweetWidget) self.tweetRejected.connect( lambda: self.pushButton_send.setEnabled(False)) self._refresh() def setupUi(self, widget): super(NewpostWindow, self).setupUi(widget) self.sendAction = QtGui.QAction(self) self.sendAction.triggered.connect(self.send) self.sendAction.setShortcut(QtGui.QKeySequence("Ctrl+Return")) self.addAction(self.sendAction) self.checkChars() self.setupButtons() def setupButtons(self): # Disabled is the default state of buttons self.pushButton_picture.setEnabled(False) self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) if self.action == "new": assert (not self.tweet) # Shouldn't have a tweet object. self.pushButton_picture.setEnabled(True) elif self.action == "retweet": self.chk_comment.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.textEdit.setText(self.tweet.append_existing_replies()) self.chk_comment_original.setEnabled(True) elif self.action == "comment": self.chk_repost.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) elif self.action == "reply": self.chk_repost.setEnabled(True) if self.tweet.original.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) else: assert False @async def _refresh(self): # The read count is not a real-time value. So refresh it now. try: self.tweet.refresh() except APIError as e: self.errorWindow.raiseException.emit(e) self.tweetRejected.emit() return self.tweetRefreshed.emit() def _create_tweetWidget(self): if self.action == "comment" and self.tweet.comments_count: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) self.replyModel = TweetUnderCommentModel( self.client.api("comments/show"), self.tweet.id, self) elif self.action == "retweet" and self.tweet.retweets_count: if self.tweet: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) elif self.tweet.original: self.tweetWidget = SingleTweetWidget(self.tweet.original, ["image", "original"], self) self.replyModel = TweetRetweetModel( self.client.api("statuses/repost_timeline"), self.tweet.id, self) else: return self.replyModel.load() self.splitter = QtGui.QSplitter(self) self.splitter.setOrientation(QtCore.Qt.Vertical) self.verticalLayout.insertWidget(0, self.splitter) self.tweetWidget.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.splitter.addWidget(self.tweetWidget) self.commentsWidget = TweetListWidget(self, ["image", "original"]) self.commentsWidget.setModel(self.replyModel) self.commentsWidget.scrollArea.setMinimumSize(20, 200) self.commentsWidget.userClicked.connect(self.userClicked) self.commentsWidget.tagClicked.connect(self.tagClicked) self.splitter.addWidget(self.commentsWidget) self.splitter.addWidget(self.textEdit) def mentions_suggest(self, text): ret_users = [] try: word = text.split(' ')[-1] word = word.split('@')[-1] except IndexError: return [] if not word.strip(): return [] users = self.client.api("search/suggestions/at_users").get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def sent(self): self._sent = True self.close() def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": self.new() elif self.action == "retweet": self.retweet() elif self.action == "comment": self.comment() elif self.action == "reply": self.reply() else: # If action is in other types, it must be a mistake. assert False @async def retweet(self): text = self.textEdit.toPlainText() comment = int(self.chk_comment.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.retweet(text, comment, comment_ori) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() @async def comment(self): text = self.textEdit.toPlainText() retweet = int(self.chk_repost.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.comment(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() @async def reply(self): text = self.textEdit.toPlainText() comment_ori = int(self.chk_comment_original.isChecked()) retweet = int(self.chk_repost.isChecked()) try: self.tweet.reply(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() @async def new(self): text = self.textEdit.toPlainText() try: if self.image: try: if getsize(self.image) > const.MAX_IMAGE_BYTES: raise ValueError with open(self.image, "rb") as image: self.client.api("statuses/upload").post(status=text, pic=image) except (OSError, IOError): self.commonError.emit( self.tr("File not found"), self.tr("No such file: %s") % self.image) self.addImage() # In fact, remove image... return except ValueError: self.commonError.emit( self.tr("Too large size"), self.tr("This image is too large to upload: %s") % self.image) self.addImage() # In fact, remove image... return else: self.client.api("statuses/update").post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(e) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.jpeg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("&Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) self.textEdit.setFocus() def showException(self, e): if "Text too long" in str(e): QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: self.errorWindow.raiseException.emit(e) self.pushButton_send.setEnabled(True) def showErrorMessage(self, title, text): QtGui.QMessageBox.warning(self, title, text) def showSmiley(self): wecase_smiley = FaceWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.faceName) self.textEdit.setFocus() def checkChars(self): """Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.""" text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens)) def reject(self): self.close() def closeEvent(self, event): # We have unsend text. if (not self._sent) and (self.textEdit.toPlainText()): choice = QtGui.QMessageBox.question( self, self.tr("Close?"), self.tr("All unpost text will lost."), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if choice == QtGui.QMessageBox.No: event.ignore() else: self.setParent(None)
class WeCaseWindow(QtGui.QMainWindow, Ui_frm_MainWindow): client = None uid = None imageLoaded = QtCore.pyqtSignal(str) tabTextChanged = QtCore.pyqtSignal(int, str) def __init__(self, parent=None): super(WeCaseWindow, self).__init__(parent) self.setupUi(self) self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.myView] self.client = const.client self.loadConfig() self.setupModels() self.init_account() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] def init_account(self): self.get_uid() def loadConfig(self): self.config = WeCaseConfig(const.config_path) self.notify_interval = self.config.notify_interval self.notify_timeout = self.config.notify_timeout self.usersBlacklist = self.config.usersBlacklist self.tweetKeywordsBlacklist = self.config.tweetsKeywordsBlacklist self.remindMentions = self.config.remind_mentions self.remindComments = self.config.remind_comments def applyConfig(self): try: self.timer.stop_event.set() except AttributeError: pass self.timer = WTimer(self.notify_interval, self.show_notify) self.timer.start() self.notify.timeout = self.notify_timeout def setupModels(self): self.all_timeline = TweetCommonModel(self.client.statuses.home_timeline, self) self.all_timeline.setUsersBlacklist(self.usersBlacklist) self.all_timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.all_timeline.load() self.homeView.setModel(self.all_timeline) self.mentions = TweetCommonModel(self.client.statuses.mentions, self) self.mentions.setUsersBlacklist(self.usersBlacklist) self.mentions.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.mentions.load() self.mentionsView.setModel(self.mentions) self.comment_to_me = TweetCommentModel(self.client.comments.to_me, self) self.comment_to_me.setUsersBlacklist(self.usersBlacklist) self.comment_to_me.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.comment_to_me.load() self.commentsView.setModel(self.comment_to_me) self.my_timeline = TweetCommonModel(self.client.statuses.user_timeline, self) self.my_timeline.setUsersBlacklist(self.usersBlacklist) self.my_timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.my_timeline.load() self.myView.setModel(self.my_timeline) def reset_remind(self): if self.tabWidget.currentIndex() == 0: self.tabWidget.setTabText(0, self.tr("Weibo")) elif self.tabWidget.currentIndex() == 1: self.client.remind.set_count.post(type="mention_status") self.tabWidget.setTabText(1, self.tr("@Me")) elif self.tabWidget.currentIndex() == 2: self.client.remind.set_count.post(type="cmt") self.tabWidget.setTabText(2, self.tr("Comments")) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" while 1: try: reminds = self.client.remind.unread_count.get(uid=uid) break except http.client.BadStatusLine: sleep(0.2) continue return reminds def get_uid(self): """How can I get my uid? here it is""" try: self.uid = self.client.account.get_uid.get().uid except AttributeError: return None def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid) msg = self.tr("You have:") + "\n" num_msg = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabTextChanged.emit(0, self.tr("Weibo(%d)") % reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabTextChanged.emit(1, self.tr("@Me(%d)") % reminds['mention_status']) num_msg += 1 if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabTextChanged.emit(2, self.tr("Comments(%d)") % reminds['cmt']) num_msg += 1 if num_msg: self.notify.showMessage(self.tr("WeCase"), msg) def setTabText(self, index, string): self.tabWidget.setTabText(index, string) def moveToTop(self): self.get_current_tweetView().moveToTop() def setLoaded(self): pass def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow(allow_auto_login=False) wecase_login.exec_() def postTweet(self): wecase_new = NewpostWindow() wecase_new.exec_() def refresh(self): tweetView = self.get_current_tweetView() tweetView.model().timelineLoaded.connect(self.moveToTop) tweetView.refresh() self.reset_remind() def get_current_tweetView(self): tweetViews = {0: self.homeView, 1: self.mentionsView, 2: self.commentsView, 3: self.myView} return tweetViews[self.tabWidget.currentIndex()] def closeEvent(self, event): self.timer.stop_event.set()
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): client = None image = None apiError = QtCore.pyqtSignal(str) sendSuccessful = QtCore.pyqtSignal() def __init__(self, parent=None, action="new", id=None, cid=None, text=""): QtGui.QDialog.__init__(self, parent) self.action = action self.id = id self.cid = cid self.setupUi(self) self.setupMyUi() self.textEdit.setText(text) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) def setupMyUi(self): self.checkChars() if self.action == "new": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) elif self.action == "retweet": self.chk_repost.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "comment": self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "reply": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) def mentions_suggest(self, text): ret_users = [] try: word = re.findall('@[-a-zA-Z0-9_\u4e00-\u9fa5]+', text)[-1] word = word.replace('@', '') except IndexError: return [] if not word.strip(): return [] users = self.client.search.suggestions.at_users.get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": threading.Thread(group=None, target=self.new).start() elif self.action == "retweet": threading.Thread(group=None, target=self.retweet).start() elif self.action == "comment": threading.Thread(group=None, target=self.comment).start() elif self.action == "reply": threading.Thread(group=None, target=self.reply).start() def retweet(self): text = str(self.textEdit.toPlainText()) try: self.client.statuses.repost.post(id=int(self.id), status=text, is_comment=int((self.chk_comment.isChecked() + self.chk_comment_original.isChecked() * 2))) self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def comment(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.create.post(id=int(self.id), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def reply(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.reply.post(id=int(self.id), cid=int(self.cid), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def new(self): text = str(self.textEdit.toPlainText()) try: if self.image: self.client.statuses.upload.post(status=text, pic=open(self.image, "rb")) else: self.client.statuses.update.post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) def showError(self, e): if "Text too long" in e: QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: QtGui.QMessageBox.warning(None, self.tr("Unknown error!"), e) self.pushButton_send.setEnabled(True) def showSmiley(self): wecase_smiley = SmileyWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.smileyName) def checkChars(self): '''Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.''' text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens))
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): client = None image = None apiError = QtCore.pyqtSignal(str) sendSuccessful = QtCore.pyqtSignal() def __init__(self, parent=None, action="new", id=None, cid=None, text=""): QtGui.QDialog.__init__(self, parent) self.action = action self.id = id self.cid = cid self.setupUi(self) self.setupMyUi() self.textEdit.setText(text) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) def setupMyUi(self): self.checkChars() if self.action == "new": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) elif self.action == "retweet": self.chk_repost.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "comment": self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "reply": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) def mentions_suggest(self, text): ret_users = [] try: word = re.findall('@[-a-zA-Z0-9_\u4e00-\u9fa5]+', text)[-1] word = word.replace('@', '') except IndexError: return [] if not word.strip(): return [] users = self.client.search.suggestions.at_users.get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": threading.Thread(group=None, target=self.new).start() elif self.action == "retweet": threading.Thread(group=None, target=self.retweet).start() elif self.action == "comment": threading.Thread(group=None, target=self.comment).start() elif self.action == "reply": threading.Thread(group=None, target=self.reply).start() def retweet(self): text = str(self.textEdit.toPlainText()) try: self.client.statuses.repost.post( id=int(self.id), status=text, is_comment=int((self.chk_comment.isChecked() + self.chk_comment_original.isChecked() * 2))) self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def comment(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.create.post( id=int(self.id), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def reply(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.reply.post( id=int(self.id), cid=int(self.cid), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def new(self): text = str(self.textEdit.toPlainText()) try: if self.image: self.client.statuses.upload.post(status=text, pic=open(self.image, "rb")) else: self.client.statuses.update.post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) def showError(self, e): if "Text too long" in e: QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: QtGui.QMessageBox.warning(None, self.tr("Unknown error!"), e) self.pushButton_send.setEnabled(True) def showSmiley(self): wecase_smiley = SmileyWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.smileyName) def checkChars(self): '''Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.''' text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens))