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 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()
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)
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)