Ejemplo n.º 1
0
 def exec_newpost_window(self, action, tweet):
     from NewpostWindow import NewpostWindow
     try:
         self.wecase_new = NewpostWindow(action, tweet)
         self.wecase_new.userClicked.connect(self.userClicked)
         self.wecase_new.tagClicked.connect(self.tagClicked)
         self.wecase_new.show()
     except APIError as e:
         self.errorWindow.raiseException.emit(e)
Ejemplo n.º 2
0
 def exec_newpost_window(self, action, tweet):
     from NewpostWindow import NewpostWindow
     try:
         self.wecase_new = NewpostWindow(action, tweet)
         self.wecase_new.userClicked.connect(self.userClicked)
         self.wecase_new.tagClicked.connect(self.tagClicked)
         self.wecase_new.show()
     except APIError as e:
         self._handle_api_error(e)
Ejemplo n.º 3
0
 def exec_newpost_window(self, action, tweet):
     from NewpostWindow import NewpostWindow
     try:
         self.wecase_new = NewpostWindow(action, tweet)
         self.wecase_new.userClicked.connect(self.userClicked)
         self.wecase_new.tagClicked.connect(self.tagClicked)
         self.wecase_new.show()
     except APIError as e:
         self.errorWindow.raiseException.emit(e)
Ejemplo n.º 4
0
 def reply(self, idstr, cidstr):
     wecase_new = NewpostWindow(action="reply", id=int(idstr), cid=int(cidstr))
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 5
0
 def comment(self, idstr):
     wecase_new = NewpostWindow(action="comment", id=int(idstr))
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 6
0
 def repost(self, idstr, text):
     wecase_new = NewpostWindow(action="retweet", id=int(idstr), text=text)
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 7
0
 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()
Ejemplo n.º 8
0
 def postTweet(self):
     wecase_new = NewpostWindow()
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 9
0
 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()
