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()
Exemple #2
0
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)
Exemple #3
0
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")
Exemple #4
0
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")
Exemple #5
0
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()
Exemple #6
0
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)
Exemple #7
0
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))
Exemple #9
0
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))