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 __init__(self, parent=None, action="new", id=None, cid=None, text=""): QtGui.QDialog.__init__(self, parent) self.action = action self.id = id self.cid = cid self.setupUi(self) self.setupMyUi() self.textEdit.setText(text) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1)
def check_availabilty_pincode(): from datetime import date for pincode, data in dict_pincode.items(): # today_date = date.today().strftime('%d-%m-%Y') to = data[0] id_list = data[1] pin_obj = SlotAvailableByPincode(pincode=pincode) pin_obj.get_slot_availability() flag, index, slots, age, date = pin_obj.return_list[0], pin_obj.return_list[1], pin_obj.return_list[2], pin_obj.return_list[3],pin_obj.return_list[4] if flag == True: email_obj = Notify(to, index, slots, age, date) if email_obj.send_mail(): remove_from_firebase(id_list, to)
def check_availabilty_district(): from datetime import date for district_id, data in dict_district.items(): # today_date = date.today().strftime('%d-%m-%Y') to = data[0] id_list = data[1] dist_obj = SlotAvailableByDistrict(district_id=district_id) dist_obj.get_slot_availability() flag, index, slots, age, date = dist_obj.return_list[0], dist_obj.return_list[1], dist_obj.return_list[2], dist_obj.return_list[3], dist_obj.return_list[4] if flag == True: email_obj = Notify(to, index, slots, age, date) if email_obj.send_mail(): remove_from_firebase(id_list, to)
def check_availabilty_district(): from datetime import date for district_id, data in dict_district.items(): to = data[0] id_list = data[1] dist_obj = SlotAvailableByID(target=district_id, mode="District") dist_obj.get_slot_availability() flag, index, slots, age, date = dist_obj.return_list[ 0], dist_obj.return_list[1], dist_obj.return_list[ 2], dist_obj.return_list[3], dist_obj.return_list[4] if flag == True: email_obj = Notify(to, index, slots, age, date) if email_obj.send_mail(): remove_from_firebase(id_list, to)
def __init__(self, client, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.tweetViews = [ self.homeView, self.mentionsView, self.commentsView, self.myView ] self.client = client self.setupModels() self.init_account() self.setupMyUi() self.loadConfig() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = []
def main(totalEvents, test_num): doPlot = False configModule = "NuralTest" maxEvents = totalEvents maxTimeSec = 0 runNumber = test_num outputFile = "data_sets/run{}_{}.bin".format(test_num, totalEvents) # Check argument validity ok = True if maxEvents < 0: print("Invalid number of events (can not be negative)") ok = False if maxTimeSec < 0: print("Invalid run time (can not be negative)") ok = False if not ok: print(__doc__) return 1 global MUONRATE wtime = round(totalEvents * float(MUONRATE)) print(25 * "=") print("\nRun {} for {} Events \n".format(test_num, totalEvents)) print("Starting DAQ system....") # if wtime == 0: # print("Process will take roughly {} min".format(1)) # else: # print("Process will take roughly {} mins".format(wtime)) # Configure the histogram plotter. # The channels to plot: a tuple of (slot, channel) pairs. # "None" will take all channels configured in the DAQ. channels_to_plot = ((2, 0), (2, 1), (2, 3), (2, 4), (2, 6), (2, 7), (2, 9), (2, 10)) nBins = 100 updateAfterHowManyEvents = 10 verticalSpaceAdjustment = 0.4 adcHisto = ADCHisto(nBins, updateAfterHowManyEvents, verticalSpaceAdjustment, channels_to_plot) tdcHisto = TDCHisto(nBins, updateAfterHowManyEvents, verticalSpaceAdjustment, channels_to_plot) plotUpdater = plotDiagnostics(doPlot, adcHisto, tdcHisto) n, t, s, err = runCAMAC(configModule, maxEvents, maxTimeSec, runNumber, outputFile, plotUpdater) print('Processed %d events in %g sec' % (n, t)) print('Run status is', s) if s == "Error": print('Error message:', err) if not (outputFile == "None" or outputFile == "none"): print('Run %d data is stored in the file "%s"' % (runNumber, outputFile)) print("Uploading File to Quanah.....\n") os.system("upload.sh {}".format(outputFile)) print("File {} has been successfully uploaded to Quanah\n".format( outputFile)) print(25 * "=") print() fileName = outputFile.split("/")[1] Notify(fileName).sendEmail() return 0
def __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage) self.errorWindow = APIErrorWindow(self) if self.action not in ["new", "reply"]: self.tweetRefreshed.connect(self._create_tweetWidget) self.tweetRejected.connect( lambda: self.pushButton_send.setEnabled(False)) self._refresh()
def quanahJob(outputFile): print("Uploading File to Quanah.....\n") os.system("upload.sh {}".format(outputFile)) print(25 * "=") print() fileName = outputFile.split("/")[1] analyzeOnQuanah(fileName) Notify(fileName).sendEmail() print("File {} has been successfully uploaded to Quanah\n".format( outputFile)) print() os.remove(outputFile)
def __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage)
def __init__(self, client, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.myView] self.client = client self.setupModels() self.init_account() self.setupMyUi() self.loadConfig() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = []
def __init__(self, parent=None): super(WeCaseWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, True) self._iconPixmap = {} self.setupUi(self) self._setupSysTray() self.tweetViews = [self.homeView, self.mentionsView, self.commentsView] 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 __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage) self.errorWindow = APIErrorWindow(self) if self.action not in ["new", "reply"]: self.tweetRefreshed.connect(self._create_tweetWidget) self.tweetRejected.connect(lambda: self.pushButton_send.setEnabled(False)) self._refresh()
def main(): camvi = Camvi(timeout=1) notify = Notify() # start listener camvi.listen() # retrieve camvi token camvi_tok = camvi.retrieve_auth_token() while True: # enable msg = camvi.event() print(msg) if msg['type'] != 'ADD': continue persons = msg.get('persons') if persons is not None: for person in persons: onBlackList = False groups = person['groups'] if groups is not None: for group in groups: if group['name'] == 'blacklist': onBlackList = True if onBlackList: print('Person on black list found!') image_url = 'http://' + camvi_options[ 'ip'] + ':' + camvi_options[ 'port'] + '/log/image/' + str(person['log']) # msg_to_send = "Person found, name: {}".format(str(person['name'])) # email if email_options['enabled']: msg_to_send = "<html><body>Black list person found, name {}, time {}, camera {}, <a href=\"{}\">picture</a></body></html>".format( str(person['name']), msg['time'], msg['camera'], image_url) print(msg_to_send) notify.send_email(subj="Black List Person Found", html=msg_to_send) # text if twilio_options['enabled']: msg_to_send = "black list person found: {}, {}".format( str(person['name']), image_url) print(msg_to_send) notify.send_text(msg=msg_to_send)
from MuonDataFrame import * from Notify import Notify if __name__ == "__main__": try: ifile = sys.argv[1] iisNew = sys.argv[2] except: print("No File passed / Invalid File") iisNew = False print("\nAssuming the file has been analyzed before.") mdfo = MuonDataFrame(ifile, isNew=iisNew, d1="last") pdfName = mdfo.generateAnaReport() Notify().sendPdfEmail(pdfName) #mdf = mdfo.events_df #mdfo.getChannelStatusPlot() # mdfo.gui() # mdfo.show() #mdfo.getAnaReport() # mdfo.generateAnaReport() # mdfo.computeAssymetries() # mdfo.get2DHistogram() # mdfo.getScatterPlot(["L1_asym", "L2_asym"]) # mdfo.getScatterPlot(["L3_asym", "L4_asym"]) # mdfo.getScatterPlot(["L1_asym", "L3_asym"]) # mdfo.getScatterPlot(["L2_asym", "L4_asym"]) # # mdfo.getAssymetry1DPlots() # mdf = mdfo.events_df
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): client = None image = None apiError = QtCore.pyqtSignal(str) sendSuccessful = QtCore.pyqtSignal() def __init__(self, parent=None, action="new", id=None, cid=None, text=""): QtGui.QDialog.__init__(self, parent) self.action = action self.id = id self.cid = cid self.setupUi(self) self.setupMyUi() self.textEdit.setText(text) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) def setupMyUi(self): self.checkChars() if self.action == "new": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) elif self.action == "retweet": self.chk_repost.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "comment": self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "reply": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) def mentions_suggest(self, text): ret_users = [] try: word = re.findall('@[-a-zA-Z0-9_\u4e00-\u9fa5]+', text)[-1] word = word.replace('@', '') except IndexError: return [] if not word.strip(): return [] users = self.client.search.suggestions.at_users.get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": threading.Thread(group=None, target=self.new).start() elif self.action == "retweet": threading.Thread(group=None, target=self.retweet).start() elif self.action == "comment": threading.Thread(group=None, target=self.comment).start() elif self.action == "reply": threading.Thread(group=None, target=self.reply).start() def retweet(self): text = str(self.textEdit.toPlainText()) try: self.client.statuses.repost.post(id=int(self.id), status=text, is_comment=int((self.chk_comment.isChecked() + self.chk_comment_original.isChecked() * 2))) self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def comment(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.create.post(id=int(self.id), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def reply(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.reply.post(id=int(self.id), cid=int(self.cid), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def new(self): text = str(self.textEdit.toPlainText()) try: if self.image: self.client.statuses.upload.post(status=text, pic=open(self.image, "rb")) else: self.client.statuses.update.post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) def showError(self, e): if "Text too long" in e: QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: QtGui.QMessageBox.warning(None, self.tr("Unknown error!"), e) self.pushButton_send.setEnabled(True) def showSmiley(self): wecase_smiley = SmileyWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.smileyName) def checkChars(self): '''Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.''' text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens))
class WeCaseWindow(QtGui.QMainWindow, Ui_frm_MainWindow): client = None uid = None imageLoaded = QtCore.pyqtSignal(str) tabTextChanged = QtCore.pyqtSignal(int, str) def __init__(self, client, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.myView] self.client = client self.setupModels() self.init_account() self.setupMyUi() self.loadConfig() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] def init_account(self): self.get_uid() def loadConfig(self): self.config = ConfigParser() self.config.read(const.config_path) if not self.config.has_section("main"): self.config["main"] = {} self.main_config = self.config["main"] self.timer_interval = int(self.main_config.get("notify_interval", 30)) self.notify_timeout = int(self.main_config.get("notify_timeout", 5)) self.remindMentions = self.main_config.getboolean("remind_mentions", 1) self.remindComments = self.main_config.getboolean("remind_comments", 1) def applyConfig(self): try: self.timer.stop_event.set() except AttributeError: pass self.timer = WTimer(self.timer_interval, self.show_notify) self.timer.start() self.notify.timeout = self.notify_timeout def setupMyUi(self): for tweetView in self.tweetViews: tweetView.setResizeMode(tweetView.SizeRootObjectToView) tweetView.setSource(QtCore.QUrl.fromLocalFile(const.myself_path + "/ui/TweetList.qml")) tweetView.rootContext().setContextProperty("mainWindow", self) @QtCore.pyqtSlot() def load_more(self): model = self.get_current_model() model.next() def setupModels(self): self.all_timeline = TweetCommonModel(TweetItem(), self.client.statuses.home_timeline, self) self.all_timeline.load() self.homeView.rootContext().setContextProperty("mymodel", self.all_timeline) self.mentions = TweetCommonModel(TweetItem(), self.client.statuses.mentions, self) self.mentions.load() self.mentionsView.rootContext().setContextProperty("mymodel", self.mentions) self.comment_to_me = TweetCommentModel(TweetItem(), self.client.comments.to_me, self) self.comment_to_me.load() self.commentsView.rootContext().setContextProperty("mymodel", self.comment_to_me) self.my_timeline = TweetCommonModel(TweetItem(), self.client.statuses.user_timeline, self) self.my_timeline.load() self.myView.rootContext().setContextProperty("mymodel", self.my_timeline) def reset_remind(self): if self.tabWidget.currentIndex() == 0: self.tabWidget.setTabText(0, self.tr("Weibo")) elif self.tabWidget.currentIndex() == 1: self.client.remind.set_count.post(type="mention_status") self.tabWidget.setTabText(1, self.tr("@Me")) elif self.tabWidget.currentIndex() == 2: self.client.remind.set_count.post(type="cmt") self.tabWidget.setTabText(2, self.tr("Comments")) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" reminds = self.client.remind.unread_count.get(uid=uid) return reminds def get_uid(self): """How can I get my uid? here it is""" try: self.uid = self.client.account.get_uid.get().uid except AttributeError: return None def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid) msg = self.tr("You have:") + "\n" num_msg = 0 if reminds["status"] != 0: # Note: do NOT send notify here, or users will crazy. self.tabTextChanged.emit(0, self.tr("Weibo(%d)") % reminds["status"]) if reminds["mention_status"] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds["mention_status"] + "\n" self.tabTextChanged.emit(1, self.tr("@Me(%d)") % reminds["mention_status"]) num_msg += 1 if reminds["cmt"] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds["cmt"] + "\n" self.tabTextChanged.emit(2, self.tr("Comments(%d)") % reminds["cmt"]) num_msg += 1 if num_msg: return self.notify.showMessage(self.tr("WeCase"), msg) def setTabText(self, index, string): self.tabWidget.setTabText(index, string) def moveToTop(self): self.get_current_tweetView().rootObject().positionViewAtBeginning() def setLoaded(self, tweetid): self.get_current_tweetView().rootObject().imageLoaded(tweetid) def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow() wecase_login.exec_() def postTweet(self): wecase_new = NewpostWindow() wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str) def comment(self, idstr): wecase_new = NewpostWindow(action="comment", id=int(idstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def repost(self, idstr, text): wecase_new = NewpostWindow(action="retweet", id=int(idstr), text=text) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, result=int) def favorite(self, idstr): try: self.client.favorites.create.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, result=bool) def un_favorite(self, idstr): try: self.client.favorites.destroy.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, str) def reply(self, idstr, cidstr): wecase_new = NewpostWindow(action="reply", id=int(idstr), cid=int(cidstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def look_orignal_pic(self, thumbnail_pic, tweetid): threading.Thread(group=None, target=self.fetch_open_original_pic, args=(thumbnail_pic, tweetid)).start() def fetch_open_original_pic(self, thumbnail_pic, tweetid): """Fetch and open original pic from thumbnail pic url. Pictures will stored in cache directory. If we already have a same name in cache directory, just open it. If we don't, then download it first.""" if tweetid in self.download_lock: return self.download_lock.append(tweetid) original_pic = thumbnail_pic.replace("thumbnail", "large") # A simple trick ... ^_^ localfile = const.cache_path + original_pic.split("/")[-1] if not os.path.exists(localfile): urllib.request.urlretrieve(original_pic, localfile) self.download_lock.remove(tweetid) os.popen("xdg-open " + localfile) # xdg-open is common? self.imageLoaded.emit(tweetid) def refresh(self): model = self.get_current_model() model.timelineLoaded.connect(self.moveToTop) # model.clear() # model.load() model.new() self.reset_remind() def get_current_tweetView(self): tweetViews = {0: self.homeView, 1: self.mentionsView, 2: self.commentsView, 3: self.myView} return tweetViews[self.tabWidget.currentIndex()] def get_current_model(self): models = {0: self.all_timeline, 1: self.mentions, 2: self.comment_to_me, 3: self.my_timeline} return models[self.tabWidget.currentIndex()] def get_current_function(self): functions = { 0: self.get_all_timeline, 1: self.get_mentions_timeline, 2: self.get_comment_to_me, 3: self.get_my_timeline, } return functions[self.tabWidget.currentIndex()] def closeEvent(self, event): self.timer.stop_event.set()
from Emailer import Emailer from Notify import Notify import time Notify("run8_100.bin").sendEmail() Notify().sendPdfEmail("events_data_frame_800.pdf")
class WeCaseWindow(QtGui.QMainWindow): client = None uid = None timelineLoaded = QtCore.pyqtSignal(int) imageLoaded = QtCore.pyqtSignal(str) tabBadgeChanged = QtCore.pyqtSignal(int, int) tabAvatarFetched = QtCore.pyqtSignal(str) def __init__(self, parent=None): super(WeCaseWindow, self).__init__(parent) self.errorWindow = APIErrorWindow(self) self.setAttribute(QtCore.Qt.WA_QuitOnClose, True) self._iconPixmap = {} self.setupUi(self) self._setupSysTray() self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.commentsMentionsTab] self.info = WeRuntimeInfo() self.client = const.client self.loadConfig() self.init_account() self.setupModels() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] self._last_reminds_count = 0 self._setupUserTab(self.uid(), False, True) def _setupTab(self, view): tab = QtGui.QWidget() layout = QtGui.QGridLayout(tab) layout.addWidget(view) view.setParent(tab) return tab def _setupCommonTab(self, timeline, view, switch=True, protect=False): self._prepareTimeline(timeline) view.setModel(timeline) view.userClicked.connect(self.userClicked) view.tagClicked.connect(self.tagClicked) tab = self._setupTab(view) self.tabWidget.addTab(tab, "") if switch: self.tabWidget.setCurrentWidget(tab) if protect: self.tabWidget.tabBar().setProtectTab(tab, True) return tab def _getSameTab(self, attr, value): for i in range(self.tabWidget.count()): try: tab = self.tabWidget.widget(i).layout().itemAt(0).widget() _value = getattr(tab.model(), attr)() if _value == value: return i except AttributeError: pass return False def _setupUserTab(self, uid, switch=True, myself=False): index = self._getSameTab("uid", uid) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() _timeline = TweetUserModel(self.client.statuses.user_timeline, uid, view) timeline = TweetFilterModel(_timeline) timeline.setModel(_timeline) tab = self._setupCommonTab(timeline, view, switch, myself) def setAvatar(f): self._setTabIcon(tab, WObjectCache().open(QtGui.QPixmap, f)) fetcher = AsyncFetcher("".join((path.cache_path, str(self.info["uid"])))) fetcher.addTask(self.client.users.show.get(uid=uid)["profile_image_url"], setAvatar) def _setupTopicTab(self, topic, switch=True): index = self._getSameTab("topic", topic) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() timeline = TweetTopicModel(self.client.search.topics, topic, view) tab = self._setupCommonTab(timeline, view, switch, protect=False) self._setTabIcon(tab, WObjectCache().open( QtGui.QPixmap, ":/IMG/img/topic.jpg" )) def userClicked(self, userItem, openAtBackend): try: self._setupUserTab(userItem.id, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def tagClicked(self, str, openAtBackend): try: self._setupTopicTab(str, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def setupUi(self, mainWindow): mainWindow.setWindowIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) mainWindow.setDocumentMode(False) mainWindow.setDockOptions(QtGui.QMainWindow.AllowTabbedDocks | QtGui.QMainWindow.AnimatedDocks) self.centralwidget = QtGui.QWidget(mainWindow) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.tabWidget = QtGui.QTabWidget(self.centralwidget) self.tabWidget.setTabBar(WTabBar(self.tabWidget)) self.tabWidget.setTabPosition(QtGui.QTabWidget.West) self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded) self.tabWidget.setDocumentMode(False) self.tabWidget.setMovable(True) self.tabWidget.tabCloseRequested.connect(self.closeTab) self.homeView = TweetListWidget() self.homeView.userClicked.connect(self.userClicked) self.homeView.tagClicked.connect(self.tagClicked) self.homeTab = self._setupTab(self.homeView) self.tabWidget.addTab(self.homeTab, "") self.tabWidget.tabBar().setProtectTab(self.homeTab, True) self.mentionsView = TweetListWidget() self.mentionsView.userClicked.connect(self.userClicked) self.mentionsView.tagClicked.connect(self.tagClicked) self.mentionsTab = self._setupTab(self.mentionsView) self.tabWidget.addTab(self.mentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.mentionsTab, True) self.commentsView = TweetListWidget() self.commentsView.userClicked.connect(self.userClicked) self.commentsView.tagClicked.connect(self.tagClicked) self.commentsTab = self._setupTab(self.commentsView) self.tabWidget.addTab(self.commentsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsTab, True) self.commentsMentionsView = TweetListWidget() self.commentsMentionsView.userClicked.connect(self.userClicked) self.commentsMentionsView.tagClicked.connect(self.tagClicked) self.commentsMentionsTab = self._setupTab(self.commentsMentionsView) self.tabWidget.addTab(self.commentsMentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsMentionsTab, True) self.verticalLayout.addWidget(self.tabWidget) self.widget = QtGui.QWidget(self.centralwidget) self.verticalLayout.addWidget(self.widget) mainWindow.setCentralWidget(self.centralwidget) self.aboutAction = QtGui.QAction(mainWindow) self.refreshAction = QtGui.QAction(mainWindow) self.logoutAction = QtGui.QAction(mainWindow) self.exitAction = QtGui.QAction(mainWindow) self.settingsAction = QtGui.QAction(mainWindow) self.aboutAction.setIcon(QtGui.QIcon(QtGui.QPixmap("./IMG/img/where_s_my_weibo.svg"))) self.exitAction.setIcon(QtGui.QIcon(QtGui.QPixmap(":/IMG/img/application-exit.svg"))) self.settingsAction.setIcon(QtGui.QIcon(QtGui.QPixmap(":/IMG/img/preferences-other.png"))) self.refreshAction.setIcon(QtGui.QIcon(QtGui.QPixmap(":/IMG/img/refresh.png"))) self.menubar = QtGui.QMenuBar(mainWindow) self.menubar.setEnabled(True) self.menubar.setDefaultUp(False) mainWindow.setMenuBar(self.menubar) self.mainMenu = QtGui.QMenu(self.menubar) self.helpMenu = QtGui.QMenu(self.menubar) self.optionsMenu = QtGui.QMenu(self.menubar) self.mainMenu.addAction(self.refreshAction) self.mainMenu.addSeparator() self.mainMenu.addAction(self.logoutAction) self.mainMenu.addAction(self.exitAction) self.helpMenu.addAction(self.aboutAction) self.optionsMenu.addAction(self.settingsAction) self.menubar.addAction(self.mainMenu.menuAction()) self.menubar.addAction(self.optionsMenu.menuAction()) self.menubar.addAction(self.helpMenu.menuAction()) self.exitAction.triggered.connect(mainWindow.close) self.aboutAction.triggered.connect(mainWindow.showAbout) self.settingsAction.triggered.connect(mainWindow.showSettings) self.logoutAction.triggered.connect(mainWindow.logout) self.refreshAction.triggered.connect(mainWindow.refresh) self.pushButton_refresh = QtGui.QPushButton(self.widget) self.pushButton_new = QtGui.QPushButton(self.widget) self.pushButton_refresh.clicked.connect(mainWindow.refresh) self.pushButton_new.clicked.connect(mainWindow.postTweet) self.timelineLoaded.connect(self.moveToTop) self.tabBadgeChanged.connect(self.drawNotifyBadge) self.refreshAction.setShortcut(QtGui.QKeySequence("F5")) self.pushButton_refresh.setIcon(QtGui.QIcon(":/IMG/img/refresh.png")) self.pushButton_new.setIcon(QtGui.QIcon(":/IMG/img/new.png")) if self.isGlobalMenu(): self._setupToolBar() else: self._setupButtonWidget() self._setTabIcon(self.homeTab, QtGui.QPixmap(":/IMG/img/sina.png")) self._setTabIcon(self.mentionsTab, QtGui.QPixmap(":/IMG/img/mentions.png")) self._setTabIcon(self.commentsTab, QtGui.QPixmap(":/IMG/img/comments2.png")) self._setTabIcon(self.commentsMentionsTab, QtGui.QPixmap(":/IMG/img/mentions_comments.svg")) self.retranslateUi(mainWindow) def isGlobalMenu(self): if os.environ.get("TOOLBAR") == "1": return True elif os.environ.get("TOOLBAR") == "0": return False elif os.environ.get('DESKTOP_SESSION') in ["ubuntu", "ubuntu-2d"]: if not os.environ.get("UBUNTU_MENUPROXY"): return False elif os.environ.get("APPMENU_DISPLAY_BOTH"): return False else: return True elif os.environ.get("DESKTOP_SESSION") == "kde-plasma" and platform.linux_distribution()[0] == "Ubuntu": return True elif platform.system() == "Darwin": return True return False def _setupToolBar(self): self.toolBar = QtGui.QToolBar() self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) empty = QtGui.QWidget() empty.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) self.toolBar.addWidget(empty) self.toolBar.addAction(self.refreshAction) newAction = self.toolBar.addAction(QtGui.QIcon(":/IMG/img/new.png"), "New") newAction.triggered.connect(self.pushButton_new.clicked) self.addToolBar(self.toolBar) def _setupButtonWidget(self): self.buttonWidget = QtGui.QWidget(self) self.buttonLayout = QtGui.QHBoxLayout(self.buttonWidget) self.horizontalSpacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.buttonLayout.addSpacerItem(self.horizontalSpacer) self.buttonLayout.addWidget(self.pushButton_refresh) self.buttonLayout.addWidget(self.pushButton_new) def resizeEvent(self, event): # This is a hack!!! if self.isGlobalMenu(): return self.buttonWidget.resize(self.menubar.sizeHint().width(), self.menubar.sizeHint().height() + 12) self.buttonWidget.move(self.width() - self.buttonWidget.width(), self.menubar.geometry().topRight().y() - 5) def retranslateUi(self, frm_MainWindow): frm_MainWindow.setWindowTitle(self.tr("WeCase")) self.mainMenu.setTitle(self.tr("&WeCase")) self.helpMenu.setTitle(self.tr("&Help")) self.optionsMenu.setTitle(self.tr("&Options")) self.aboutAction.setText(self.tr("&About...")) self.refreshAction.setText(self.tr("Refresh")) self.logoutAction.setText(self.tr("&Log out")) self.exitAction.setText(self.tr("&Exit")) self.settingsAction.setText(self.tr("&Settings")) def _setupSysTray(self): self.systray = QtGui.QSystemTrayIcon() self.systray.activated.connect(self.clickedSystray) self.systray.setToolTip("WeCase") self.systray.setIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) self.systray.show() self.visibleAction = QtGui.QAction(self) self.visibleAction.setText(self.tr("&Hide")) self.visibleAction.triggered.connect(self._switchVisibility) self.sysMenu = QtGui.QMenu(self) self.sysMenu.addAction(self.visibleAction) self.sysMenu.addAction(self.logoutAction) self.sysMenu.addAction(self.exitAction) self.systray.setContextMenu(self.sysMenu) def clickedSystray(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self._switchVisibility() elif reason == QtGui.QSystemTrayIcon.Context: pass def _switchVisibility(self): if self.isVisible(): self.hide() self.visibleAction.setText(self.tr("&Show")) else: self.show() self.visibleAction.setText(self.tr("&Hide")) def _setTabIcon(self, tab, icon): pixmap = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(pixmap) self._iconPixmap[icon.cacheKey()] = pixmap self.tabWidget.setTabIcon(self.tabWidget.indexOf(tab), icon) self.tabWidget.setIconSize(QtCore.QSize(24, 24)) def _prepareTimeline(self, timeline): try: timeline.setUsersBlacklist(self.usersBlacklist) timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) timeline.setWordWarKeywords(self.wordWarKeywords) timeline.setBlockWordwars(self.blockWordwars) except AttributeError: pass timeline.load() def closeTab(self, index): widget = self.tabWidget.widget(index) self.tabWidget.removeTab(index) widget.deleteLater() def init_account(self): self.uid() def loadConfig(self): self.config = WConfigParser(path.myself_path + "WMetaConfig", path.config_path, "main") self.notify_interval = self.config.notify_interval self.notify_timeout = self.config.notify_timeout self.usersBlacklist = self.config.usersBlacklist self.tweetKeywordsBlacklist = self.config.tweetsKeywordsBlacklist self.remindMentions = self.config.remind_mentions self.remindComments = self.config.remind_comments self.wordWarKeywords = self.config.wordWarKeywords self.blockWordwars = self.config.blockWordwars self.maxRetweets = self.config.maxRetweets self.maxTweetsPerUser = self.config.maxTweetsPerUser self.mainWindow_geometry = self.config.mainwindow_geometry def applyConfig(self): try: self.timer.stop() except AttributeError: pass self.timer = WTimer(self.show_notify, self.notify_interval) self.timer.start() self.notify.timeout = self.notify_timeout setGeometry(self, self.mainWindow_geometry) def setupModels(self): self._all_timeline = TweetCommonModel(self.client.statuses.home_timeline, self) self.all_timeline = TweetFilterModel(self._all_timeline) self.all_timeline.setModel(self._all_timeline) self._prepareTimeline(self.all_timeline) # extra rules self.all_timeline.setMaxRetweets(self.maxRetweets) self.all_timeline.setMaxTweetsPerUser(self.maxTweetsPerUser) self.homeView.setModel(self.all_timeline) self._mentions = TweetCommonModel(self.client.statuses.mentions, self) self.mentions = TweetFilterModel(self._mentions) self.mentions.setModel(self._mentions) self._prepareTimeline(self.mentions) self.mentionsView.setModel(self.mentions) self._comment_to_me = TweetCommentModel(self.client.comments.to_me, self) self.comment_to_me = TweetFilterModel(self._comment_to_me) self.comment_to_me.setModel(self._comment_to_me) self._prepareTimeline(self.comment_to_me) self.commentsView.setModel(self.comment_to_me) self._comment_mentions = TweetCommentModel(self.client.comments.mentions, self) self.comment_mentions = TweetFilterModel(self._comment_mentions) self.comment_mentions.setModel(self._comment_mentions) self._prepareTimeline(self.comment_mentions) self.commentsMentionsView.setModel(self.comment_mentions) @async def reset_remind(self): typ = "" if self.currentTweetView() == self.homeView: self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.mentionsView: typ = "mention_status" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsView: typ = "cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsMentionsView: typ = "mention_cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) if typ: self.client.remind.set_count.post(type=typ) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" reminds = self.client.remind.unread_count.get(uid=uid) return reminds def uid(self): """How can I get my uid? here it is""" if not self.info.get("uid"): self.info["uid"] = self.client.account.get_uid.get().uid return self.info["uid"] def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid()) msg = self.tr("You have:") + "\n" reminds_count = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.homeTab), reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), reminds['mention_status']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), 0) if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), reminds['cmt']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), 0) if reminds["mention_cmt"] and self.remindMentions: msg += self.tr("%d unread @ME comment(s)") % reminds["mention_cmt"] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsMentionsTab), reminds["mention_cmt"]) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsMentionsTab), 0) if reminds_count and reminds_count != self._last_reminds_count: self.notify.showMessage(self.tr("WeCase"), msg) self._last_reminds_count = reminds_count def drawNotifyBadge(self, index, count): tabIcon = self.tabWidget.tabIcon(index) _tabPixmap = self._iconPixmap[tabIcon.cacheKey()] tabPixmap = _tabPixmap.transformed(QtGui.QTransform().rotate(-90)) icon = NotifyBadgeDrawer().draw(tabPixmap, str(count)) icon = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(icon) self._iconPixmap[icon.cacheKey()] = _tabPixmap self.tabWidget.setTabIcon(index, icon) def moveToTop(self): self.currentTweetView().moveToTop() def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow(allow_auto_login=False) wecase_login.exec_() def postTweet(self): self.wecase_new = NewpostWindow() self.wecase_new.userClicked.connect(self.userClicked) self.wecase_new.tagClicked.connect(self.tagClicked) self.wecase_new.show() def refresh(self): tweetView = self.currentTweetView() tweetView.model().timelineLoaded.connect(self.moveToTop) tweetView.refresh() self.reset_remind() def currentTweetView(self): # The most tricky part of MainWindow. return self.tabWidget.currentWidget().layout().itemAt(0).widget() def saveConfig(self): self.config.mainwindow_geometry = getGeometry(self) self.config.save() def closeEvent(self, event): self.systray.hide() self.hide() self.saveConfig() self.timer.stop(True) # Reset uid when the thread exited. self.info["uid"] = None logging.info("Die")
class WeCaseWindow(QtGui.QMainWindow, Ui_frm_MainWindow): client = None uid = None imageLoaded = QtCore.pyqtSignal(str) tabTextChanged = QtCore.pyqtSignal(int, str) def __init__(self, parent=None): super(WeCaseWindow, self).__init__(parent) self.setupUi(self) self.tweetViews = [self.homeView, self.mentionsView, self.commentsView, self.myView] self.client = const.client self.loadConfig() self.setupModels() self.init_account() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] def init_account(self): self.get_uid() def loadConfig(self): self.config = WeCaseConfig(const.config_path) self.notify_interval = self.config.notify_interval self.notify_timeout = self.config.notify_timeout self.usersBlacklist = self.config.usersBlacklist self.tweetKeywordsBlacklist = self.config.tweetsKeywordsBlacklist self.remindMentions = self.config.remind_mentions self.remindComments = self.config.remind_comments def applyConfig(self): try: self.timer.stop_event.set() except AttributeError: pass self.timer = WTimer(self.notify_interval, self.show_notify) self.timer.start() self.notify.timeout = self.notify_timeout def setupModels(self): self.all_timeline = TweetCommonModel(self.client.statuses.home_timeline, self) self.all_timeline.setUsersBlacklist(self.usersBlacklist) self.all_timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.all_timeline.load() self.homeView.setModel(self.all_timeline) self.mentions = TweetCommonModel(self.client.statuses.mentions, self) self.mentions.setUsersBlacklist(self.usersBlacklist) self.mentions.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.mentions.load() self.mentionsView.setModel(self.mentions) self.comment_to_me = TweetCommentModel(self.client.comments.to_me, self) self.comment_to_me.setUsersBlacklist(self.usersBlacklist) self.comment_to_me.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.comment_to_me.load() self.commentsView.setModel(self.comment_to_me) self.my_timeline = TweetCommonModel(self.client.statuses.user_timeline, self) self.my_timeline.setUsersBlacklist(self.usersBlacklist) self.my_timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) self.my_timeline.load() self.myView.setModel(self.my_timeline) def reset_remind(self): if self.tabWidget.currentIndex() == 0: self.tabWidget.setTabText(0, self.tr("Weibo")) elif self.tabWidget.currentIndex() == 1: self.client.remind.set_count.post(type="mention_status") self.tabWidget.setTabText(1, self.tr("@Me")) elif self.tabWidget.currentIndex() == 2: self.client.remind.set_count.post(type="cmt") self.tabWidget.setTabText(2, self.tr("Comments")) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" while 1: try: reminds = self.client.remind.unread_count.get(uid=uid) break except http.client.BadStatusLine: sleep(0.2) continue return reminds def get_uid(self): """How can I get my uid? here it is""" try: self.uid = self.client.account.get_uid.get().uid except AttributeError: return None def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid) msg = self.tr("You have:") + "\n" num_msg = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabTextChanged.emit(0, self.tr("Weibo(%d)") % reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabTextChanged.emit(1, self.tr("@Me(%d)") % reminds['mention_status']) num_msg += 1 if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabTextChanged.emit(2, self.tr("Comments(%d)") % reminds['cmt']) num_msg += 1 if num_msg: self.notify.showMessage(self.tr("WeCase"), msg) def setTabText(self, index, string): self.tabWidget.setTabText(index, string) def moveToTop(self): self.get_current_tweetView().moveToTop() def setLoaded(self): pass def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow(allow_auto_login=False) wecase_login.exec_() def postTweet(self): wecase_new = NewpostWindow() wecase_new.exec_() def refresh(self): tweetView = self.get_current_tweetView() tweetView.model().timelineLoaded.connect(self.moveToTop) tweetView.refresh() self.reset_remind() def get_current_tweetView(self): tweetViews = {0: self.homeView, 1: self.mentionsView, 2: self.commentsView, 3: self.myView} return tweetViews[self.tabWidget.currentIndex()] def closeEvent(self, event): self.timer.stop_event.set()
class application : def __init__(self): #init threading gobject.threads_init() #keep track of the window size self.window_height=0 self.window_width=0 self.window_is_hidden = False self.has_status_icon = False #keep track of the initial conversation id so that conversations don't colide self.conversation_id="0" #keep track of the filters self.filters ={'users':[],'strings':[]} self.options={'run_as_tray_app':False,'context_backwards':False,'no_avatars':False,'notifications':True,'notify_replies':False} #keep track of the direct_message requests self.last_direct_message_time=0 #something something direct message self.is_direct_message_mode=False self.direct_message_to=None self.waiting_requests=0 self.is_first_dents = True #keep track of the respond to id self.respond_to_id=0 self.pre_group_page=None self.pre_user_page=None #keep track of the last time statuses where pulled self.last_get_statuses = 0 #what are the assets? asset_dir = 'assets' heybuddy_dir = os.path.dirname( os.path.realpath( __file__ ) ) self.readme_file = os.path.join(heybuddy_dir,'README.txt') self.standard_icon_path = os.path.join(heybuddy_dir,asset_dir,'icon.png') self.direct_icon_path = os.path.join(heybuddy_dir,asset_dir,'direct_icon.png') self.networking_icon_path = os.path.join(heybuddy_dir,asset_dir,'icon1.png') self.throbber_icon_path = os.path.join(heybuddy_dir,asset_dir,'throbber.gif') self.default_icon_path = self.standard_icon_path self.conf = Configuration(app_name) #has the account info been authenticated? self.credentials_verified = self.conf.get_bool('access', 'credentials_verified') self.xmlprocessor = XMLProcessor() #create a regex to replace parts of a dent self.regex_tag = re.compile("(^| )#([\w-]+)", re.UNICODE) self.regex_group = re.compile("(^| )!([\w-]+)") self.regex_user=re.compile("(^|[^A-z0-9])@(\w+)") self.regex_url=re.compile("(http[s]?://.*?)(\.$|\. |\s|$)",re.IGNORECASE) #get the initial dents self.initial_dents = self.conf.get('settings','initial_dents',default='20' ) self.dent_limit = int(self.initial_dents)*2 #get the pull time self.pull_time = self.conf.get('settings','pull_time',default='60') self.pull_time_changed_bool = False self.pull_time_mentions = False #build the gui self.build_gui() #where is the certs file? ca_certs_files = [ "/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/certs/ca-bundle.crt", ] #what if there isn't a cert_file cert_file=None #determine the certs_file for f in ca_certs_files: if os.path.exists(f): cert_file=f break #create the communicator self.comm = Communicator(app_name, cert_file) self.comm.connect('statusesXML',self.process_statusesXML,self.dentspage) self.comm.connect('mentionsXML',self.process_statusesXML,self.mentionspage) self.comm.connect('favoritesXML', self.process_statusesXML,self.favoritespage) self.comm.connect('group-statusesXML',self.process_statusesXML,self.grouppage) self.comm.connect('user-statusesXML',self.process_statusesXML,self.userpage) self.comm.connect('direct_messagesXML',self.process_statusesXML,self.directspage,True) self.comm.connect('conversationXML',self.process_conversationXML) self.comm.connect('userXML',self.process_userXML) self.comm.connect('groupXML',self.process_groupXML) self.comm.connect('new-statusXML',self.process_new_statusXML) self.comm.connect('redent-statusXML',self.process_new_statusXML) self.comm.connect('user_is_friendXML',self.process_user_is_friendXML) self.comm.connect('user_is_memberXML',self.process_user_is_memberXML) self.comm.connect('friendshipXML',self.process_friendshipXML) self.comm.connect('exception-caught',self.process_communication_exception) self.comm.connect('widget-image',self.process_widget_image) self.comm.connect('direct-messageXML',self.process_new_directXML) self.comm.connect('verify_credentialsXML',self.process_verifycredentialsXML) self.comm.connect('configXML',self.process_configXML) #create an image cacher thingy self.imagecache = ImageCache() self.imagecache.set_disabled( self.conf.get_bool_option('no_avatars') ) self.imagecache.connect('get-widget-image', self.get_widget_image) #Create notify-er if has pynotify if has_pynotify: self.notify = Notify() #align the window self.align_window() # do we need to create the status icon if self.conf.get_bool_option('run_as_tray_app'): self.create_status_icon() def build_gui(self): #build the GUI self.mainwindow=MainWindow.MainWindow(app_name,version,branch) try: self.mainwindow.set_icon_from_file(self.default_icon_path) except: pass self.mainwindow.set_textlimit( self.conf.textlimit() ) self.mainwindow.set_ctrl_enter( self.conf.get_bool_option('ctrl_enter') ) self.mainwindow.connect('quit', self.quit_triggered ) self.mainwindow.connect('window-to-tray', self.window_to_tray ) self.mainwindow.connect('update-status',self.update_status) self.mainwindow.connect('get-conversation',self.get_conversation) self.mainwindow.connect('show-user',self.get_user_info) self.mainwindow.connect('show-group',self.get_group_info) self.mainwindow.connect('notebook-page-change',self.page_change) self.mainwindow.connect('follow-user',self.follow_user) self.mainwindow.connect('join-group',self.join_group) self.mainwindow.connect('clear-respond-to-id',self.clear_respond_to_id) #keep track of the window size self.mainwindow.connect('size-allocate', self.window_size_allocate) #self.mainwindow.connect('window-state-event', self.mainwindow_state_event) self.mainwindow.connect('delete-event', self.mainwindow_delete_event) # local function to create a closeable tab label for closeable tabs def closeable_tab_label(caption, tab): tablabel = gtk.HBox(False,2) tablabel.pack_start(gtk.Label(caption),False,False,0) closebutton = gtk.Button() closeicon = gtk.Image() closeicon.set_from_stock(gtk.STOCK_CLOSE,gtk.ICON_SIZE_MENU) closebutton.set_image(closeicon) closebutton.set_relief(gtk.RELIEF_NONE) tinybutton_style = gtk.RcStyle() tinybutton_style.xthickness = 0 tinybutton_style.ythickness = 0 closebutton.modify_style(tinybutton_style) if tab != None: # if this isn't a mock-add closebutton.connect('clicked',tab.close) #don't show a tooltip on maemo if not has_hildon: closebutton.set_tooltip_text(_("Close")) tablabel.pack_start(closebutton,False,False,0) tablabel.show_all() return tablabel # do a mock add of dentspage, with a close label, so as to determine height needed for uncloseable tabs' labels, then break it all down again # this is ridiculously hacky, but it works, and doesn't leave anything behind self.dentspage = ScrollPage() self.mock_label = closeable_tab_label(_("Dents"),None) self.mainwindow.notebook.append_page(self.dentspage,self.mock_label) self.mainwindow.show_all() # we have to do this so the tab gets actualised, and thus gets a height min_tab_height = self.mock_label.allocation.height self.mainwindow.hide_all() self.mainwindow.notebook.remove_page(-1) del self.mock_label # local function to create a label the same height as the closeable tabs' labels def uncloseable_tab_label(caption): tablabel = gtk.Label(caption) tablabel.set_size_request(-1,min_tab_height) tablabel.show() return tablabel # create and add all of the pages self.dentspage = ScrollPage() self.mainwindow.notebook.append_page(self.dentspage,uncloseable_tab_label(_("Dents") ) ) self.mentionspage = ScrollPage() self.mainwindow.notebook.append_page(self.mentionspage,uncloseable_tab_label(_("Mentions")) ) self.favoritespage = ScrollPage() self.mainwindow.notebook.append_page(self.favoritespage,uncloseable_tab_label(_("Favorites")) ) self.directspage = ScrollPage() self.mainwindow.notebook.append_page(self.directspage,uncloseable_tab_label(_("Directs")) ) #make the conversation page self.contextpage=ContextPage() self.contextpage.connect('context-page-hide',self.hide_contextpage) #add the contextpage context_label = closeable_tab_label(_("Context"), self.contextpage) self.mainwindow.notebook.append_page(self.contextpage, context_label) #create a user page self.userpage=UserPage() self.userpage.connect('user-page-hide',self.hide_userpage) self.userpage.connect('follow-user',self.follow_user) self.userpage.connect('direct-clicked',self.direct_clicked) self.userpage.connect('open-link',self.open_link) self.userpage.connect('block-create',self.block_create) self.userpage.connect('block-destroy',self.block_destroy) #add the userpage user_label = closeable_tab_label(_("User"),self.userpage ) self.mainwindow.notebook.append_page(self.userpage, user_label) #create a Group page self.grouppage=GroupPage() self.grouppage.connect('group-page-hide',self.hide_grouppage) self.grouppage.connect('join-group',self.join_group) self.grouppage.connect('open-link',self.open_link) #add the Grouppage group_label = closeable_tab_label(_("Group"),self.grouppage ) self.mainwindow.notebook.append_page(self.grouppage, group_label) #create and add the account page self.settingspage = SettingsPage(has_hildon,has_pynotify) self.settingspage.set_initial_dents( self.initial_dents ) self.settingspage.set_pull_time(self.pull_time) #update the configuration of the settings self.settingspage.connect('update-account',self.update_account) self.options['ctrl_enter'] = self.conf.get_bool_option('ctrl_enter') self.settingspage.set_ctrl_enter( self.options['ctrl_enter'] ) self.options['run_as_tray_app'] = self.conf.get_bool_option('run_as_tray_app') self.settingspage.set_run_as_tray_app( self.options['run_as_tray_app'] ) self.options['context_backwards'] = self.conf.get_bool_option('context_backwards') self.settingspage.set_context_backwards( self.options['context_backwards'] ) self.options['no_avatar']= self.conf.get_bool_option('no_avatars') self.settingspage.set_no_avatars( self.options['no_avatar'] ) self.options['api_retweet'] = self.conf.get_bool_option('api_retweet') self.settingspage.set_api_retweet( self.options['api_retweet'] ) self.options['notifications']= self.conf.get_bool_option('notifications') self.settingspage.set_notifications( self.options['notifications'] ) self.options['notify_replies']= self.conf.get_bool_option('notify_replies') self.settingspage.set_notify_replies( self.options['notify_replies'] ) link_color = self.conf.get('settings','link_color',default='blue') self.settingspage.set_link_color( link_color ) self.theme_link_color(link_color) #connect the setting signals self.settingspage.connect('option-run-as-tray-app', self.option_changed, 'run_as_tray_app') self.settingspage.connect('option-ctrl-enter', self.option_changed, 'ctrl_enter') self.settingspage.connect('option-context-backwards',self.option_changed, 'context_backwards') self.settingspage.connect('option-no-avatars',self.option_changed, 'no_avatars') self.settingspage.connect('option-api-retweet', self.option_changed, 'api_retweet') self.settingspage.connect('option-notifications',self.option_changed, 'notifications') self.settingspage.connect('option-notify-replies',self.option_changed, 'notify_replies') self.settingspage.connect('initial-dents',self.set_initial_dents) self.settingspage.connect('pull-time',self.set_pull_time) self.settingspage.connect('link-color',self.set_link_color) self.settingspage.connect('add-string-filter', self.add_string_filter ) self.settingspage.connect('remove-string-filter', self.remove_string_filter ) self.settingspage.connect('add-user-filter', self.add_user_filter ) self.settingspage.connect('remove-user-filter', self.remove_user_filter ) #add the settings to the mainwindow self.mainwindow.add_notebook_page(self.settingspage,uncloseable_tab_label(_("Settings") ) ) #create and add the about page about = About(version,branch,self.standard_icon_path,self.readme_file) about.connect('open-link',self.open_link) self.mainwindow.add_notebook_page( about, uncloseable_tab_label(_("About") ) ) self.mainwindow.show_some() #hide some stuff self.grouppage.hide_all() self.userpage.hide_all() self.contextpage.hide_all() def align_window(self): #try to set the mainwindows size based on conf info try: w = int( self.conf.get('window_info','width') ) h = int( self.conf.get('window_info','height') ) self.mainwindow.resize(w,h) except: pass try: x = int( self.conf.get('window_info','x') ) y = int( self.conf.get('window_info','y') ) self.mainwindow.move(x,y) except: pass #get the filters try: #read the filters filters = self.conf.get('settings','filters',True) #the filters should be an array if len(filters): #self.filters = filters self.filters['users'] = filters['users'] self.filters['strings'] = filters['strings'] #set the filters self.settingspage.set_string_filters( self.filters['strings'] ) self.settingspage.set_user_filters( self.filters['users'] ) except: pass def create_status_icon(self): if not self.has_status_icon: #create the statusicon self.statusicon = StatusIcon() self.statusicon.connect('activate', self.status_clicked ) self.statusicon.connect('quit-selected',self.quit_app) self.statusicon.set_icon( self.standard_icon_path ) self.statusicon.set_property("visible",True) self.has_status_icon=True def destroy_status_icon(self): self.statusicon.set_property("visible",False) self.has_status_icon=False def update_account(self, widget, n, p, s): #check if these are valid self.mainwindow.set_message(_("Authenticating account...")) self.increment_requests() self.comm.verify_credentials(n, p, s) def increment_requests(self): self.waiting_requests+=1 if self.waiting_requests==1: try: self.mainwindow.set_icon_from_file(self.networking_icon_path) except: pass try: self.mainwindow.set_throbber(self.throbber_icon_path) except: pass if self.has_status_icon: self.statusicon.set_icon( self.networking_icon_path) def decrement_requests(self): self.waiting_requests-=1 if self.waiting_requests==0: try: self.mainwindow.set_icon_from_file(self.default_icon_path) except: pass try: self.mainwindow.set_throbber(self.default_icon_path) except: pass if self.has_status_icon: self.statusicon.set_icon( self.default_icon_path ) if self.waiting_requests<0: self.waiting_requests=0 def valid_account_info(self, n, p, s): self.conf.name( n ) self.conf.password( p ) self.conf.service( s ) self.conf.save() #update the comm self.comm.set_name_and_password( n,p ) self.comm.set_service( s ) def get_statuses(self,count="20"): if self.credentials_verified: #do some time handling for the good doctor now = time.time() if now - self.last_get_statuses > 2*self.pull_time: count = self.initial_dents self.last_get_statuses = now self.increment_requests() self.comm.get_statuses(count=count, since=highest_id['dent_previous']) #clean up the garbage gc.collect() def get_mentions(self,count="20"): if self.credentials_verified: self.increment_requests() self.comm.get_mentions(count=count,since=highest_id['mention_previous']) def get_favorites(self): if self.credentials_verified: self.increment_requests() self.comm.get_favorites() def get_direct_messages(self): if self.credentials_verified: now = time.time() #NOTE this could be changed to 3 minutes just setting it #this way for now #has it been 3 times the pull time? if now - (3 * int(self.pull_time) ) > self.last_direct_message_time: self.increment_requests() self.comm.get_direct_messages(highest_id['direct_previous']) self.last_direct_message_time=now def run(self, enable_logging=False): self.logging = enable_logging #start the communicator self.comm.start() self.main_loop = gobject.MainLoop() #we have to temporarily show the various pages or nothing works ''' why the f**k do I need to do this? ''' self.mainwindow.set_notebook_page(DIRECT) self.mainwindow.set_notebook_page(MENTION) self.mainwindow.set_notebook_page(FAVORITE) self.mainwindow.set_notebook_page(DENT) #send the service to the settings page self.settingspage.set_service(self.conf.service() ) #did the conf read a name and password? if( self.conf.name() !="" and self.conf.password()!=""): if self.credentials_verified: self.comm.set_name_and_password( self.conf.name(),self.conf.password() ) self.comm.set_service( self.conf.service() ) #fill the Account tab name/pw fields to show the user that they're logged in self.settingspage.set_name(self.conf.name()) self.settingspage.set_password(self.conf.password()) #add a function to the main loop gobject.timeout_add(int(self.pull_time)*1000, self.update_statuses ) gobject.timeout_add(int(self.pull_time)*1500, self.update_mentions ) #add a timout to get dents gobject.timeout_add(500,self.get_statuses,self.initial_dents ) gobject.timeout_add(600,self.get_mentions,self.initial_dents ) #gobject.timeout_add(1000,self.get_direct_messages ) else: #set the focus on the account page; the last page self.mainwindow.set_notebook_page(ACCOUNT) self.mainwindow.run() self.main_loop.run() #if we ever get here, we should quit def update_statuses(self): self.get_statuses() if(self.pull_time_changed_bool): self.pull_time_changed_bool= False gobject.timeout_add(int(self.pull_time)*1000, self.update_statuses) return False return True def update_mentions(self): self.get_mentions() if(self.pull_time_mentions): self.pull_time_mentions=False gobject.timeout_add(int(self.pull_time)*1500, self.update_mentions) return False return True def update_direct_messages(self): self.get_direct_messages() return True def update_status(self,widget,text): self.increment_requests() #remove newlines from text text=text.replace("\n","") #is this direct message mode? if self.is_direct_message_mode: self.comm.send_direct_message(text,self.direct_message_to) self.set_is_direct_message_mode(False) else: self.comm.send_update_status(text,self.respond_to_id) self.clear_respond_to_id() def quit_app(self,widget=None): #quit the communicator loop self.comm.quit() #quit the main loop self.main_loop.quit() def get_widget_image(self,imagecache,image): self.comm.get_widget_image(image) def get_conversation(self,id,conversation_id): if self.credentials_verified: self.increment_requests() self.comm.get_conversation(id,conversation_id) def parse_profile(self, profile=None, name=None ): #is this a remote user? remote_user = True service = '' #did we get a name? if profile!=None: bits = profile.rsplit("/") service = bits[2] if name==None: name = bits[3] #if there is no name, use the first subdomain as a name if name==None: dot_split = service.split(".") name = dot_split[0] if service==self.conf.service(): remote_user = False else: remote_user = False return {'service':service, 'remote':remote_user,'name':name} def get_user_info(self, profile=None, name=None): #parse the info result = self.parse_profile( profile, name ) #is this a remote user? remote_user = result['remote'] name = result['name'] service = result['service'] #is this not a remote user? if not remote_user: if self.credentials_verified: self.increment_requests() self.comm.get_user_info(name) self.increment_requests() self.comm.get_user_statuses(name) return self.increment_requests() self.comm.get_remote_user_info(service,name) self.increment_requests() self.comm.get_remote_user_statuses(service,name) def get_group_info(self,name): if self.credentials_verified: self.increment_requests() self.comm.get_group_info(name) def follow_user(self,widget,name,bool): if self.credentials_verified: if bool: self.comm.friendship_create(name) else: self.comm.friendship_destroy(name) def join_group(self,widget,name,bool): if self.credentials_verified: if bool: self.comm.group_join(name) else: self.comm.group_leave(name) def process_friendshipXML(self,widget,text): pass def page_change(self,widget,old_id,new_id): if new_id==MainWindow.DIRECT: self.get_direct_messages() elif new_id==MainWindow.FAVORITE: self.get_favorites() else: if self.is_direct_message_mode: self.set_is_direct_message_mode(False) #should we clear any warning message? self.mainwindow.clear_message() def process_userXML(self,comm,text): self.decrement_requests() data = self.xmlprocessor.get_user_info(text) if data['profile_image_url']!=None: self.imagecache.add_image_to_widget(data['profile_image_url'],self.userpage) self.userpage.set_user_data(data) def process_groupXML(self,comm,text): self.decrement_requests() data = self.xmlprocessor.get_group_info(text) if data['stream_logo']!=None: self.imagecache.add_image_to_widget(data['stream_logo'],self.grouppage) '''#is this user a member of this group self.increment_requests() self.comm.get_user_is_member(data['id'])''' self.increment_requests() self.comm.get_group_statuses(data['id']) self.grouppage.set_group_data(data) def process_user_is_friendXML(self,comm,text): self.decrement_requests() is_friend = self.xmlprocessor.get_user_is_friend(text) self.mainwindow.display_user_is_friend( is_friend ) def process_user_is_memberXML(self,comm,text): self.decrement_requests() is_member = self.xmlprocessor.get_user_is_member(text) self.mainwindow.display_user_is_member( is_member ) def process_new_directXML(self,comm,text): #a update status was sent self.decrement_requests() #clear the textview thing self.mainwindow.emit_update_textview_responsed() def process_new_statusXML(self,comm,text): #a update status was sent self.decrement_requests() #clear the textview thing self.mainwindow.emit_update_textview_responsed() #there is one status and it is the DOM status = self.xmlprocessor.get_dom(text) data = self.xmlprocessor.get_dent_data(status) data['markup'] = self.markup_dent_text(data['text']) #add the dent dent = self.connect_dent(data,self.dentspage) def process_verifycredentialsXML(self, object, text, data): #actually, if we are here, the authorization worked! self.conf.set('access', 'credentials_verified', True) self.credentials_verified = True self.mainwindow.message_label.hide() (n, p, s) = data self.valid_account_info(n, p, s) #get the config self.comm.get_config() #switch to the dents page self.mainwindow.set_notebook_page(DENT) self.get_statuses() self.get_mentions() def process_conversationXML(self,object,text,conversation_id): self.decrement_requests() #is this the current conversation Id? if not, then do nothing #convert to int because there is a problem with string comparison '''is one of the strings unicode?''' if int(self.conversation_id)==int(conversation_id): #get the status status = self.xmlprocessor.get_dom(text) data = self.xmlprocessor.get_dent_data(status) data['markup']=self.markup_dent_text(data['text']) #since this is a conversation, we can get rid of the in_reply_to_screen_name data['in_reply_to_screen_name']=None #tell the mainWindow to add the dent dent = self.connect_dent(data,self.contextpage,True, self.options['context_backwards'] ) if data['in_reply_to_id']!=None: #recursively get in_reply_to_ids self.get_conversation(id=data['in_reply_to_id'],conversation_id=conversation_id) def process_configXML(self, object, text): self.decrement_requests() server = self.xmlprocessor.get_server_config(text) print server self.conf.textlimit( server['textlimit'] ) self.conf.save() self.mainwindow.set_textlimit( server['textlimit'] ) def connect_dent(self,data,target_page,is_conv=False,conv_backwards=False,is_direct_dent=False): #make the dent dent = Dent(data,is_direct=is_direct_dent) if target_page.dentScroller.add_dent( dent, is_conv, conv_backwards ): dent.connect('group-clicked', self.view_group) dent.connect('reply-clicked', self.reply_clicked) dent.connect('direct-clicked', self.direct_clicked) dent.connect('view-conversation-clicked', self.view_conversation) dent.connect('user-clicked', self.view_user_name) dent.connect('profile-clicked', self.view_user_profile) dent.connect('id-clicked', self.view_id) dent.connect('text-label-clicked',self.dent_text_clicked) dent.connect('redent-clicked',self.redent_clicked) dent.connect('favorite-clicked',self.favorite_clicked) dent.connect('unfavorite-clicked',self.unfavorite_clicked) dent.connect('open-link',self.open_link) if target_page!=self.userpage: #get the image for this dent self.imagecache.add_image_to_widget(data['profile_image_url'],dent) return True else: dent.destroy() del dent return False def reply_clicked(self,dent,name): #set the text buffer self.mainwindow.update_textbuffer.set_text("@%s " % (name) ) self.mainwindow.update_textview.grab_focus() #set the respond_to_id self.respond_to_id=dent.id def favorite_clicked(self,dent): id=dent.id self.comm.favorite(id) def unfavorite_clicked(self,dent): id=dent.id self.comm.unfavorite(id) def direct_clicked(self,widget,name): self.direct_message_to = name if type(widget).__name__=="Dent": self.respond_to_id=widget.id else: self.respond_to_id=None self.set_is_direct_message_mode(True,name) #we should be on the directs page self.mainwindow.set_notebook_page(DIRECT) #set the text buffer self.mainwindow.update_textbuffer.set_text("") self.mainwindow.update_textview.grab_focus() def view_conversation(self,dent,id): self.conversation_id=id self.pre_context_page=self.mainwindow.notebook_current_page self.contextpage.dentScroller.clear() self.contextpage.show_all() #get conversation starting with id self.get_conversation(id,id) self.mainwindow.notebook.set_current_page(CONTEXT) def view_user_profile(self, widget, profile_url, screen_name): self.get_user_info(profile=profile_url, name=screen_name) #self.get_user_info(screen_name) self.pre_user_page=self.mainwindow.notebook_current_page #make the user page checkbox insensitive self.userpage.disable() #show the page self.userpage.show_all() #rehide its collapsed widgetbox, that doesn't need to be visible yet self.userpage.widgetbox_collapsed.hide() #clear the userpage stuff self.userpage.clear() #change to the user page self.mainwindow.set_notebook_page(USER) def view_id(self, widget, id): url = 'http://%s/notice/%s' % (self.conf.service(), id) self.open_link(None, url) def view_user_name(self, widget, screen_name): #TODO: merge this function with view_user_profile self.get_user_info(name=screen_name) #self.get_user_info(screen_name) self.pre_user_page=self.mainwindow.notebook_current_page #make the user page checkbox insensitive self.userpage.disable() #show the page self.userpage.show_all() #rehide its collapsed widgetbox, that doesn't need to be visible yet self.userpage.widgetbox_collapsed.hide() #clear the userpage stuff self.userpage.clear() #change to the user page self.mainwindow.set_notebook_page(USER) #does this function even get called? get rid of it def get_dent_time(self,text): #print text pass def markup_dent_text(self,text,is_notification=False): #process the text to markup #xmlencode the string text = self.xmlprocessor.xmlentities(text) #regex find the highlights markup = self.regex_tag.sub(r'\1#<b>\2</b>',text) #regex find users if has_hildon or links_unavailable or is_notification: markup = self.regex_group.sub(r'\1!<b>\2</b>',markup) markup = self.regex_user.sub(r'\1@<b>\2</b>',markup) else: #find urls markup = self.regex_url.sub(r'<a href="\1">\1</a>\2',markup) markup = self.regex_user.sub(r'\1@<a href="@\2">\2</a>',markup) markup = self.regex_group.sub(r'\1!<a href="!\2">\2</a>',markup) return markup def process_statusesXML(self,object,text,target_page,is_direct=False): #based on the target, what is the counting thingy? count_ref=None if target_page==self.dentspage: count_ref = "dent" elif target_page==self.mentionspage: count_ref = "mention" elif target_page==self.directspage: count_ref = "direct" self.decrement_requests() #set the "previous" count ref, do this now and get data twice if count_ref!=None: highest_id[count_ref+"_previous"] = highest_id[count_ref] #get a list of the statuses statuses = self.xmlprocessor.get_statuses(text,is_direct) #if there aren't any statuses, return if len(statuses)==0: return #reverse the statuses list statuses.reverse() dent_count=0 reply_count=0 #what is the highest id of the target index? for status in statuses: filtered_status = False data = self.xmlprocessor.get_dent_data(status) if target_page==self.dentspage: #we should check for filtration filtered = self.check_filtered( data ) filtered_status=filtered[0] if not filtered_status: #get the markup data['markup'] = self.markup_dent_text(data['text']) #did this dent connect if not self.connect_dent(data,target_page,is_direct_dent=is_direct): continue #if the target_page = 0 and not first_dents and not is_conf if target_page==self.dentspage and not self.is_first_dents: if "@"+self.conf.name() in data['markup']: dent=self.connect_dent(data, self.mentionspage ) reply_count+=1 if self.options['notify_replies'] and has_pynotify: user = data['screen_name'] #the message shouldn't be marked up if the server doesn't understand markup if notifier_reads_markup: message = self.markup_dent_text(data['text'],True) else: message = data['text'] avatar = self.imagecache.get_image_path(data['profile_image_url']) self.notify.notify_reply(user,message,avatar) else: dent_count+=1 else: self.log("filter #%s %s" %(data['status_id'], filtered[1] ) ) #keep track of the last status_id if count_ref!=None and data!=None: highest_id[count_ref]=data['status_id'] self.is_first_dents=False #get the related images self.imagecache.get_images() #do we notify? if (dent_count!=0 or reply_count!=0) and has_pynotify and target_page==self.dentspage: if self.options['notifications']: if not self.options['notify_replies']: self.notify.notify_updates_replies(dent_count,reply_count,self.standard_icon_path) else: if dent_count!=0: self.notify.notify_updates(dent_count,self.standard_icon_path) #prune off the extra dents target_page.dentScroller.prune(self.dent_limit) def process_widget_image(self,comm,data,name): self.imagecache.widget_image_add(data,name) def process_communication_exception(self,communicator,code,data,signal=None): if self.logging: self.log("code:%s, signal:%s" % (code,signal) ) self.decrement_requests() #is there an error message? try: error_message = self.xmlprocessor.get_error_message(data) except: error_message = False if error_message and not code: self.mainwindow.set_message( error_message, MainWindow.ERROR_MESSAGE) elif code=='401': #bad authorization self.mainwindow.set_notebook_page(MainWindow.ACCOUNT) error_message = _("Invalid Authorization: Your name or password is incorrect") elif code == '404': error_message = _("Service Not Found") elif code == '503': error_message = _("Service Unavailable") elif code == 'unknown error': error_message = _("Unknown Error") else: error_message = code #send the error message self.mainwindow.set_message(error_message, MainWindow.ERROR_MESSAGE) #a signal may have been passed from the comm if signal == "new-statusXML": #a dent was sent but it failed self.mainwindow.emit_update_textview_responsed(error=True) #functions to handle the filtration system def add_string_filter(self,winder,string): if not string in self.filters['strings']: self.filters['strings'].append(string) self.filters['strings'].sort() self.settingspage.set_string_filters( self.filters['strings'] ) def remove_string_filter(self,winder,string): if string in self.filters['strings']: self.filters['strings'].remove(string) self.settingspage.set_string_filters( self.filters['strings'] ) def add_user_filter(self,winder,user): if not user in self.filters['users']: self.filters['users'].append(user) self.filters['users'].sort() self.settingspage.set_user_filters( self.filters['users'] ) def remove_user_filter(self,winder,user): if user in self.filters['users']: self.filters['users'].remove(user) self.settingspage.set_user_filters( self.filters['users'] ) def check_filtered(self,data): if len(self.filters['users'])!=0 : #filter against the user for user in self.filters['users']: if data['screen_name'].lower()==user.lower(): return (True, "user: %s" % data['screen_name'] ) if len(self.filters['strings'])!=0: #filter against the strings #get the dent text text = data['text'] #loop through the filter strings for string in self.filters['strings']: if re.search(string,text, flags=re.IGNORECASE): return (True, "string: %s" % string ) #if we get this far, just return return (False, None) def status_clicked(self,widget): if self.window_is_hidden==True: self.window_is_hidden=False self.mainwindow.show() self.align_window() self.mainwindow.present() else: self.window_to_tray(widget) def window_size_allocate(self,widget,size): self.window_width = size[2] self.window_height = size[3] def save_app_info(self): #save the filters self.conf.set('settings','filters', self.filters ,True) #save the window info self.conf.set('window_info','width', self.window_width ) self.conf.set('window_info','height', self.window_height ) try: #some themes don't pass root origin? origin = self.mainwindow.window.get_root_origin() self.window_x = origin[0] self.window_y = origin[1] self.conf.set('window_info','x', self.window_x ) self.conf.set('window_info','y', self.window_y ) except: pass self.conf.save() def mainwindow_delete_event(self,window,event=None): self.save_app_info() #are we in tray mode? if self.conf.get_bool_option('run_as_tray_app') or self.has_status_icon: #is the status icon embedded? if self.statusicon.is_embedded(): self.window_is_hidden=True self.mainwindow.hide_on_delete() #do not propogate the signal return True else: #we need to quit self.quit_app() def quit_triggered(self,widget): self.save_app_info() self.quit_app() def option_changed(self,widget,value,option): #save the option change in the configuration self.conf.set('options',option,value) self.options[option]=value self.conf.save() #is this the run_tray_app: if option=='run_as_tray_app': if value: self.create_status_icon() else: self.destroy_status_icon() elif option=='no_avatars': self.imagecache.set_disabled(value) elif option=='ctrl_enter': self.mainwindow.set_ctrl_enter(value) def redent_clicked(self,dent,name,text): if self.options['api_retweet']: self.comm.send_redent(dent.id) else: self.respond_to_id=dent.id #formatted_text= u'\u267A @%s: %s' % (name,text) formatted_text= u'\u267A @%s: %s' % (name,text) self.mainwindow.update_textbuffer.set_text(formatted_text ) self.mainwindow.update_textview.grab_focus() def view_group(self,widget,group_name): #where were we? self.pre_group_page=self.mainwindow.notebook_current_page #make some flags self.grouppage.joined_checkbutton.set_sensitive(False) #make the grouppage visible self.grouppage.show_all() #rehide its collapsed widgetbox, that doesn't need to be visible yet self.grouppage.widgetbox_collapsed.hide() #clear the grouppage self.grouppage.clear() #switch to the group page self.mainwindow.set_notebook_page(GROUP) #get the group info self.get_group_info(group_name) def hide_contextpage(self,widget): #end any conversation in progress self.conversation_id="0" self.mainwindow.set_notebook_page( self.pre_context_page ) self.contextpage.hide() def hide_grouppage(self,widget): self.mainwindow.set_notebook_page( self.pre_group_page ) self.grouppage.hide() def hide_userpage(self,widget): self.mainwindow.set_notebook_page( self.pre_user_page ) self.userpage.hide() def dent_text_clicked(self,dent,text_label): self.mainwindow.last_clicked_label = text_label def clear_respond_to_id(self,widget=None): self.respond_to_id=0 def set_initial_dents(self,widget,value): self.initial_dents=value self.dent_limit = int(self.initial_dents)*2 self.conf.set('settings','initial_dents',value) def set_pull_time(self, widget,value): """A method for setting the time between pulls. obvious comment is obvious. Very possible everything will die now that I've added this. --Muel Kiel (aka samsnotunix)""" self.pull_time=value self.conf.set('settings','pull_time',value) self.pull_time_changed_bool = True self.pull_time_mentions = True def set_link_color(self,widget,string): self.conf.set('settings','link_color',string) self.theme_link_color(string) def theme_link_color(self,color): style=''' style "label" { GtkLabel::link-color="%s" } widget_class "*GtkLabel" style "label" ''' % (color) gtk.rc_parse_string(style) #f**k you GTK for not make this work, more than once! #functions for blocking/unblocking def block_create(self,widget,user_id): self.comm.block_create(user_id) def block_destroy(self,widget,user_id): self.comm.block_destroy(user_id) def set_is_direct_message_mode(self,mode,user=None): self.is_direct_message_mode=mode self.mainwindow.set_is_direct_message_mode(mode,user) if mode: self.default_icon_path=self.direct_icon_path else: self.default_icon_path=self.standard_icon_path #if we aren't waiting on any requests, swap the graphic if self.waiting_requests==0: try: self.mainwindow.set_icon_from_file(self.default_icon_path) except: pass try: self.mainwindow.set_throbber(self.default_icon_path) except: pass def simple_decrement(self,text=None,data=None): self.decrement_requests() ''' function window_to_tray sets the run_as_tray_app to true and minimizes the app ''' def window_to_tray(self,window): if self.options['run_as_tray_app']: self.mainwindow_delete_event(window) def open_link(self, widget, uri): webbrowser.open(uri) return True ''' command = "xdg-open '%s'" % ( uri ) #print command subprocess.Popen(command,shell=True) return True ''' def log(self,string): if self.logging: now = time.strftime("%H:%M:%S") file = os.path.join( os.path.expanduser("~"),"heybuddy.log") f = open(file,'a') f.write("%s %s\n" % (now,string) ) f.close()
def localJob(outputFile): fileName = outputFile.split("/")[1] Notify(fileName).sendLocalStorageEmail() print("Saving raw data file locally....\n")
def __init__(self): #init threading gobject.threads_init() #keep track of the window size self.window_height=0 self.window_width=0 self.window_is_hidden = False self.has_status_icon = False #keep track of the initial conversation id so that conversations don't colide self.conversation_id="0" #keep track of the filters self.filters ={'users':[],'strings':[]} self.options={'run_as_tray_app':False,'context_backwards':False,'no_avatars':False,'notifications':True,'notify_replies':False} #keep track of the direct_message requests self.last_direct_message_time=0 #something something direct message self.is_direct_message_mode=False self.direct_message_to=None self.waiting_requests=0 self.is_first_dents = True #keep track of the respond to id self.respond_to_id=0 self.pre_group_page=None self.pre_user_page=None #keep track of the last time statuses where pulled self.last_get_statuses = 0 #what are the assets? asset_dir = 'assets' heybuddy_dir = os.path.dirname( os.path.realpath( __file__ ) ) self.readme_file = os.path.join(heybuddy_dir,'README.txt') self.standard_icon_path = os.path.join(heybuddy_dir,asset_dir,'icon.png') self.direct_icon_path = os.path.join(heybuddy_dir,asset_dir,'direct_icon.png') self.networking_icon_path = os.path.join(heybuddy_dir,asset_dir,'icon1.png') self.throbber_icon_path = os.path.join(heybuddy_dir,asset_dir,'throbber.gif') self.default_icon_path = self.standard_icon_path self.conf = Configuration(app_name) #has the account info been authenticated? self.credentials_verified = self.conf.get_bool('access', 'credentials_verified') self.xmlprocessor = XMLProcessor() #create a regex to replace parts of a dent self.regex_tag = re.compile("(^| )#([\w-]+)", re.UNICODE) self.regex_group = re.compile("(^| )!([\w-]+)") self.regex_user=re.compile("(^|[^A-z0-9])@(\w+)") self.regex_url=re.compile("(http[s]?://.*?)(\.$|\. |\s|$)",re.IGNORECASE) #get the initial dents self.initial_dents = self.conf.get('settings','initial_dents',default='20' ) self.dent_limit = int(self.initial_dents)*2 #get the pull time self.pull_time = self.conf.get('settings','pull_time',default='60') self.pull_time_changed_bool = False self.pull_time_mentions = False #build the gui self.build_gui() #where is the certs file? ca_certs_files = [ "/etc/ssl/certs/ca-certificates.crt", "/etc/ssl/certs/ca-bundle.crt", ] #what if there isn't a cert_file cert_file=None #determine the certs_file for f in ca_certs_files: if os.path.exists(f): cert_file=f break #create the communicator self.comm = Communicator(app_name, cert_file) self.comm.connect('statusesXML',self.process_statusesXML,self.dentspage) self.comm.connect('mentionsXML',self.process_statusesXML,self.mentionspage) self.comm.connect('favoritesXML', self.process_statusesXML,self.favoritespage) self.comm.connect('group-statusesXML',self.process_statusesXML,self.grouppage) self.comm.connect('user-statusesXML',self.process_statusesXML,self.userpage) self.comm.connect('direct_messagesXML',self.process_statusesXML,self.directspage,True) self.comm.connect('conversationXML',self.process_conversationXML) self.comm.connect('userXML',self.process_userXML) self.comm.connect('groupXML',self.process_groupXML) self.comm.connect('new-statusXML',self.process_new_statusXML) self.comm.connect('redent-statusXML',self.process_new_statusXML) self.comm.connect('user_is_friendXML',self.process_user_is_friendXML) self.comm.connect('user_is_memberXML',self.process_user_is_memberXML) self.comm.connect('friendshipXML',self.process_friendshipXML) self.comm.connect('exception-caught',self.process_communication_exception) self.comm.connect('widget-image',self.process_widget_image) self.comm.connect('direct-messageXML',self.process_new_directXML) self.comm.connect('verify_credentialsXML',self.process_verifycredentialsXML) self.comm.connect('configXML',self.process_configXML) #create an image cacher thingy self.imagecache = ImageCache() self.imagecache.set_disabled( self.conf.get_bool_option('no_avatars') ) self.imagecache.connect('get-widget-image', self.get_widget_image) #Create notify-er if has pynotify if has_pynotify: self.notify = Notify() #align the window self.align_window() # do we need to create the status icon if self.conf.get_bool_option('run_as_tray_app'): self.create_status_icon()
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): image = None apiError = QtCore.pyqtSignal(Exception) commonError = QtCore.pyqtSignal(str, str) sendSuccessful = QtCore.pyqtSignal() userClicked = QtCore.pyqtSignal(UserItem, bool) tagClicked = QtCore.pyqtSignal(str, bool) tweetRefreshed = QtCore.pyqtSignal() tweetRejected = QtCore.pyqtSignal() def __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage) self.errorWindow = APIErrorWindow(self) if self.action not in ["new", "reply"]: self.tweetRefreshed.connect(self._create_tweetWidget) self.tweetRejected.connect( lambda: self.pushButton_send.setEnabled(False)) self._refresh() def setupUi(self, widget): super(NewpostWindow, self).setupUi(widget) self.sendAction = QtGui.QAction(self) self.sendAction.triggered.connect(self.send) self.sendAction.setShortcut(QtGui.QKeySequence("Ctrl+Return")) self.addAction(self.sendAction) self.checkChars() self.setupButtons() def setupButtons(self): # Disabled is the default state of buttons self.pushButton_picture.setEnabled(False) self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) if self.action == "new": assert (not self.tweet) # Shouldn't have a tweet object. self.pushButton_picture.setEnabled(True) elif self.action == "retweet": self.chk_comment.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.textEdit.setText(self.tweet.append_existing_replies()) self.chk_comment_original.setEnabled(True) elif self.action == "comment": self.chk_repost.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) elif self.action == "reply": self.chk_repost.setEnabled(True) if self.tweet.original.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) else: assert False @async def _refresh(self): # The read count is not a real-time value. So refresh it now. try: self.tweet.refresh() except APIError as e: self.errorWindow.raiseException.emit(e) self.tweetRejected.emit() return self.tweetRefreshed.emit() def _create_tweetWidget(self): if self.action == "comment" and self.tweet.comments_count: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) self.replyModel = TweetUnderCommentModel( self.client.api("comments/show"), self.tweet.id, self) elif self.action == "retweet" and self.tweet.retweets_count: if self.tweet: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) elif self.tweet.original: self.tweetWidget = SingleTweetWidget(self.tweet.original, ["image", "original"], self) self.replyModel = TweetRetweetModel( self.client.api("statuses/repost_timeline"), self.tweet.id, self) else: return self.replyModel.load() self.splitter = QtGui.QSplitter(self) self.splitter.setOrientation(QtCore.Qt.Vertical) self.verticalLayout.insertWidget(0, self.splitter) self.tweetWidget.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.splitter.addWidget(self.tweetWidget) self.commentsWidget = TweetListWidget(self, ["image", "original"]) self.commentsWidget.setModel(self.replyModel) self.commentsWidget.scrollArea.setMinimumSize(20, 200) self.commentsWidget.userClicked.connect(self.userClicked) self.commentsWidget.tagClicked.connect(self.tagClicked) self.splitter.addWidget(self.commentsWidget) self.splitter.addWidget(self.textEdit) def mentions_suggest(self, text): ret_users = [] try: word = text.split(' ')[-1] word = word.split('@')[-1] except IndexError: return [] if not word.strip(): return [] users = self.client.api("search/suggestions/at_users").get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def sent(self): self._sent = True self.close() def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": self.new() elif self.action == "retweet": self.retweet() elif self.action == "comment": self.comment() elif self.action == "reply": self.reply() else: # If action is in other types, it must be a mistake. assert False @async def retweet(self): text = self.textEdit.toPlainText() comment = int(self.chk_comment.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.retweet(text, comment, comment_ori) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() @async def comment(self): text = self.textEdit.toPlainText() retweet = int(self.chk_repost.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.comment(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() @async def reply(self): text = self.textEdit.toPlainText() comment_ori = int(self.chk_comment_original.isChecked()) retweet = int(self.chk_repost.isChecked()) try: self.tweet.reply(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() @async def new(self): text = self.textEdit.toPlainText() try: if self.image: try: if getsize(self.image) > const.MAX_IMAGE_BYTES: raise ValueError with open(self.image, "rb") as image: self.client.api("statuses/upload").post(status=text, pic=image) except (OSError, IOError): self.commonError.emit( self.tr("File not found"), self.tr("No such file: %s") % self.image) self.addImage() # In fact, remove image... return except ValueError: self.commonError.emit( self.tr("Too large size"), self.tr("This image is too large to upload: %s") % self.image) self.addImage() # In fact, remove image... return else: self.client.api("statuses/update").post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(e) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.jpeg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("&Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) self.textEdit.setFocus() def showException(self, e): if "Text too long" in str(e): QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: self.errorWindow.raiseException.emit(e) self.pushButton_send.setEnabled(True) def showErrorMessage(self, title, text): QtGui.QMessageBox.warning(self, title, text) def showSmiley(self): wecase_smiley = FaceWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.faceName) self.textEdit.setFocus() def checkChars(self): """Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.""" text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens)) def reject(self): self.close() def closeEvent(self, event): # We have unsend text. if (not self._sent) and (self.textEdit.toPlainText()): choice = QtGui.QMessageBox.question( self, self.tr("Close?"), self.tr("All unpost text will lost."), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if choice == QtGui.QMessageBox.No: event.ignore() else: self.setParent(None)
class WeCaseWindow(QtGui.QMainWindow, Ui_frm_MainWindow): client = None uid = None imageLoaded = QtCore.pyqtSignal(str) tabTextChanged = QtCore.pyqtSignal(int, str) def __init__(self, client, parent=None): QtGui.QMainWindow.__init__(self, parent) self.setupUi(self) self.tweetViews = [ self.homeView, self.mentionsView, self.commentsView, self.myView ] self.client = client self.setupModels() self.init_account() self.setupMyUi() self.loadConfig() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] def init_account(self): self.get_uid() def loadConfig(self): self.config = ConfigParser() self.config.read(const.config_path) if not self.config.has_section('main'): self.config['main'] = {} self.main_config = self.config['main'] self.timer_interval = int(self.main_config.get('notify_interval', 30)) self.notify_timeout = int(self.main_config.get('notify_timeout', 5)) self.remindMentions = self.main_config.getboolean('remind_mentions', 1) self.remindComments = self.main_config.getboolean('remind_comments', 1) def applyConfig(self): try: self.timer.stop_event.set() except AttributeError: pass self.timer = WTimer(self.timer_interval, self.show_notify) self.timer.start() self.notify.timeout = self.notify_timeout def setupMyUi(self): for tweetView in self.tweetViews: tweetView.setResizeMode(tweetView.SizeRootObjectToView) tweetView.setSource( QtCore.QUrl.fromLocalFile(const.myself_path + "/ui/TweetList.qml")) tweetView.rootContext().setContextProperty("mainWindow", self) @QtCore.pyqtSlot() def load_more(self): model = self.get_current_model() model.next() def setupModels(self): self.all_timeline = TweetCommonModel( TweetItem(), self.client.statuses.home_timeline, self) self.all_timeline.load() self.homeView.rootContext().setContextProperty("mymodel", self.all_timeline) self.mentions = TweetCommonModel(TweetItem(), self.client.statuses.mentions, self) self.mentions.load() self.mentionsView.rootContext().setContextProperty( "mymodel", self.mentions) self.comment_to_me = TweetCommentModel(TweetItem(), self.client.comments.to_me, self) self.comment_to_me.load() self.commentsView.rootContext().setContextProperty( "mymodel", self.comment_to_me) self.my_timeline = TweetCommonModel(TweetItem(), self.client.statuses.user_timeline, self) self.my_timeline.load() self.myView.rootContext().setContextProperty("mymodel", self.my_timeline) def reset_remind(self): if self.tabWidget.currentIndex() == 0: self.tabWidget.setTabText(0, self.tr("Weibo")) elif self.tabWidget.currentIndex() == 1: self.client.remind.set_count.post(type="mention_status") self.tabWidget.setTabText(1, self.tr("@Me")) elif self.tabWidget.currentIndex() == 2: self.client.remind.set_count.post(type="cmt") self.tabWidget.setTabText(2, self.tr("Comments")) def get_remind(self, uid): '''this function is used to get unread_count from Weibo API. uid is necessary.''' reminds = self.client.remind.unread_count.get(uid=uid) return reminds def get_uid(self): '''How can I get my uid? here it is''' try: self.uid = self.client.account.get_uid.get().uid except AttributeError: return None def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid) msg = self.tr("You have:") + "\n" num_msg = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabTextChanged.emit(0, self.tr("Weibo(%d)") % reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabTextChanged.emit( 1, self.tr("@Me(%d)") % reminds['mention_status']) num_msg += 1 if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabTextChanged.emit(2, self.tr("Comments(%d)") % reminds['cmt']) num_msg += 1 if num_msg: return self.notify.showMessage(self.tr("WeCase"), msg) def setTabText(self, index, string): self.tabWidget.setTabText(index, string) def moveToTop(self): self.get_current_tweetView().rootObject().positionViewAtBeginning() def setLoaded(self, tweetid): self.get_current_tweetView().rootObject().imageLoaded(tweetid) def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow() wecase_login.exec_() def postTweet(self): wecase_new = NewpostWindow() wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str) def comment(self, idstr): wecase_new = NewpostWindow(action="comment", id=int(idstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def repost(self, idstr, text): wecase_new = NewpostWindow(action="retweet", id=int(idstr), text=text) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, result=int) def favorite(self, idstr): try: self.client.favorites.create.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, result=bool) def un_favorite(self, idstr): try: self.client.favorites.destroy.post(id=int(idstr)) return True except: return False @QtCore.pyqtSlot(str, str) def reply(self, idstr, cidstr): wecase_new = NewpostWindow(action="reply", id=int(idstr), cid=int(cidstr)) wecase_new.client = self.client wecase_new.exec_() @QtCore.pyqtSlot(str, str) def look_orignal_pic(self, thumbnail_pic, tweetid): threading.Thread(group=None, target=self.fetch_open_original_pic, args=(thumbnail_pic, tweetid)).start() def fetch_open_original_pic(self, thumbnail_pic, tweetid): """Fetch and open original pic from thumbnail pic url. Pictures will stored in cache directory. If we already have a same name in cache directory, just open it. If we don't, then download it first.""" if tweetid in self.download_lock: return self.download_lock.append(tweetid) original_pic = thumbnail_pic.replace("thumbnail", "large") # A simple trick ... ^_^ localfile = const.cache_path + original_pic.split("/")[-1] if not os.path.exists(localfile): urllib.request.urlretrieve(original_pic, localfile) self.download_lock.remove(tweetid) os.popen("xdg-open " + localfile) # xdg-open is common? self.imageLoaded.emit(tweetid) def refresh(self): model = self.get_current_model() model.timelineLoaded.connect(self.moveToTop) #model.clear() #model.load() model.new() self.reset_remind() def get_current_tweetView(self): tweetViews = { 0: self.homeView, 1: self.mentionsView, 2: self.commentsView, 3: self.myView } return tweetViews[self.tabWidget.currentIndex()] def get_current_model(self): models = { 0: self.all_timeline, 1: self.mentions, 2: self.comment_to_me, 3: self.my_timeline } return models[self.tabWidget.currentIndex()] def get_current_function(self): functions = { 0: self.get_all_timeline, 1: self.get_mentions_timeline, 2: self.get_comment_to_me, 3: self.get_my_timeline } return functions[self.tabWidget.currentIndex()] def closeEvent(self, event): self.timer.stop_event.set()
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): image = None apiError = QtCore.pyqtSignal(Exception) commonError = QtCore.pyqtSignal(str, str) sendSuccessful = QtCore.pyqtSignal() userClicked = QtCore.pyqtSignal(UserItem, bool) tagClicked = QtCore.pyqtSignal(str, bool) tweetRefreshed = QtCore.pyqtSignal() tweetRejected = QtCore.pyqtSignal() def __init__(self, action="new", tweet=None, parent=None): super(NewpostWindow, self).__init__(parent) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.client = const.client self.tweet = tweet self.action = action self.setupUi(self) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) self._sent = False self.apiError.connect(self.showException) self.sendSuccessful.connect(self.sent) self.commonError.connect(self.showErrorMessage) self.errorWindow = APIErrorWindow(self) if self.action not in ["new", "reply"]: self.tweetRefreshed.connect(self._create_tweetWidget) self.tweetRejected.connect(lambda: self.pushButton_send.setEnabled(False)) self._refresh() def setupUi(self, widget): super(NewpostWindow, self).setupUi(widget) self.sendAction = QtGui.QAction(self) self.sendAction.triggered.connect(self.send) self.sendAction.setShortcut(QtGui.QKeySequence("Ctrl+Return")) self.addAction(self.sendAction) self.checkChars() self.setupButtons() def setupButtons(self): # Disabled is the default state of buttons self.pushButton_picture.setEnabled(False) self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) if self.action == "new": assert (not self.tweet) # Shouldn't have a tweet object. self.pushButton_picture.setEnabled(True) elif self.action == "retweet": self.chk_comment.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.textEdit.setText(self.tweet.append_existing_replies()) self.chk_comment_original.setEnabled(True) elif self.action == "comment": self.chk_repost.setEnabled(True) if self.tweet.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) elif self.action == "reply": self.chk_repost.setEnabled(True) if self.tweet.original.type == TweetItem.RETWEET: self.chk_comment_original.setEnabled(True) else: assert False @async def _refresh(self): # The read count is not a real-time value. So refresh it now. try: self.tweet.refresh() except APIError as e: self.errorWindow.raiseException.emit(e) self.tweetRejected.emit() return self.tweetRefreshed.emit() def _create_tweetWidget(self): if self.action == "comment" and self.tweet.comments_count: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) self.replyModel = TweetUnderCommentModel(self.client.api("comments/show"), self.tweet.id, self) elif self.action == "retweet" and self.tweet.retweets_count: if self.tweet: self.tweetWidget = SingleTweetWidget(self.tweet, ["image", "original"], self) elif self.tweet.original: self.tweetWidget = SingleTweetWidget(self.tweet.original, ["image", "original"], self) self.replyModel = TweetRetweetModel(self.client.api("statuses/repost_timeline"), self.tweet.id, self) else: return self.replyModel.load() self.splitter = QtGui.QSplitter(self) self.splitter.setOrientation(QtCore.Qt.Vertical) self.verticalLayout.insertWidget(0, self.splitter) self.tweetWidget.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.splitter.addWidget(self.tweetWidget) self.commentsWidget = TweetListWidget(self, ["image", "original"]) self.commentsWidget.setModel(self.replyModel) self.commentsWidget.scrollArea.setMinimumSize(20, 200) self.commentsWidget.userClicked.connect(self.userClicked) self.commentsWidget.tagClicked.connect(self.tagClicked) self.splitter.addWidget(self.commentsWidget) self.splitter.addWidget(self.textEdit) def mentions_suggest(self, text): ret_users = [] try: word = text.split(' ')[-1] word = word.split('@')[-1] except IndexError: return [] if not word.strip(): return [] users = self.client.api("search/suggestions/at_users").get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def sent(self): self._sent = True self.close() def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": self.new() elif self.action == "retweet": self.retweet() elif self.action == "comment": self.comment() elif self.action == "reply": self.reply() else: # If action is in other types, it must be a mistake. assert False @async def retweet(self): text = self.textEdit.toPlainText() comment = int(self.chk_comment.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.retweet(text, comment, comment_ori) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() @async def comment(self): text = self.textEdit.toPlainText() retweet = int(self.chk_repost.isChecked()) comment_ori = int(self.chk_comment_original.isChecked()) try: self.tweet.comment(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() @async def reply(self): text = self.textEdit.toPlainText() comment_ori = int(self.chk_comment_original.isChecked()) retweet = int(self.chk_repost.isChecked()) try: self.tweet.reply(text, comment_ori, retweet) except APIError as e: self.apiError.emit(e) return self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() @async def new(self): text = self.textEdit.toPlainText() try: if self.image: try: if getsize(self.image) > const.MAX_IMAGE_BYTES: raise ValueError with open(self.image, "rb") as image: self.client.api("statuses/upload").post(status=text, pic=image) except (OSError, IOError): self.commonError.emit(self.tr("File not found"), self.tr("No such file: %s") % self.image) self.addImage() # In fact, remove image... return except ValueError: self.commonError.emit(self.tr("Too large size"), self.tr("This image is too large to upload: %s") % self.image) self.addImage() # In fact, remove image... return else: self.client.api("statuses/update").post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(e) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.jpeg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("&Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) self.textEdit.setFocus() def showException(self, e): if "Text too long" in str(e): QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: self.errorWindow.raiseException.emit(e) self.pushButton_send.setEnabled(True) def showErrorMessage(self, title, text): QtGui.QMessageBox.warning(self, title, text) def showSmiley(self): wecase_smiley = FaceWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.faceName) self.textEdit.setFocus() def checkChars(self): """Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.""" text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens)) def reject(self): self.close() def closeEvent(self, event): # We have unsend text. if (not self._sent) and (self.textEdit.toPlainText()): choice = QtGui.QMessageBox.question( self, self.tr("Close?"), self.tr("All unpost text will lost."), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) if choice == QtGui.QMessageBox.No: event.ignore() else: self.setParent(None)
class WeCaseWindow(QtGui.QMainWindow): client = None uid = None timelineLoaded = QtCore.pyqtSignal(int) imageLoaded = QtCore.pyqtSignal(str) tabBadgeChanged = QtCore.pyqtSignal(int, int) tabAvatarFetched = QtCore.pyqtSignal(str) def __init__(self, username, parent=None): super(WeCaseWindow, self).__init__(parent) self.username = username LoginInfo().add_account(self.username) self.errorWindow = APIErrorWindow(self) self.setAttribute(QtCore.Qt.WA_QuitOnClose, True) self._iconPixmap = {} self.setupUi(self) self._setupSysTray() self.tweetViews = [ self.homeView, self.mentionsView, self.commentsView, self.commentsMentionsTab ] self.info = WeRuntimeInfo() self.client = const.client self.loadConfig() self.init_account() self.setupModels() self.IMG_AVATAR = -2 self.IMG_THUMB = -1 self.notify = Notify(timeout=self.notify_timeout) self.applyConfig() self.download_lock = [] self._last_reminds_count = 0 self._setupUserTab(self.uid(), False, True) def _setupTab(self, view): tab = QtGui.QWidget() layout = QtGui.QGridLayout(tab) layout.addWidget(view) view.setParent(tab) return tab def _setupCommonTab(self, timeline, view, switch=True, protect=False): self._prepareTimeline(timeline) view.setModel(timeline) view.userClicked.connect(self.userClicked) view.tagClicked.connect(self.tagClicked) tab = self._setupTab(view) self.tabWidget.addTab(tab, "") if switch: self.tabWidget.setCurrentWidget(tab) if protect: self.tabWidget.tabBar().setProtectTab(tab, True) return tab def _getSameTab(self, attr, value): for i in range(self.tabWidget.count()): try: tab = self.tabWidget.widget(i).layout().itemAt(0).widget() _value = getattr(tab.model(), attr)() if _value == value: return i except AttributeError: pass return False def _setupUserTab(self, uid, switch=True, myself=False): index = self._getSameTab("uid", uid) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() _timeline = TweetUserModel(self.client.api("statuses/user_timeline"), uid, view) timeline = TweetFilterModel(_timeline) timeline.setModel(_timeline) tab = self._setupCommonTab(timeline, view, switch, myself) def setAvatar(f): self._setTabIcon(tab, WObjectCache().open(QtGui.QPixmap, f)) fetcher = AsyncFetcher("".join( (path.cache_path, str(self.info["uid"])))) fetcher.addTask( self.client.api("users/show").get(uid=uid)["profile_image_url"], setAvatar) def _setupTopicTab(self, topic, switch=True): index = self._getSameTab("topic", topic) if index: if switch: self.tabWidget.setCurrentIndex(index) return view = TweetListWidget() timeline = TweetTopicModel(self.client.api("search/topics"), topic, view) tab = self._setupCommonTab(timeline, view, switch, protect=False) self._setTabIcon( tab, WObjectCache().open(QtGui.QPixmap, ":/IMG/img/topic.jpg")) def userClicked(self, userItem, openAtBackend): try: self._setupUserTab(userItem.id, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def tagClicked(self, str, openAtBackend): try: self._setupTopicTab(str, switch=(not openAtBackend)) except APIError as e: self.errorWindow.raiseException.emit(e) def setupUi(self, mainWindow): mainWindow.setWindowIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) mainWindow.setDocumentMode(False) mainWindow.setDockOptions(QtGui.QMainWindow.AllowTabbedDocks | QtGui.QMainWindow.AnimatedDocks) self.centralwidget = QtGui.QWidget(mainWindow) self.verticalLayout = QtGui.QVBoxLayout(self.centralwidget) self.tabWidget = QtGui.QTabWidget(self.centralwidget) self.tabWidget.setTabBar(WTabBar(self.tabWidget)) self.tabWidget.setTabPosition(QtGui.QTabWidget.West) self.tabWidget.setTabShape(QtGui.QTabWidget.Rounded) self.tabWidget.setDocumentMode(False) self.tabWidget.setMovable(True) self.tabWidget.tabCloseRequested.connect(self.closeTab) self.homeView = TweetListWidget() self.homeView.userClicked.connect(self.userClicked) self.homeView.tagClicked.connect(self.tagClicked) self.homeTab = self._setupTab(self.homeView) self.tabWidget.addTab(self.homeTab, "") self.tabWidget.tabBar().setProtectTab(self.homeTab, True) self.mentionsView = TweetListWidget() self.mentionsView.userClicked.connect(self.userClicked) self.mentionsView.tagClicked.connect(self.tagClicked) self.mentionsTab = self._setupTab(self.mentionsView) self.tabWidget.addTab(self.mentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.mentionsTab, True) self.commentsView = TweetListWidget() self.commentsView.userClicked.connect(self.userClicked) self.commentsView.tagClicked.connect(self.tagClicked) self.commentsTab = self._setupTab(self.commentsView) self.tabWidget.addTab(self.commentsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsTab, True) self.commentsMentionsView = TweetListWidget() self.commentsMentionsView.userClicked.connect(self.userClicked) self.commentsMentionsView.tagClicked.connect(self.tagClicked) self.commentsMentionsTab = self._setupTab(self.commentsMentionsView) self.tabWidget.addTab(self.commentsMentionsTab, "") self.tabWidget.tabBar().setProtectTab(self.commentsMentionsTab, True) self.verticalLayout.addWidget(self.tabWidget) self.widget = QtGui.QWidget(self.centralwidget) self.verticalLayout.addWidget(self.widget) mainWindow.setCentralWidget(self.centralwidget) self.aboutAction = QtGui.QAction(mainWindow) self.refreshAction = QtGui.QAction(mainWindow) self.logoutAction = QtGui.QAction(mainWindow) self.exitAction = QtGui.QAction(mainWindow) self.settingsAction = QtGui.QAction(mainWindow) self.aboutAction.setIcon( QtGui.QIcon(QtGui.QPixmap("./IMG/img/where_s_my_weibo.svg"))) self.exitAction.setIcon( QtGui.QIcon(QtGui.QPixmap(":/IMG/img/application-exit.svg"))) self.settingsAction.setIcon( QtGui.QIcon(QtGui.QPixmap(":/IMG/img/preferences-other.png"))) self.refreshAction.setIcon( QtGui.QIcon(QtGui.QPixmap(":/IMG/img/refresh.png"))) self.menubar = QtGui.QMenuBar(mainWindow) self.menubar.setEnabled(True) self.menubar.setDefaultUp(False) mainWindow.setMenuBar(self.menubar) self.mainMenu = QtGui.QMenu(self.menubar) self.helpMenu = QtGui.QMenu(self.menubar) self.optionsMenu = QtGui.QMenu(self.menubar) self.mainMenu.addAction(self.refreshAction) self.mainMenu.addSeparator() self.mainMenu.addAction(self.logoutAction) self.mainMenu.addAction(self.exitAction) self.helpMenu.addAction(self.aboutAction) self.optionsMenu.addAction(self.settingsAction) self.menubar.addAction(self.mainMenu.menuAction()) self.menubar.addAction(self.optionsMenu.menuAction()) self.menubar.addAction(self.helpMenu.menuAction()) self.exitAction.triggered.connect(mainWindow.close) self.aboutAction.triggered.connect(mainWindow.showAbout) self.settingsAction.triggered.connect(mainWindow.showSettings) self.logoutAction.triggered.connect(mainWindow.logout) self.refreshAction.triggered.connect(mainWindow.refresh) self.pushButton_refresh = QtGui.QPushButton(self.widget) self.pushButton_new = QtGui.QPushButton(self.widget) self.pushButton_refresh.clicked.connect(mainWindow.refresh) self.pushButton_new.clicked.connect(mainWindow.postTweet) self.timelineLoaded.connect(self.moveToTop) self.tabBadgeChanged.connect(self.drawNotifyBadge) self.refreshAction.setShortcut(QtGui.QKeySequence("F5")) self.pushButton_refresh.setIcon(QtGui.QIcon(":/IMG/img/refresh.png")) self.pushButton_new.setIcon(QtGui.QIcon(":/IMG/img/new.png")) if self.isGlobalMenu(): self._setupToolBar() else: self._setupButtonWidget() self._setTabIcon(self.homeTab, QtGui.QPixmap(":/IMG/img/sina.png")) self._setTabIcon(self.mentionsTab, QtGui.QPixmap(":/IMG/img/mentions.png")) self._setTabIcon(self.commentsTab, QtGui.QPixmap(":/IMG/img/comments2.png")) self._setTabIcon(self.commentsMentionsTab, QtGui.QPixmap(":/IMG/img/mentions_comments.svg")) self.retranslateUi(mainWindow) def isGlobalMenu(self): if os.environ.get("TOOLBAR") == "1": return True elif os.environ.get("TOOLBAR") == "0": return False elif os.environ.get('DESKTOP_SESSION') in ["ubuntu", "ubuntu-2d"]: if not os.environ.get("UBUNTU_MENUPROXY"): return False elif os.environ.get("APPMENU_DISPLAY_BOTH"): return False else: return True elif os.environ.get( "DESKTOP_SESSION" ) == "kde-plasma" and platform.linux_distribution()[0] == "Ubuntu": return True elif platform.system() == "Darwin": return True return False def _setupToolBar(self): self.toolBar = QtGui.QToolBar() self.toolBar.setToolButtonStyle(QtCore.Qt.ToolButtonTextBesideIcon) empty = QtGui.QWidget() empty.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Preferred) self.toolBar.addWidget(empty) self.toolBar.addAction(self.refreshAction) newAction = self.toolBar.addAction(QtGui.QIcon(":/IMG/img/new.png"), "New") newAction.triggered.connect(self.pushButton_new.clicked) self.addToolBar(self.toolBar) def _setupButtonWidget(self): self.buttonWidget = QtGui.QWidget(self) self.buttonLayout = QtGui.QHBoxLayout(self.buttonWidget) self.horizontalSpacer = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum) self.buttonLayout.addSpacerItem(self.horizontalSpacer) self.buttonLayout.addWidget(self.pushButton_refresh) self.buttonLayout.addWidget(self.pushButton_new) def resizeEvent(self, event): # This is a hack!!! if self.isGlobalMenu(): return self.buttonWidget.resize(self.menubar.sizeHint().width(), self.menubar.sizeHint().height() + 12) self.buttonWidget.move(self.width() - self.buttonWidget.width(), self.menubar.geometry().topRight().y() - 5) def retranslateUi(self, frm_MainWindow): frm_MainWindow.setWindowTitle(self.tr("WeCase")) self.mainMenu.setTitle(self.tr("&WeCase")) self.helpMenu.setTitle(self.tr("&Help")) self.optionsMenu.setTitle(self.tr("&Options")) self.aboutAction.setText(self.tr("&About...")) self.refreshAction.setText(self.tr("Refresh")) self.logoutAction.setText(self.tr("&Log out")) self.exitAction.setText(self.tr("&Exit")) self.settingsAction.setText(self.tr("&Settings")) def _setupSysTray(self): self.systray = QtGui.QSystemTrayIcon() self.systray.activated.connect(self.clickedSystray) self.systray.setToolTip("WeCase") self.systray.setIcon(QtGui.QIcon(":/IMG/img/WeCase.svg")) self.systray.show() self.visibleAction = QtGui.QAction(self) self.visibleAction.setText(self.tr("&Hide")) self.visibleAction.triggered.connect(self._switchVisibility) self.sysMenu = QtGui.QMenu(self) self.sysMenu.addAction(self.visibleAction) self.sysMenu.addAction(self.logoutAction) self.sysMenu.addAction(self.exitAction) self.systray.setContextMenu(self.sysMenu) def clickedSystray(self, reason): if reason == QtGui.QSystemTrayIcon.Trigger: self._switchVisibility() elif reason == QtGui.QSystemTrayIcon.Context: pass def _switchVisibility(self): if self.isVisible(): self.hide() self.visibleAction.setText(self.tr("&Show")) else: self.show() self.visibleAction.setText(self.tr("&Hide")) def _setTabIcon(self, tab, icon): pixmap = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(pixmap) self._iconPixmap[icon.cacheKey()] = pixmap self.tabWidget.setTabIcon(self.tabWidget.indexOf(tab), icon) self.tabWidget.setIconSize(QtCore.QSize(24, 24)) def _prepareTimeline(self, timeline): try: timeline.setUsersBlacklist(self.usersBlacklist) timeline.setTweetsKeywordsBlacklist(self.tweetKeywordsBlacklist) timeline.setWordWarKeywords(self.wordWarKeywords) timeline.setBlockWordwars(self.blockWordwars) timeline.setKeywordsAsRegexs(self.keywordsAsRegex) except AttributeError: pass timeline.load() def closeTab(self, index): widget = self.tabWidget.widget(index) self.tabWidget.removeTab(index) widget.deleteLater() def init_account(self): self.uid() def loadConfig(self): self.config = WConfigParser(path.myself_path + "WMetaConfig", path.config_path, "main") self.notify_interval = self.config.notify_interval self.notify_timeout = self.config.notify_timeout self.usersBlacklist = self.config.usersBlacklist self.tweetKeywordsBlacklist = self.config.tweetsKeywordsBlacklist self.remindMentions = self.config.remind_mentions self.remindComments = self.config.remind_comments self.wordWarKeywords = self.config.wordWarKeywords self.blockWordwars = self.config.blockWordwars self.maxRetweets = self.config.maxRetweets self.maxTweetsPerUser = self.config.maxTweetsPerUser self.mainWindow_geometry = self.config.mainwindow_geometry self.keywordsAsRegex = self.config.keywordsAsRegex def applyConfig(self): try: self.timer.stop() except AttributeError: pass self.timer = WTimer(self.show_notify, self.notify_interval) self.timer.start() self.notify.timeout = self.notify_timeout setGeometry(self, self.mainWindow_geometry) def setupModels(self): self._all_timeline = TweetCommonModel( self.client.api("statuses/home_timeline"), self) self.all_timeline = TweetFilterModel(self._all_timeline) self.all_timeline.setModel(self._all_timeline) self._prepareTimeline(self.all_timeline) # extra rules self.all_timeline.setMaxRetweets(self.maxRetweets) self.all_timeline.setMaxTweetsPerUser(self.maxTweetsPerUser) self.homeView.setModel(self.all_timeline) self._mentions = TweetCommonModel(self.client.api("statuses/mentions"), self) self.mentions = TweetFilterModel(self._mentions) self.mentions.setModel(self._mentions) self._prepareTimeline(self.mentions) self.mentionsView.setModel(self.mentions) self._comment_to_me = TweetCommentModel( self.client.api("comments/to_me"), self) self.comment_to_me = TweetFilterModel(self._comment_to_me) self.comment_to_me.setModel(self._comment_to_me) self._prepareTimeline(self.comment_to_me) self.commentsView.setModel(self.comment_to_me) self._comment_mentions = TweetCommentModel( self.client.api("comments/mentions"), self) self.comment_mentions = TweetFilterModel(self._comment_mentions) self.comment_mentions.setModel(self._comment_mentions) self._prepareTimeline(self.comment_mentions) self.commentsMentionsView.setModel(self.comment_mentions) @async def reset_remind(self): typ = "" if self.currentTweetView() == self.homeView: self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.mentionsView: typ = "mention_status" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsView: typ = "cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) elif self.currentTweetView() == self.commentsMentionsView: typ = "mention_cmt" self.tabBadgeChanged.emit(self.tabWidget.currentIndex(), 0) if typ: self.client.api("remind/set_count").post(type=typ) def get_remind(self, uid): """this function is used to get unread_count from Weibo API. uid is necessary.""" reminds = self.client.api("remind/unread_count").get(uid=uid) return reminds def uid(self): """How can I get my uid? here it is""" if not self.info.get("uid"): self.info["uid"] = self.client.api("account/get_uid").get().uid return self.info["uid"] def show_notify(self): # This function is run in another thread by WTimer. # Do not modify UI directly. Send signal and react it in a slot only. # We use SIGNAL self.tabTextChanged and SLOT self.setTabText() # to display unread count reminds = self.get_remind(self.uid()) msg = self.tr("You have:") + "\n" reminds_count = 0 if reminds['status'] != 0: # Note: do NOT send notify here, or users will crazy. self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.homeTab), reminds['status']) if reminds['mention_status'] and self.remindMentions: msg += self.tr("%d unread @ME") % reminds['mention_status'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), reminds['mention_status']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.mentionsTab), 0) if reminds['cmt'] and self.remindComments: msg += self.tr("%d unread comment(s)") % reminds['cmt'] + "\n" self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), reminds['cmt']) reminds_count += 1 else: self.tabBadgeChanged.emit(self.tabWidget.indexOf(self.commentsTab), 0) if reminds["mention_cmt"] and self.remindMentions: msg += self.tr( "%d unread @ME comment(s)") % reminds["mention_cmt"] + "\n" self.tabBadgeChanged.emit( self.tabWidget.indexOf(self.commentsMentionsTab), reminds["mention_cmt"]) reminds_count += 1 else: self.tabBadgeChanged.emit( self.tabWidget.indexOf(self.commentsMentionsTab), 0) if reminds_count and reminds_count != self._last_reminds_count: self.notify.showMessage(self.tr("WeCase"), msg) self._last_reminds_count = reminds_count def drawNotifyBadge(self, index, count): tabIcon = self.tabWidget.tabIcon(index) _tabPixmap = self._iconPixmap[tabIcon.cacheKey()] tabPixmap = _tabPixmap.transformed(QtGui.QTransform().rotate(-90)) icon = NotifyBadgeDrawer().draw(tabPixmap, str(count)) icon = icon.transformed(QtGui.QTransform().rotate(90)) icon = QtGui.QIcon(icon) self._iconPixmap[icon.cacheKey()] = _tabPixmap self.tabWidget.setTabIcon(index, icon) def moveToTop(self): self.currentTweetView().moveToTop() def showSettings(self): wecase_settings = WeSettingsWindow() if wecase_settings.exec_(): self.loadConfig() self.applyConfig() def showAbout(self): wecase_about = AboutWindow() wecase_about.exec_() def logout(self): self.close() # This is a model dialog, if we exec it before we close MainWindow # MainWindow won't close from LoginWindow import LoginWindow wecase_login = LoginWindow(allow_auto_login=False) wecase_login.exec_() def postTweet(self): self.wecase_new = NewpostWindow() self.wecase_new.userClicked.connect(self.userClicked) self.wecase_new.tagClicked.connect(self.tagClicked) self.wecase_new.show() def refresh(self): tweetView = self.currentTweetView() tweetView.model().timelineLoaded.connect(self.moveToTop) tweetView.refresh() self.reset_remind() def currentTweetView(self): # The most tricky part of MainWindow. return self.tabWidget.currentWidget().layout().itemAt(0).widget() def saveConfig(self): self.config.mainwindow_geometry = getGeometry(self) self.config.save() def closeEvent(self, event): self.systray.hide() self.hide() self.saveConfig() self.timer.stop(True) # Reset uid when the thread exited. self.info["uid"] = None LoginInfo().remove_account(self.username) logging.info("Die")
class NewpostWindow(QtGui.QDialog, Ui_NewPostWindow): client = None image = None apiError = QtCore.pyqtSignal(str) sendSuccessful = QtCore.pyqtSignal() def __init__(self, parent=None, action="new", id=None, cid=None, text=""): QtGui.QDialog.__init__(self, parent) self.action = action self.id = id self.cid = cid self.setupUi(self) self.setupMyUi() self.textEdit.setText(text) self.textEdit.callback = self.mentions_suggest self.textEdit.mention_flag = "@" self.notify = Notify(timeout=1) def setupMyUi(self): self.checkChars() if self.action == "new": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.chk_comment_original.setEnabled(False) elif self.action == "retweet": self.chk_repost.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "comment": self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) elif self.action == "reply": self.chk_repost.setEnabled(False) self.chk_comment.setEnabled(False) self.pushButton_picture.setEnabled(False) def mentions_suggest(self, text): ret_users = [] try: word = re.findall('@[-a-zA-Z0-9_\u4e00-\u9fa5]+', text)[-1] word = word.replace('@', '') except IndexError: return [] if not word.strip(): return [] users = self.client.search.suggestions.at_users.get(q=word, type=0) for user in users: ret_users.append("@" + user['nickname']) return ret_users def send(self): self.pushButton_send.setEnabled(False) if self.action == "new": threading.Thread(group=None, target=self.new).start() elif self.action == "retweet": threading.Thread(group=None, target=self.retweet).start() elif self.action == "comment": threading.Thread(group=None, target=self.comment).start() elif self.action == "reply": threading.Thread(group=None, target=self.reply).start() def retweet(self): text = str(self.textEdit.toPlainText()) try: self.client.statuses.repost.post( id=int(self.id), status=text, is_comment=int((self.chk_comment.isChecked() + self.chk_comment_original.isChecked() * 2))) self.notify.showMessage(self.tr("WeCase"), self.tr("Retweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def comment(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.create.post( id=int(self.id), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Comment Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def reply(self): text = str(self.textEdit.toPlainText()) try: self.client.comments.reply.post( id=int(self.id), cid=int(self.cid), comment=text, comment_ori=int(self.chk_comment_original.isChecked())) if self.chk_repost.isChecked(): self.client.statuses.repost.post(id=int(self.id), status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Reply Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return def new(self): text = str(self.textEdit.toPlainText()) try: if self.image: self.client.statuses.upload.post(status=text, pic=open(self.image, "rb")) else: self.client.statuses.update.post(status=text) self.notify.showMessage(self.tr("WeCase"), self.tr("Tweet Success!")) self.sendSuccessful.emit() except APIError as e: self.apiError.emit(str(e)) return self.image = None def addImage(self): ACCEPT_TYPE = self.tr("Images") + "(*.png *.jpg *.bmp *.gif)" if self.image: self.image = None self.pushButton_picture.setText(self.tr("Picture")) else: self.image = QtGui.QFileDialog.getOpenFileName(self, self.tr("Choose a" " image"), filter=ACCEPT_TYPE) # user may cancel the dialog, so check again if self.image: self.pushButton_picture.setText(self.tr("Remove the picture")) def showError(self, e): if "Text too long" in e: QtGui.QMessageBox.warning(None, self.tr("Text too long!"), self.tr("Please remove some text.")) else: QtGui.QMessageBox.warning(None, self.tr("Unknown error!"), e) self.pushButton_send.setEnabled(True) def showSmiley(self): wecase_smiley = SmileyWindow() if wecase_smiley.exec_(): self.textEdit.textCursor().insertText(wecase_smiley.smileyName) def checkChars(self): '''Check textEdit's characters. If it larger than 140, Send Button will be disabled and label will show red chars.''' text = self.textEdit.toPlainText() numLens = 140 - tweetLength(text) if numLens == 140 and (not self.action == "retweet"): # you can not send empty tweet, except retweet self.pushButton_send.setEnabled(False) elif numLens >= 0: # length is okay self.label.setStyleSheet("color:black;") self.pushButton_send.setEnabled(True) else: # text is too long self.label.setStyleSheet("color:red;") self.pushButton_send.setEnabled(False) self.label.setText(str(numLens))