Ejemplo n.º 10
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")
Ejemplo n.º 11
0
class SingleTweetWidget(QtGui.QFrame):

    userClicked = QtCore.pyqtSignal(UserItem, bool)
    tagClicked = QtCore.pyqtSignal(str, bool)
    deleteReturn = QtCore.pyqtSignal(bool)

    MENTIONS_RE = re.compile('(@[-a-zA-Z0-9_\u4e00-\u9fa5]+)')
    SINA_URL_RE = re.compile(r"(http://t.cn/[a-zA-Z0-9]{5,7})")
    HASHTAG_RE = re.compile("(#.*?#)")

    def __init__(self, tweet=None, without=(), parent=None):
        super(SingleTweetWidget, self).__init__(parent)
        self.errorWindow = APIErrorWindow(self)
        self.tweet = tweet
        self.client = const.client
        self.without = without
        self.setObjectName("SingleTweetWidget")
        try:
            self.setupUi()
        except RuntimeError:
            return
        self.fetcher = AsyncFetcher("".join((cache_path, str(WeRuntimeInfo()["uid"]))))
        self.download_lock = False
        self.__favorite_queue = []

    def setupUi(self):
        self.horizontalLayout = QtGui.QHBoxLayout(self)
        self.horizontalLayout.setMargin(0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.verticalLayout_2 = QtGui.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")

        reason = self.tweet.author.verify_reason
        if self.tweet.author.verify_type == "personal":
            self.avatar = WAvatarLabel(WAvatarLabel.PERSONAL_VERIFY, reason)
        elif self.tweet.author.verify_type == "organization":
            self.avatar = WAvatarLabel(WAvatarLabel.ORGANIZATION_VERIFY, reason)
        else:
            self.avatar = WAvatarLabel(WAvatarLabel.NO_VERIFY)
        self.avatar.setObjectName("avatar")
        self.avatar.setPixmap(self.tweet.author.avatar)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.avatar.sizePolicy().hasHeightForWidth())
        self.avatar.setSizePolicy(sizePolicy)
        self.avatar.setAlignment(QtCore.Qt.AlignTop)
        self.avatar.clicked.connect(self._userClicked)
        self.verticalLayout_2.addWidget(self.avatar)

        self.time = SimpleLabel()
        self.time.setObjectName("time")
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.time.sizePolicy().hasHeightForWidth())
        self.time.setSizePolicy(sizePolicy)
        self.verticalLayout_2.addWidget(self.time)
        self.verticalLayout_2.setAlignment(QtCore.Qt.AlignTop)

        self.horizontalLayout.addLayout(self.verticalLayout_2)
        self.verticalLayout = QtGui.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")

        self.username = QtGui.QLabel(self)
        self.username.setObjectName("username")
        self.username.setAlignment(QtCore.Qt.AlignTop)
        self.username.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
        self.verticalLayout.addWidget(self.username)

        self.tweetText = WTweetLabel(self)
        self.tweetText.setObjectName("tweetText")
        self.tweetText.setAlignment(QtCore.Qt.AlignTop)
        self.tweetText.userClicked.connect(self._userTextClicked)
        self.tweetText.tagClicked.connect(self._tagClicked)
        self.verticalLayout.addWidget(self.tweetText)

        if self.tweet.thumbnail_pic and ("image" not in self.without):
            self.imageWidget = self._createImageLabel(self.tweet.thumbnail_pic)
            self.verticalLayout.addWidget(self.imageWidget)

        if self.tweet.original and ("original" not in self.without):
            self.originalLabel = self._createOriginalLabel()
            self.verticalLayout.addWidget(self.originalLabel)

        self.horizontalLayout.setStretch(1, 1)
        self.horizontalLayout.setStretch(2, 10)

        self.counterHorizontalLayout = QtGui.QHBoxLayout()
        self.counterHorizontalLayout.setObjectName("counterhorizontalLayout")
        self.horizontalSpacer = QtGui.QSpacerItem(40, 20,
                                                  QtGui.QSizePolicy.Expanding,
                                                  QtGui.QSizePolicy.Minimum)
        self.counterHorizontalLayout.addItem(self.horizontalSpacer)

        if WeRuntimeInfo().get("uid") == self.tweet.author.id:
            self.delete = self._createDeleteLabel()
            self.counterHorizontalLayout.addWidget(self.delete)

        if not (self.tweet.type == TweetItem.COMMENT):
            self.client = QtGui.QLabel()
            self.client.setText(self.tr("From: %s") % self.tweet.source)
            self.client.linkActivated.connect(lambda link: openLink(link))
            self.counterHorizontalLayout.addWidget(self.client)

            self.retweet = self._createRetweetLabel()
            self.counterHorizontalLayout.addWidget(self.retweet)

            self.comment = self._createCommentLabel()
            self.counterHorizontalLayout.addWidget(self.comment)

            self.favorite = self._createFavoriteLabel()
            self.counterHorizontalLayout.addWidget(self.favorite)

            self.counterHorizontalLayout.setAlignment(QtCore.Qt.AlignTop)
        elif self.tweet.type == TweetItem.COMMENT:
            self.reply = self._createReplyLabel()
            self.counterHorizontalLayout.addWidget(self.reply)

        self.verticalLayout.addLayout(self.counterHorizontalLayout)
        self.horizontalLayout.addLayout(self.verticalLayout)

        self.setStyleSheet("""
            QFrame#SingleTweetWidget {
                border-bottom: 2px solid palette(highlight);
                border-radius: 0px;
                padding: 2px;
            }
        """)

        self.username.setText(" " + self.tweet.author.name)
        text = QtCore.Qt.escape(self.tweet.text)
        text = self._create_mentions(text)
        text = self._create_html_url(text)
        text = self._create_hashtag(text)
        text = self._create_smiles(text)
        self.tweetText.setHtml(text)
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self._update_time)
        self._update_time()

    def _setup_timer(self):
        self.timer.stop()
        passedSeconds = self.tweet.passedSeconds
        if passedSeconds < 60:
            self.timer.start(1 * 1000)
        elif passedSeconds < 3600:
            self.timer.start(60 * 1000)
        elif passedSeconds < 86400:
            self.timer.start(60 * 60 * 1000)
        else:
            self.timer.start(60 * 60 * 24 * 1000)

    def _update_time(self):
        try:
            if not self.time.visibleRegion() and self.timer.isActive():
                # Skip update only when timer is active, insure
                # at least run once time.
                return

            if not self.time.toolTip():
                self.time.setToolTip(self.tweet.timestamp)

            if self.tweet.type != TweetItem.COMMENT:
                self.time.setText("<a href='%s'>%s</a>" %
                                  (self.tweet.url, self.tweet.time))
            else:
                self.time.setText("<a href='%s'>%s</a>" %
                                  (self.tweet.original.url, self.tweet.time))
            self._setup_timer()
        except:
            # Sometimes, user closed the window and the window
            # has been garbage collected already, but
            # the timer is still running. It will cause a runtime error
            pass

    def _createOriginalLabel(self):
        widget = QtGui.QWidget(self)
        widget.setObjectName("originalWidget")
        widgetLayout = QtGui.QVBoxLayout(widget)
        widgetLayout.setSpacing(0)
        widgetLayout.setMargin(0)
        widgetLayout.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)

        frame = QtGui.QFrame()
        frame.setObjectName("originalFrame")
        widgetLayout.addWidget(frame)
        layout = QtGui.QVBoxLayout(frame)
        layout.setObjectName("originalLayout")
        layout.setAlignment(QtCore.Qt.AlignTop)
        textLabel = WTweetLabel()
        textLabel.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)
        textLabel.userClicked.connect(self._userTextClicked)
        textLabel.tagClicked.connect(self._tagClicked)
        self.textLabel = textLabel  # Hack: save a reference
        originalItem = self.tweet.original

        text = QtCore.Qt.escape(originalItem.text)
        text = self._create_mentions(text)
        text = self._create_html_url(text)
        text = self._create_hashtag(text)
        text = self._create_smiles(text)
        try:
            authorName = self._create_mentions("@" + originalItem.author.name)
            textLabel.setHtml("%s: %s" % (authorName, text))
        except:
            # originalItem.text == This tweet deleted by author
            textLabel.setHtml(text)
        layout.addWidget(textLabel)

        if originalItem.thumbnail_pic:
            layout.addWidget(self._createImageLabel(originalItem.thumbnail_pic))

        counterHorizontalLayout = QtGui.QHBoxLayout()
        counterHorizontalLayout.setObjectName("counterhorizontalLayout")
        horizontalSpacer = QtGui.QSpacerItem(40, 20,
                                             QtGui.QSizePolicy.Expanding,
                                             QtGui.QSizePolicy.Minimum)
        counterHorizontalLayout.addItem(horizontalSpacer)
        retweet = WIconLabel(widget)
        retweet.setObjectName("retweet")
        retweet.setText(str(originalItem.retweets_count))
        retweet.setIcon(":/IMG/img/retweets.png")
        retweet.clicked.connect(self._original_retweet)
        counterHorizontalLayout.addWidget(retweet)
        comment = WIconLabel(widget)
        comment.setObjectName("comment")
        comment.setIcon(":/IMG/img/comments.png")
        comment.setText(str(originalItem.comments_count))
        comment.clicked.connect(self._original_comment)
        counterHorizontalLayout.addWidget(comment)
        counterHorizontalLayout.setSpacing(6)
        layout.setMargin(8)
        layout.setSpacing(0)
        layout.addLayout(counterHorizontalLayout)

        frame.setStyleSheet("""
            QFrame#originalFrame {
                border: 2px solid palette(highlight);
                border-radius: 4px;
                padding: 2px;
            }
        """)

        return widget

    def _createImageLabel(self, thumbnail_pic):
        widget = QtGui.QWidget(self)
        widget.setObjectName("imageLabel")
        widgetLayout = QtGui.QVBoxLayout(widget)
        widgetLayout.setSpacing(0)
        widgetLayout.setMargin(0)
        widgetLayout.setAlignment(QtCore.Qt.AlignCenter)

        frame = QtGui.QFrame()
        frame.setObjectName("imageFrame")
        widgetLayout.addWidget(frame)
        layout = QtGui.QVBoxLayout(frame)
        layout.setObjectName("imageLayout")

        self.imageLabel = WSwitchLabel(widget)
        self.imageLabel.setImagesUrls(thumbnail_pic)
        self.imageLabel.clicked.connect(self._showFullImage)

        layout.addWidget(self.imageLabel)
        widgetLayout.addWidget(frame)

        return widget

    def _createFavoriteLabel(self):
        favorite = WIconLabel(self)
        favorite.setIcon(":/IMG/img/no_favorites.png")
        favorite.clicked.connect(self._favorite)
        return favorite

    def _createRetweetLabel(self):
        retweet = WIconLabel(self)
        retweet.setObjectName("retweet")
        retweet.setText(str(self.tweet.retweets_count))
        retweet.setIcon(":/IMG/img/retweets.png")
        retweet.clicked.connect(self._retweet)
        return retweet

    def _createCommentLabel(self):
        comment = WIconLabel(self)
        comment.setObjectName("comment")
        comment.setIcon(":/IMG/img/comments.png")
        comment.setText(str(self.tweet.comments_count))
        comment.clicked.connect(self._comment)
        return comment

    def _createReplyLabel(self):
        reply = WIconLabel(self)
        reply.setObjectName("reply")
        reply.setIcon(":/IMG/img/retweets.png")
        reply.clicked.connect(self._reply)
        return reply

    def _createDeleteLabel(self):
        delete = WIconLabel(self)
        delete.setObjectName("delete")
        delete.setIcon(":/IMG/img/deletes.png")
        delete.clicked.connect(self._delete)
        return delete

    def fetch_open_original_pic(self, thumbnail_pic):
        """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."""

        def open_pic(localfile):
            start(localfile)
            self.download_lock = False
            self.imageLabel.setBusy(False)

        if self.download_lock:
            return

        self.download_lock = True
        self.imageLabel.setBusy(True)
        original_pic = thumbnail_pic.replace("thumbnail",
                                             "large")  # A simple trick ... ^_^
        self.fetcher.addTask(original_pic, open_pic)

    def _showFullImage(self):
        self.fetch_open_original_pic(self.imageLabel.url())

    def _favorite(self):
        needWorker = False

        if not self.__favorite_queue:
            state = not self.tweet.isFavorite()
            needWorker = True
        elif not self.__favorite_queue[-1]:
            state = True
        else:
            state = False

        self.__favorite_queue.append(state)
        if state:
            self.favorite.setIcon(":/IMG/img/favorites.png")
        else:
            self.favorite.setIcon(":/IMG/img/no_favorites.png")

        if needWorker:
            self.__favorite_worker()

    @async
    def __favorite_worker(self):
        while self.__favorite_queue:
            state = self.__favorite_queue[0]

            try:
                self.tweet.setFavorite(state)
                sleep(0.5)
                self.__favorite_queue.pop(0)
            except APIError as e:
                if e.error_code == 20101:
                    self.tweet.setFavoriteForce(True)
                elif e.error_code == 20704:
                    self.tweet.setFavoriteForce(True)
                self._e = e
                self.__favorite_queue = []
                self.errorWindow.raiseException.emit(self._e)
                return

    def _retweet(self, tweet=None):
        if not tweet:
            tweet = self.tweet

        self.exec_newpost_window("retweet", tweet)

    def _comment(self, tweet=None):
        if not tweet:
            tweet = self.tweet
        if tweet.type == TweetItem.COMMENT:
            self._reply(tweet)
            return

        self.exec_newpost_window("comment", tweet)

    def _reply(self, tweet=None):
        if not tweet:
            tweet = self.tweet
        self.exec_newpost_window("reply", tweet)

    def _delete(self):

        @async
        def do_delete():
            try:
                self.tweet.delete()
                self.deleteReturn.emit(True)
            except APIError as e:
                self.errorWindow.raiseException.emit(e)
                self.deleteReturn.emit(False)

        questionDialog = QtGui.QMessageBox.question
        choice = questionDialog(self, self.tr("Delete?"),
                                self.tr("You can't undo your deletion."),
                                QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if choice == QtGui.QMessageBox.No:
            return

        self.deleteReturn.connect(lambda state: state and self.remove())
        do_delete()

    def remove(self):
        # not really remove myself.
        self.timer.stop()
        self.hide()

    def _original_retweet(self):
        self._retweet(self.tweet.original)

    def _original_comment(self):
        self._comment(self.tweet.original)

    def _create_html_url(self, text):
        return self.SINA_URL_RE.sub(r"""<a href='\1'>\1</a>""", text)

    def _create_smiles(self, text):
        faceModel = FaceModel()
        for face in faceModel.all_faces():
            new_text = text.replace("[%s]" % face.name, '<img src="%s" />' % face.path)
            if new_text != text:
                self._create_animation(face.path)
                text = new_text
        return text

    def _create_mentions(self, text):
        return self.MENTIONS_RE.sub(r"""<a href='mentions:///\1'>\1</a>""", text)

    def _create_hashtag(self, text):
        return self.HASHTAG_RE.sub(r"""<a href='hashtag:///\1'>\1</a>""", text)

    def _create_animation(self, path):
        movie = WObjectCache().open(WMovie, path)
        movie.frameChanged.connect(self.drawAnimate, QtCore.Qt.UniqueConnection)
        movie.start()

    def drawAnimate(self):
        sender = self.sender()

        if (not isinstance(sender, WMovie)) or (not self.tweetText.visibleRegion()):
            return

        movie = sender

        self._addSingleFrame(movie, self.tweetText)
        if self.tweet.original and ("original" not in self.without):
            self._addSingleFrame(movie, self.textLabel)

    def _addSingleFrame(self, movie, textBrowser):
        document = textBrowser.document()
        document.addResource(QtGui.QTextDocument.ImageResource,
                             QtCore.QUrl(movie.fileName()),
                             movie.currentPixmap())
        # Cause a force refresh
        textBrowser.update()

    def exec_newpost_window(self, action, tweet):
        from NewpostWindow import NewpostWindow
        try:
            self.wecase_new = NewpostWindow(action, tweet)
            self.wecase_new.userClicked.connect(self.userClicked)
            self.wecase_new.tagClicked.connect(self.tagClicked)
            self.wecase_new.show()
        except APIError as e:
            self.errorWindow.raiseException.emit(e)

    def _userClicked(self, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.userClicked.emit(self.tweet.author, openAtBackend)

    @async
    def _userTextClicked(self, user, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True

        try:
            self.__userItem = UserItem({"name": user})
        except APIError as e:
            self.errorWindow.raiseException.emit(e)
            return
        self.userClicked.emit(self.__userItem, openAtBackend)

    def _tagClicked(self, tag, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.tagClicked.emit(tag, openAtBackend)
Ejemplo n.º 12
0
class SingleTweetWidget(QtGui.QFrame):

    userClicked = QtCore.pyqtSignal(UserItem, bool)
    tagClicked = QtCore.pyqtSignal(str, bool)
    deleteReturn = QtCore.pyqtSignal(bool)

    MENTIONS_RE = re.compile('(@[-a-zA-Z0-9_\u4e00-\u9fa5]+)')
    SINA_URL_RE = re.compile(r"(http://t.cn/[a-zA-Z0-9]{5,7})")
    HASHTAG_RE = re.compile("(#.*?#)")

    def __init__(self, tweet=None, without=(), parent=None):
        super(SingleTweetWidget, self).__init__(parent)
        self.errorWindow = APIErrorWindow(self)
        self.tweet = tweet
        self.client = const.client
        self.without = without
        self.setObjectName("SingleTweetWidget")
        try:
            self.setupUi()
        except RuntimeError:
            return
        self.fetcher = AsyncFetcher("".join(
            (cache_path, str(WeRuntimeInfo()["uid"]))))
        self.download_lock = False
        self.__favorite_queue = []

    def setupUi(self):
        self.horizontalLayout = QtGui.QHBoxLayout(self)
        self.horizontalLayout.setMargin(0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.verticalLayout_2 = QtGui.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")

        reason = self.tweet.author.verify_reason
        if self.tweet.author.verify_type == "personal":
            self.avatar = WAvatarLabel(WAvatarLabel.PERSONAL_VERIFY, reason)
        elif self.tweet.author.verify_type == "organization":
            self.avatar = WAvatarLabel(WAvatarLabel.ORGANIZATION_VERIFY,
                                       reason)
        else:
            self.avatar = WAvatarLabel(WAvatarLabel.NO_VERIFY)
        self.avatar.setObjectName("avatar")
        self.avatar.setPixmap(self.tweet.author.avatar)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
                                       QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.avatar.sizePolicy().hasHeightForWidth())
        self.avatar.setSizePolicy(sizePolicy)
        self.avatar.setAlignment(QtCore.Qt.AlignTop)
        self.avatar.clicked.connect(self._userClicked)
        self.verticalLayout_2.addWidget(self.avatar)

        self.time = SimpleLabel()
        self.time.setObjectName("time")
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed,
                                       QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.time.sizePolicy().hasHeightForWidth())
        self.time.setSizePolicy(sizePolicy)
        self.verticalLayout_2.addWidget(self.time)
        self.verticalLayout_2.setAlignment(QtCore.Qt.AlignTop)

        self.horizontalLayout.addLayout(self.verticalLayout_2)
        self.verticalLayout = QtGui.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")

        self.username = QtGui.QLabel(self)
        self.username.setObjectName("username")
        self.username.setAlignment(QtCore.Qt.AlignTop)
        self.username.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
        self.verticalLayout.addWidget(self.username)

        self.tweetText = WTweetLabel(self)
        self.tweetText.setObjectName("tweetText")
        self.tweetText.setAlignment(QtCore.Qt.AlignTop)
        self.tweetText.userClicked.connect(self._userTextClicked)
        self.tweetText.tagClicked.connect(self._tagClicked)
        self.verticalLayout.addWidget(self.tweetText)

        if self.tweet.thumbnail_pic and ("image" not in self.without):
            self.imageWidget = self._createImageLabel(self.tweet.thumbnail_pic)
            self.verticalLayout.addWidget(self.imageWidget)

        if self.tweet.original and ("original" not in self.without):
            self.originalLabel = self._createOriginalLabel()
            self.verticalLayout.addWidget(self.originalLabel)

        self.horizontalLayout.setStretch(1, 1)
        self.horizontalLayout.setStretch(2, 10)

        self.counterHorizontalLayout = QtGui.QHBoxLayout()
        self.counterHorizontalLayout.setObjectName("counterhorizontalLayout")
        self.horizontalSpacer = QtGui.QSpacerItem(40, 20,
                                                  QtGui.QSizePolicy.Expanding,
                                                  QtGui.QSizePolicy.Minimum)
        self.counterHorizontalLayout.addItem(self.horizontalSpacer)

        if WeRuntimeInfo().get("uid") == self.tweet.author.id:
            self.delete = self._createDeleteLabel()
            self.counterHorizontalLayout.addWidget(self.delete)

        if not (self.tweet.type == TweetItem.COMMENT):
            self.client = QtGui.QLabel()
            self.client.setText(self.tr("From: %s") % self.tweet.source)
            self.client.linkActivated.connect(lambda link: openLink(link))
            self.counterHorizontalLayout.addWidget(self.client)

            self.retweet = self._createRetweetLabel()
            self.counterHorizontalLayout.addWidget(self.retweet)

            self.comment = self._createCommentLabel()
            self.counterHorizontalLayout.addWidget(self.comment)

            self.favorite = self._createFavoriteLabel()
            self.counterHorizontalLayout.addWidget(self.favorite)

            self.counterHorizontalLayout.setAlignment(QtCore.Qt.AlignTop)
        elif self.tweet.type == TweetItem.COMMENT:
            self.reply = self._createReplyLabel()
            self.counterHorizontalLayout.addWidget(self.reply)

        self.verticalLayout.addLayout(self.counterHorizontalLayout)
        self.horizontalLayout.addLayout(self.verticalLayout)

        self.setStyleSheet("""
            QFrame#SingleTweetWidget {
                border-bottom: 2px solid palette(highlight);
                border-radius: 0px;
                padding: 2px;
            }
        """)

        self.username.setText(" " + self.tweet.author.name)
        text = QtCore.Qt.escape(self.tweet.text)
        text = self._create_mentions(text)
        text = self._create_html_url(text)
        text = self._create_hashtag(text)
        text = self._create_smiles(text)
        self.tweetText.setHtml(text)
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self._update_time)
        self._update_time()

    def _setup_timer(self):
        self.timer.stop()
        passedSeconds = self.tweet.passedSeconds
        if passedSeconds < 60:
            self.timer.start(1 * 1000)
        elif passedSeconds < 3600:
            self.timer.start(60 * 1000)
        elif passedSeconds < 86400:
            self.timer.start(60 * 60 * 1000)
        else:
            self.timer.start(60 * 60 * 24 * 1000)

    def _update_time(self):
        try:
            if not self.time.visibleRegion() and self.timer.isActive():
                # Skip update only when timer is active, insure
                # at least run once time.
                return

            if not self.time.toolTip():
                self.time.setToolTip(self.tweet.timestamp)

            if self.tweet.type != TweetItem.COMMENT:
                self.time.setText("<a href='%s'>%s</a>" %
                                  (self.tweet.url, self.tweet.time))
            else:
                self.time.setText("<a href='%s'>%s</a>" %
                                  (self.tweet.original.url, self.tweet.time))
            self._setup_timer()
        except:
            # Sometimes, user closed the window and the window
            # has been garbage collected already, but
            # the timer is still running. It will cause a runtime error
            pass

    def _createOriginalLabel(self):
        widget = QtGui.QWidget(self)
        widget.setObjectName("originalWidget")
        widgetLayout = QtGui.QVBoxLayout(widget)
        widgetLayout.setSpacing(0)
        widgetLayout.setMargin(0)
        widgetLayout.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)

        frame = QtGui.QFrame()
        frame.setObjectName("originalFrame")
        widgetLayout.addWidget(frame)
        layout = QtGui.QVBoxLayout(frame)
        layout.setObjectName("originalLayout")
        layout.setAlignment(QtCore.Qt.AlignTop)
        textLabel = WTweetLabel()
        textLabel.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)
        textLabel.userClicked.connect(self._userTextClicked)
        textLabel.tagClicked.connect(self._tagClicked)
        self.textLabel = textLabel  # Hack: save a reference
        originalItem = self.tweet.original

        text = QtCore.Qt.escape(originalItem.text)
        text = self._create_mentions(text)
        text = self._create_html_url(text)
        text = self._create_hashtag(text)
        text = self._create_smiles(text)
        try:
            authorName = self._create_mentions("@" + originalItem.author.name)
            textLabel.setHtml("%s: %s" % (authorName, text))
        except:
            # originalItem.text == This tweet deleted by author
            textLabel.setHtml(text)
        layout.addWidget(textLabel)

        if originalItem.thumbnail_pic:
            layout.addWidget(self._createImageLabel(
                originalItem.thumbnail_pic))

        counterHorizontalLayout = QtGui.QHBoxLayout()
        counterHorizontalLayout.setObjectName("counterhorizontalLayout")
        horizontalSpacer = QtGui.QSpacerItem(40, 20,
                                             QtGui.QSizePolicy.Expanding,
                                             QtGui.QSizePolicy.Minimum)
        counterHorizontalLayout.addItem(horizontalSpacer)
        retweet = WIconLabel(widget)
        retweet.setObjectName("retweet")
        retweet.setText(str(originalItem.retweets_count))
        retweet.setIcon(":/IMG/img/retweets.png")
        retweet.clicked.connect(self._original_retweet)
        counterHorizontalLayout.addWidget(retweet)
        comment = WIconLabel(widget)
        comment.setObjectName("comment")
        comment.setIcon(":/IMG/img/comments.png")
        comment.setText(str(originalItem.comments_count))
        comment.clicked.connect(self._original_comment)
        counterHorizontalLayout.addWidget(comment)
        counterHorizontalLayout.setSpacing(6)
        layout.setMargin(8)
        layout.setSpacing(0)
        layout.addLayout(counterHorizontalLayout)

        frame.setStyleSheet("""
            QFrame#originalFrame {
                border: 2px solid palette(highlight);
                border-radius: 4px;
                padding: 2px;
            }
        """)

        return widget

    def _createImageLabel(self, thumbnail_pic):
        widget = QtGui.QWidget(self)
        widget.setObjectName("imageLabel")
        widgetLayout = QtGui.QVBoxLayout(widget)
        widgetLayout.setSpacing(0)
        widgetLayout.setMargin(0)
        widgetLayout.setAlignment(QtCore.Qt.AlignCenter)

        frame = QtGui.QFrame()
        frame.setObjectName("imageFrame")
        widgetLayout.addWidget(frame)
        layout = QtGui.QVBoxLayout(frame)
        layout.setObjectName("imageLayout")

        self.imageLabel = WSwitchLabel(widget)
        self.imageLabel.setImagesUrls(thumbnail_pic)
        self.imageLabel.clicked.connect(self._showFullImage)

        layout.addWidget(self.imageLabel)
        widgetLayout.addWidget(frame)

        return widget

    def _createFavoriteLabel(self):
        favorite = WIconLabel(self)
        favorite.setIcon(":/IMG/img/no_favorites.png")
        favorite.clicked.connect(self._favorite)
        return favorite

    def _createRetweetLabel(self):
        retweet = WIconLabel(self)
        retweet.setObjectName("retweet")
        retweet.setText(str(self.tweet.retweets_count))
        retweet.setIcon(":/IMG/img/retweets.png")
        retweet.clicked.connect(self._retweet)
        return retweet

    def _createCommentLabel(self):
        comment = WIconLabel(self)
        comment.setObjectName("comment")
        comment.setIcon(":/IMG/img/comments.png")
        comment.setText(str(self.tweet.comments_count))
        comment.clicked.connect(self._comment)
        return comment

    def _createReplyLabel(self):
        reply = WIconLabel(self)
        reply.setObjectName("reply")
        reply.setIcon(":/IMG/img/retweets.png")
        reply.clicked.connect(self._reply)
        return reply

    def _createDeleteLabel(self):
        delete = WIconLabel(self)
        delete.setObjectName("delete")
        delete.setIcon(":/IMG/img/deletes.png")
        delete.clicked.connect(self._delete)
        return delete

    def fetch_open_original_pic(self, thumbnail_pic):
        """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."""
        def open_pic(localfile):
            start(localfile)
            self.download_lock = False
            self.imageLabel.setBusy(False)

        if self.download_lock:
            return

        self.download_lock = True
        self.imageLabel.setBusy(True)
        original_pic = thumbnail_pic.replace("thumbnail",
                                             "large")  # A simple trick ... ^_^
        self.fetcher.addTask(original_pic, open_pic)

    def _showFullImage(self):
        self.fetch_open_original_pic(self.imageLabel.url())

    def _favorite(self):
        needWorker = False

        if not self.__favorite_queue:
            state = not self.tweet.isFavorite()
            needWorker = True
        elif not self.__favorite_queue[-1]:
            state = True
        else:
            state = False

        self.__favorite_queue.append(state)
        if state:
            self.favorite.setIcon(":/IMG/img/favorites.png")
        else:
            self.favorite.setIcon(":/IMG/img/no_favorites.png")

        if needWorker:
            self.__favorite_worker()

    @async
    def __favorite_worker(self):
        while self.__favorite_queue:
            state = self.__favorite_queue[0]

            try:
                self.tweet.setFavorite(state)
                sleep(0.5)
                self.__favorite_queue.pop(0)
            except APIError as e:
                if e.error_code == 20101:
                    self.tweet.setFavoriteForce(True)
                elif e.error_code == 20704:
                    self.tweet.setFavoriteForce(True)
                self._e = e
                self.__favorite_queue = []
                self.errorWindow.raiseException.emit(self._e)
                return

    def _retweet(self, tweet=None):
        if not tweet:
            tweet = self.tweet

        self.exec_newpost_window("retweet", tweet)

    def _comment(self, tweet=None):
        if not tweet:
            tweet = self.tweet
        if tweet.type == TweetItem.COMMENT:
            self._reply(tweet)
            return

        self.exec_newpost_window("comment", tweet)

    def _reply(self, tweet=None):
        if not tweet:
            tweet = self.tweet
        self.exec_newpost_window("reply", tweet)

    def _delete(self):
        @async
        def do_delete():
            try:
                self.tweet.delete()
                self.deleteReturn.emit(True)
            except APIError as e:
                self.errorWindow.raiseException.emit(e)
                self.deleteReturn.emit(False)

        questionDialog = QtGui.QMessageBox.question
        choice = questionDialog(self, self.tr("Delete?"),
                                self.tr("You can't undo your deletion."),
                                QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if choice == QtGui.QMessageBox.No:
            return

        self.deleteReturn.connect(lambda state: state and self.remove())
        do_delete()

    def remove(self):
        # not really remove myself.
        self.timer.stop()
        self.hide()

    def _original_retweet(self):
        self._retweet(self.tweet.original)

    def _original_comment(self):
        self._comment(self.tweet.original)

    def _create_html_url(self, text):
        return self.SINA_URL_RE.sub(r"""<a href='\1'>\1</a>""", text)

    def _create_smiles(self, text):
        faceModel = FaceModel()
        for face in faceModel.all_faces():
            new_text = text.replace("[%s]" % face.name,
                                    '<img src="%s" />' % face.path)
            if new_text != text:
                self._create_animation(face.path)
                text = new_text
        return text

    def _create_mentions(self, text):
        return self.MENTIONS_RE.sub(r"""<a href='mentions:///\1'>\1</a>""",
                                    text)

    def _create_hashtag(self, text):
        return self.HASHTAG_RE.sub(r"""<a href='hashtag:///\1'>\1</a>""", text)

    def _create_animation(self, path):
        movie = WObjectCache().open(WMovie, path)
        try:
            movie.frameChanged.connect(self.drawAnimate,
                                       QtCore.Qt.UniqueConnection)
        except TypeError:
            # connected already
            pass
        movie.start()

    def drawAnimate(self):
        sender = self.sender()

        if (not isinstance(sender,
                           WMovie)) or (not self.tweetText.visibleRegion()):
            return

        movie = sender

        self._addSingleFrame(movie, self.tweetText)
        if self.tweet.original and ("original" not in self.without):
            self._addSingleFrame(movie, self.textLabel)

    def _addSingleFrame(self, movie, textBrowser):
        document = textBrowser.document()
        document.addResource(QtGui.QTextDocument.ImageResource,
                             QtCore.QUrl(movie.fileName()),
                             movie.currentPixmap())
        # Cause a force refresh
        textBrowser.update()

    def exec_newpost_window(self, action, tweet):
        from NewpostWindow import NewpostWindow
        try:
            self.wecase_new = NewpostWindow(action, tweet)
            self.wecase_new.userClicked.connect(self.userClicked)
            self.wecase_new.tagClicked.connect(self.tagClicked)
            self.wecase_new.show()
        except APIError as e:
            self.errorWindow.raiseException.emit(e)

    def _userClicked(self, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.userClicked.emit(self.tweet.author, openAtBackend)

    @async
    def _userTextClicked(self, user, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True

        try:
            self.__userItem = UserItem({"name": user})
        except APIError as e:
            self.errorWindow.raiseException.emit(e)
            return
        self.userClicked.emit(self.__userItem, openAtBackend)

    def _tagClicked(self, tag, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.tagClicked.emit(tag, openAtBackend)
Ejemplo n.º 13
0
class SingleTweetWidget(QtGui.QFrame):

    imageLoaded = QtCore.pyqtSignal()
    userClicked = QtCore.pyqtSignal(UserItem, bool)
    tagClicked = QtCore.pyqtSignal(str, bool)
    commonSignal = QtCore.pyqtSignal(object)

    def __init__(self, tweet=None, without=[], parent=None):
        super(SingleTweetWidget, self).__init__(parent)
        self.commonSignal.connect(self.commonProcessor)
        self._gif_list = {}
        self.tweet = tweet
        self.client = const.client
        self.without = without
        self.setObjectName("SingleTweetWidget")
        self.setupUi()
        self.download_lock = False
        self.__favorite_queue = []

    def setupUi(self):
        self.horizontalLayout = QtGui.QHBoxLayout(self)
        self.horizontalLayout.setMargin(0)
        self.horizontalLayout.setObjectName("horizontalLayout")
        self.verticalLayout_2 = QtGui.QVBoxLayout()
        self.verticalLayout_2.setObjectName("verticalLayout_2")

        reason = self.tweet.author.verify_reason
        if self.tweet.author.verify_type == "personal":
            self.avatar = WAvatarLabel(WAvatarLabel.PERSONAL_VERIFY, reason)
        elif self.tweet.author.verify_type == "organization":
            self.avatar = WAvatarLabel(WAvatarLabel.ORGANIZATION_VERIFY, reason)
        else:
            self.avatar = WAvatarLabel(WAvatarLabel.NO_VERIFY)
        self.avatar.setObjectName("avatar")
        self.avatar.setPixmap(self.tweet.author.avatar)
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.avatar.sizePolicy().hasHeightForWidth())
        self.avatar.setSizePolicy(sizePolicy)
        self.avatar.setAlignment(QtCore.Qt.AlignTop)
        self.avatar.clicked.connect(self._userClicked)
        self.verticalLayout_2.addWidget(self.avatar)

        self.time = QtGui.QLabel(self)
        self.time.setObjectName("time")
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.time.sizePolicy().hasHeightForWidth())
        self.time.setSizePolicy(sizePolicy)
        self.time.setOpenExternalLinks(True)
        self.verticalLayout_2.addWidget(self.time)
        self.verticalLayout_2.setAlignment(QtCore.Qt.AlignTop)

        self.horizontalLayout.addLayout(self.verticalLayout_2)
        self.verticalLayout = QtGui.QVBoxLayout()
        self.verticalLayout.setObjectName("verticalLayout")

        self.username = QtGui.QLabel(self)
        self.username.setObjectName("username")
        self.username.setAlignment(QtCore.Qt.AlignTop)
        self.username.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
        self.verticalLayout.addWidget(self.username)

        self.tweetText = WTweetLabel(self)
        self.tweetText.setObjectName("tweetText")
        self.tweetText.setAlignment(QtCore.Qt.AlignTop)
        self.tweetText.userClicked.connect(self._userTextClicked)
        self.tweetText.tagClicked.connect(self._tagClicked)
        self.verticalLayout.addWidget(self.tweetText)

        if self.tweet.thumbnail_pic and (not "image" in self.without):
            self.imageWidget = self._createImageLabel(self.tweet.thumbnail_pic)
            self.verticalLayout.addWidget(self.imageWidget)

        if self.tweet.original and (not "original" in self.without):
            self.originalLabel = self._createOriginalLabel()
            self.verticalLayout.addWidget(self.originalLabel)

        self.horizontalLayout.setStretch(1, 1)
        self.horizontalLayout.setStretch(2, 10)

        self.counterHorizontalLayout = QtGui.QHBoxLayout()
        self.counterHorizontalLayout.setObjectName("counterhorizontalLayout")
        self.horizontalSpacer = QtGui.QSpacerItem(40, 20,
                                                  QtGui.QSizePolicy.Expanding,
                                                  QtGui.QSizePolicy.Minimum)
        self.counterHorizontalLayout.addItem(self.horizontalSpacer)

        if WeRuntimeInfo().get("uid") == self.tweet.author.id:
            self.delete = self._createDeleteLabel()
            self.counterHorizontalLayout.addWidget(self.delete)

        if not (self.tweet.type == TweetItem.COMMENT):
            self.retweet = self._createRetweetLabel()
            self.counterHorizontalLayout.addWidget(self.retweet)

            self.comment = self._createCommentLabel()
            self.counterHorizontalLayout.addWidget(self.comment)

            self.favorite = self._createFavoriteLabel()
            self.counterHorizontalLayout.addWidget(self.favorite)

            self.counterHorizontalLayout.setAlignment(QtCore.Qt.AlignTop)
        elif self.tweet.type == TweetItem.COMMENT:
            self.reply = self._createReplyLabel()
            self.counterHorizontalLayout.addWidget(self.reply)

        self.verticalLayout.addLayout(self.counterHorizontalLayout)
        self.horizontalLayout.addLayout(self.verticalLayout)

        self.setStyleSheet("""
            QFrame#SingleTweetWidget {
                border-bottom: 2px solid palette(highlight);
                border-radius: 0px;
                padding: 2px;
            }
        """)

        self.username.setText(" " + self.tweet.author.name)
        text = QtCore.Qt.escape(self.tweet.text)
        text = self._create_mentions(text)
        text = self._create_html_url(text)
        text = self._create_hashtag(text)
        text = self._create_smiles(text)
        self.tweetText.setHtml(text)
        self.timer = QtCore.QTimer(self)
        self.timer.timeout.connect(self._update_time)
        self._update_time()

    def _setup_timer(self):
        self.timer.stop()
        passedSeconds = self.tweet.passedSeconds
        if passedSeconds < 60:
            self.timer.start(1 * 1000)
        elif passedSeconds < 3600:
            self.timer.start(60 * 1000)
        elif passedSeconds < 86400:
            self.timer.start(60 * 60 * 1000)
        else:
            self.timer.start(60 * 60 * 24 * 1000)

    def _update_time(self):
        try:
            if self.tweet.type != TweetItem.COMMENT:
                self.time.setText("<a href='%s'>%s</a>" %
                                  (self.tweet.url, self.tweet.time))
            else:
                self.time.setText("<a href='%s'>%s</a>" %
                                  (self.tweet.original.url, self.tweet.time))
            self._setup_timer()
        except:
            # Sometimes, user closed the window and the window
            # has been garbage collected already, but
            # the timer is still running. It will cause a runtime error
            pass

    def _createOriginalLabel(self):
        widget = QtGui.QWidget(self)
        widget.setObjectName("originalWidget")
        widgetLayout = QtGui.QVBoxLayout(widget)
        widgetLayout.setSpacing(0)
        widgetLayout.setMargin(0)
        widgetLayout.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)

        frame = QtGui.QFrame()
        frame.setObjectName("originalFrame")
        widgetLayout.addWidget(frame)
        layout = QtGui.QVBoxLayout(frame)
        layout.setObjectName("originalLayout")
        layout.setAlignment(QtCore.Qt.AlignTop)
        textLabel = WTweetLabel()
        textLabel.setAlignment(QtCore.Qt.AlignCenter | QtCore.Qt.AlignTop)
        textLabel.userClicked.connect(self._userTextClicked)
        textLabel.tagClicked.connect(self._tagClicked)
        self.textLabel = textLabel  # Hack: save a reference
        originalItem = self.tweet.original

        text = QtCore.Qt.escape(originalItem.text)
        text = self._create_mentions(text)
        text = self._create_html_url(text)
        text = self._create_hashtag(text)
        text = self._create_smiles(text)
        try:
            authorName = self._create_mentions("@" + originalItem.author.name)
            textLabel.setHtml("%s: %s" % (authorName, text))
        except:
            # originalItem.text == This tweet deleted by author
            textLabel.setHtml(text)
        layout.addWidget(textLabel)

        if originalItem.thumbnail_pic:
            layout.addWidget(self._createImageLabel(originalItem.thumbnail_pic))

        counterHorizontalLayout = QtGui.QHBoxLayout()
        counterHorizontalLayout.setObjectName("counterhorizontalLayout")
        horizontalSpacer = QtGui.QSpacerItem(40, 20,
                                             QtGui.QSizePolicy.Expanding,
                                             QtGui.QSizePolicy.Minimum)
        counterHorizontalLayout.addItem(horizontalSpacer)
        retweet = WIconLabel(widget)
        retweet.setObjectName("retweet")
        retweet.setText(str(originalItem.retweets_count))
        retweet.setIcon(const.myself_path + "/icon/retweets.png")
        retweet.clicked.connect(self._original_retweet)
        counterHorizontalLayout.addWidget(retweet)
        comment = WIconLabel(widget)
        comment.setObjectName("comment")
        comment.setIcon(const.myself_path + "/icon/comments.png")
        comment.setText(str(originalItem.comments_count))
        comment.clicked.connect(self._original_comment)
        counterHorizontalLayout.addWidget(comment)
        counterHorizontalLayout.setSpacing(6)
        layout.setMargin(8)
        layout.setSpacing(0)
        layout.addLayout(counterHorizontalLayout)

        frame.setStyleSheet("""
            QFrame#originalFrame {
                border: 2px solid palette(highlight);
                border-radius: 4px;
                padding: 2px;
            }
        """)

        return widget

    def _createImageLabel(self, thumbnail_pic):
        widget = QtGui.QWidget(self)
        widget.setObjectName("imageLabel")
        widgetLayout = QtGui.QVBoxLayout(widget)
        widgetLayout.setSpacing(0)
        widgetLayout.setMargin(0)
        widgetLayout.setAlignment(QtCore.Qt.AlignCenter)

        frame = QtGui.QFrame()
        frame.setObjectName("imageFrame")
        widgetLayout.addWidget(frame)
        layout = QtGui.QVBoxLayout(frame)
        layout.setObjectName("imageLayout")

        self.imageLabel = WAsyncLabel(widget)
        self.imageLabel.setPixmap(thumbnail_pic)
        self.imageLabel.setAlignment(QtCore.Qt.AlignCenter)
        self.imageLabel.clicked.connect(self._showFullImage)

        layout.addWidget(self.imageLabel)
        widgetLayout.addWidget(frame)

        return widget

    def _createFavoriteLabel(self):
        favorite = WIconLabel(self)
        favorite.setIcon(const.myself_path + "/icon/no_favorites.png")
        favorite.clicked.connect(self._favorite)
        return favorite

    def _createRetweetLabel(self):
        retweet = WIconLabel(self)
        retweet.setObjectName("retweet")
        retweet.setText(str(self.tweet.retweets_count))
        retweet.setIcon(const.myself_path + "/icon/retweets.png")
        retweet.clicked.connect(self._retweet)
        return retweet

    def _createCommentLabel(self):
        comment = WIconLabel(self)
        comment.setObjectName("comment")
        comment.setIcon(const.myself_path + "/icon/comments.png")
        comment.setText(str(self.tweet.comments_count))
        comment.clicked.connect(self._comment)
        return comment

    def _createReplyLabel(self):
        reply = WIconLabel(self)
        reply.setObjectName("reply")
        reply.setIcon(const.myself_path + "/icon/retweets.png")
        reply.clicked.connect(self._reply)
        return reply

    def _createDeleteLabel(self):
        delete = WIconLabel(self)
        delete.setObjectName("delete")
        delete.setIcon(const.myself_path + "/icon/deletes.png")
        delete.clicked.connect(self._delete)
        return delete

    @async
    def fetch_open_original_pic(self, thumbnail_pic):
        """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 self.download_lock:
            return

        self.download_lock = True
        self.commonSignal.emit(lambda: self.imageLabel.setBusy(True))
        original_pic = thumbnail_pic.replace("thumbnail",
                                             "large")  # A simple trick ... ^_^
        localfile = cache_path + original_pic.split("/")[-1]
        if not os.path.exists(localfile):
            while True:
                try:
                    urllib.request.urlretrieve(original_pic, localfile)
                    break
                except (BadStatusLine, URLError, ContentTooShortError):
                    continue

        self.download_lock = False
        self.commonSignal.emit(lambda: self.imageLabel.setBusy(False))
        start(localfile)
        self.imageLoaded.emit()

    def _showFullImage(self):
        self.fetch_open_original_pic(self.imageLabel.url())

    def commonProcessor(self, object):
        object()

    def _favorite(self):
        needWorker = False

        if not self.__favorite_queue:
            state = not self.tweet.isFavorite()
            needWorker = True
        elif not self.__favorite_queue[-1]:
            state = True
        else:
            state = False

        self.__favorite_queue.append(state)
        if state:
            self.favorite.setIcon(const.icon("favorites.png"))
        else:
            self.favorite.setIcon(const.icon("no_favorites.png"))

        if needWorker:
            self.__favorite_worker()

    @async
    def __favorite_worker(self):
        while self.__favorite_queue:
            state = self.__favorite_queue[0]

            try:
                self.tweet.setFavorite(state)
                sleep(0.5)
                self.__favorite_queue.pop(0)
            except APIError as e:
                if e.error_code == 20101:
                    self.tweet.setFavoriteForce(True)
                elif e.error_code == 20704:
                    self.tweet.setFavoriteForce(True)
                self._e = e
                self.__favorite_queue = []
                self.commonSignal.emit(lambda: self._handle_api_error(self._e))
                return

    def _retweet(self, tweet=None):
        if not tweet:
            tweet = self.tweet

        self.exec_newpost_window("retweet", tweet)

    def _comment(self, tweet=None):
        if not tweet:
            tweet = self.tweet
        if tweet.type == TweetItem.COMMENT:
            self._reply(tweet)
            return

        self.exec_newpost_window("comment", tweet)

    def _reply(self, tweet=None):
        if not tweet:
            tweet = self.tweet
        self.exec_newpost_window("reply", tweet)

    def _delete(self):
        questionDialog = QtGui.QMessageBox.question
        choice = questionDialog(self, self.tr("Delete?"),
                                self.tr("You can't undo your deletion."),
                                QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
        if choice == QtGui.QMessageBox.No:
            return

        try:
            self.tweet.delete()
        except APIError as e:
            self._handle_api_error(e)
        self.timer.stop()
        self.hide()

    def _original_retweet(self):
        self._retweet(self.tweet.original)

    def _original_comment(self):
        self._comment(self.tweet.original)

    def _create_html_url(self, text):
        COMMON_URL_RE = (
            r"(?:(http|https)://"
            r"(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?)\."
            r")*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?:\d+)(?:\.(?:\d+)"
            r"){3}))(?::(?:\d+))?)(?:/(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F"
            r"\d]{2}))|[;:@&=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{"
            r"2}))|[;:@&=])*))*)(?:\?(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-fA-F\d]{"
            r"2}))|[;:@&=])*))?)?)|(?:ftp://(?:(?:(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?"
            r":%[a-fA-F\d]{2}))|[;?&=])*)(?::(?:(?:(?:[a-zA-Z\d$\-_.+!*'(),]|(?:%[a-"
            r"fA-F\d]{2}))|[;?&=])*))?@)?(?:(?:(?:(?:(?:[a-zA-Z\d](?:(?:[a-zA-Z\d]|-"
            r")*[a-zA-Z\d])?)\.)*(?:[a-zA-Z](?:(?:[a-zA-Z\d]|-)*[a-zA-Z\d])?))|(?:(?"
            r":\d+)(?:\.(?:\d+)){3}))(?::(?:\d+))?))(?:/(?:(?:(?:(?:[a-zA-Z\d$\-_.+!"
            r"*'(),]|(?:%[a-fA-F\d]{2}))|[?:@&=])*)(?:/(?:(?:(?:[a-zA-Z\d$\-_.+!*'()"
            r",]|(?:%[a-fA-F\d]{2}))|[?:@&=])*))*)(?:;type=[AIDaid])?)?)"
        )
        SINA_URL_RE = r"(http://t.cn/\w{6,7})"
        regex = re.compile("((%s)|(%s))" % (SINA_URL_RE, COMMON_URL_RE))
        new_text = regex.sub(r"""<a href='\1'>\1</a>""", text)
        return new_text

    def _create_smiles(self, text):
        faceModel = FaceModel()
        faceModel.init()
        for name, path in faceModel.dic().items():
            new_text = text.replace("[%s]" % name, '<img src="%s" />' % path)
            if new_text != text:
                self._create_animation(path)
                text = new_text
        return text

    def _create_mentions(self, text):
        MENTIONS_RE = re.compile('(@[-a-zA-Z0-9_\u4e00-\u9fa5]+)')
        regex = re.compile(MENTIONS_RE)
        new_text = regex.sub(r"""<a href='mentions:///\1'>\1</a>""", text)
        return new_text

    def _create_hashtag(self, text):
        HASHTAG_RE = re.compile("([#]+[a-zA-Z0-9_\u4e00-\u9fa5\s]+[#])")
        regex = re.compile(HASHTAG_RE)
        new_text = regex.sub(r"""<a href='hashtag:///\1'>\1</a>""", text)
        return new_text

    def _create_animation(self, path):
        if path in self._gif_list.values():
            # We added it already.
            return
        movie = WObjectCache().open(QtGui.QMovie, path)
        self._gif_list[movie] = path
        movie.frameChanged.connect(self.drawAnimate)
        movie.start()

    def drawAnimate(self):
        sender = self.sender()
        if isinstance(sender, QtGui.QMovie):
            movie = sender
        else:
            return

        self._addSingleFrame(movie, self.tweetText)
        if self.tweet.type == TweetItem.RETWEET:
            try:
                self._addSingleFrame(movie, self.textLabel)
            except AttributeError:
                pass

    def _addSingleFrame(self, movie, textBrowser):
        document = textBrowser.document()
        document.addResource(QtGui.QTextDocument.ImageResource,
                             QtCore.QUrl(self._gif_list[movie]),
                             movie.currentPixmap())
        # Cause a force refresh
        textBrowser.setLineWrapColumnOrWidth(textBrowser.lineWrapColumnOrWidth())

    def exec_newpost_window(self, action, tweet):
        from NewpostWindow import NewpostWindow
        try:
            self.wecase_new = NewpostWindow(action, tweet)
            self.wecase_new.userClicked.connect(self.userClicked)
            self.wecase_new.tagClicked.connect(self.tagClicked)
            self.wecase_new.show()
        except APIError as e:
            self._handle_api_error(e)

    def _handle_api_error(self, exception):
        if exception.error_code == 20101:
            QtGui.QMessageBox.information(self, self.tr("Error"),
                                          self.tr("This tweet have been deleted."))
        elif exception.error_code == 20704:
            QtGui.QMessageBox.information(self, self.tr("Error"),
                                          self.tr("This tweet have been collected already.."))
        else:
            QtGui.QMessageBox.warning(self, self.tr("Unknown Error"),
                                      str(exception))

    def _userClicked(self, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.userClicked.emit(self.tweet.author, openAtBackend)

    def _userTextClicked(self, user, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.userClicked.emit(UserItem({"name": user}), openAtBackend)

    def _tagClicked(self, tag, button):
        openAtBackend = False
        if button == QtCore.Qt.MiddleButton:
            openAtBackend = True
        self.tagClicked.emit(tag, openAtBackend)
Ejemplo n.º 14
0
 def reply(self, idstr, cidstr):
     wecase_new = NewpostWindow(action="reply",
                                id=int(idstr),
                                cid=int(cidstr))
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 15
0
 def repost(self, idstr, text):
     wecase_new = NewpostWindow(action="retweet", id=int(idstr), text=text)
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 16
0
 def comment(self, idstr):
     wecase_new = NewpostWindow(action="comment", id=int(idstr))
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 17
0
 def postTweet(self):
     wecase_new = NewpostWindow()
     wecase_new.client = self.client
     wecase_new.exec_()
Ejemplo n.º 18
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")
Ejemplo n.º 19
0
 def postTweet(self):
     wecase_new = NewpostWindow()
     wecase_new.exec_()