1
+ #!/usr/bin/env python
2
+
3
+ import os , sys , pickle , subprocess
4
+ from PyQt4 import QtCore , QtGui , QtWebKit
5
+ import Windows , Helper
6
+
7
+ class Bungloo :
8
+
9
+ def __init__ (self ):
10
+ self .app = QtGui .QApplication (sys .argv )
11
+ self .new_message_windows = []
12
+ self .controller = Controller (self )
13
+ self .console = Console ()
14
+
15
+ self .preferences = Windows .Preferences (self )
16
+ self .preferences .show ()
17
+
18
+ self .oauth_implementation = Windows .Oauth (self )
19
+
20
+ if self .controller .stringForKey ("user_access_token" ) != "" :
21
+ self .authentification_succeded ()
22
+
23
+ self .app .exec_ ()
24
+
25
+ def resources_path (self ):
26
+ return os .path .abspath (os .path .join (os .path .dirname (__file__ ), '..' ))
27
+
28
+ def resources_uri (self ):
29
+ return "file://localhost" + os .path .abspath (os .path .join (self .resources_path (), "WebKit" ))
30
+
31
+ def login_with_entity (self , entity ):
32
+ self .controller .setStringForKey (entity , "entity" )
33
+ self .oauth_implementation .login ()
34
+
35
+ def authentification_succeded (self ):
36
+ self .preferences .hide ()
37
+ if hasattr (self , "oauth_implementation" ):
38
+ self .oauth_implementation .hide ()
39
+ self .preferences .active (False )
40
+ self .init_web_views ()
41
+
42
+ def init_web_views (self ):
43
+ self .timeline = Windows .Timeline (self )
44
+ self .mentions = Windows .Timeline (self , "mentions" , "Mentions" )
45
+ self .timeline .show ()
46
+ self .conversation = Windows .Timeline (self , "conversation" , "Conversation" )
47
+ self .profile = Windows .Timeline (self , "profile" , "Profile" )
48
+
49
+ def timeline_show (self ):
50
+ self .timeline .show ()
51
+
52
+ def mentions_show (self ):
53
+ self .controller .unreadMentions (0 )
54
+ self .mentions .show ()
55
+
56
+
57
+ class Controller (QtCore .QObject ):
58
+
59
+ def __init__ (self , app ):
60
+ QtCore .QObject .__init__ (self )
61
+ self .app = app
62
+
63
+ self .config_path = os .path .expanduser ('~/.bungloo.cfg' )
64
+ if os .access (self .config_path , os .R_OK ):
65
+ with open (self .config_path , 'r' ) as f :
66
+ self .config = pickle .load (f )
67
+ else :
68
+ print self .config_path + " is not readable"
69
+ self .config = {}
70
+
71
+ @QtCore .pyqtSlot (str , str )
72
+ def setStringForKey (self , string , key ):
73
+ string , key = str (string ), str (key )
74
+ self .config [key ] = string
75
+ try :
76
+ with open (self .config_path , 'w+' ) as f :
77
+ pickle .dump (self .config , f )
78
+ except IOError :
79
+ print self .config_path + " is not writable"
80
+ print "I/O error({0}): {1}" .format (e .errno , e .strerror )
81
+
82
+ @QtCore .pyqtSlot (str , result = str )
83
+ def stringForKey (self , key ):
84
+ key = str (key )
85
+ if key in self .config :
86
+ return self .config [key ]
87
+ else :
88
+ return ""
89
+
90
+ @QtCore .pyqtSlot (str )
91
+ def openAuthorizationURL (self , url ):
92
+ self .app .oauth_implementation .handle_authentication (str (url ))
93
+
94
+ @QtCore .pyqtSlot (str )
95
+ def openURL (self , url ):
96
+ QtGui .QDesktopServices .openUrl (QtCore .QUrl (url , QtCore .QUrl .TolerantMode ))
97
+
98
+ def openQURL (self , url ):
99
+ QtGui .QDesktopServices .openUrl (url )
100
+
101
+ @QtCore .pyqtSlot ()
102
+ def loggedIn (self ):
103
+ self .app .authentification_succeded ()
104
+
105
+ @QtCore .pyqtSlot (int )
106
+ def unreadMentions (self , count ):
107
+ i = int (count )
108
+ if i > 0 :
109
+ self .app .timeline .set_window_title ("Tentia (^" + str (i ) + ")" )
110
+ else :
111
+ self .app .timeline .set_window_title ("Tentia" )
112
+ self .app .mentions .evaluateJavaScript ("bungloo_instance.unread_mentions = 0;" )
113
+
114
+ @QtCore .pyqtSlot (str , str , str , str )
115
+ def notificateUserAboutMentionFromNameWithPostIdAndEntity (self , text , name , post_id , entity ):
116
+ try :
117
+ subprocess .check_output (['kdialog' , '--passivepopup' , name + ' mentioned you: ' + text ])
118
+ except OSError :
119
+ try :
120
+ subprocess .check_output (['notify-send' , '-i' , 'dialog-information' , name + ' mentioned you on Tent' , text ])
121
+ except OSError :
122
+ pass
123
+
124
+ @QtCore .pyqtSlot (str )
125
+ def openNewMessageWidow (self , string ):
126
+ new_message_window = Windows .NewPost (self .app )
127
+ new_message_window .show ()
128
+ new_message_window .setAttribute (QtCore .Qt .WA_DeleteOnClose )
129
+ self .app .new_message_windows .append (new_message_window )
130
+
131
+ @QtCore .pyqtSlot (str , str , str , bool )
132
+ def openNewMessageWindowInReplyTostatusIdwithStringIsPrivate (self , entity , status_id , string , is_private ):
133
+ new_message_window = Windows .NewPost (self .app )
134
+ new_message_window .inReplyToStatusIdWithString (entity , status_id , string )
135
+ new_message_window .setIsPrivate (is_private )
136
+ new_message_window .show ()
137
+ new_message_window .setAttribute (QtCore .Qt .WA_DeleteOnClose )
138
+ self .app .new_message_windows .append (new_message_window )
139
+
140
+ def sendMessage (self , message ):
141
+ text = message .text
142
+ text = unicode .replace (text , "\\ " , "\\ \\ " )
143
+ text = unicode .replace (text , "\" " , "\\ \" " )
144
+ text = unicode .replace (text , "\n " , "\\ n" )
145
+
146
+ in_reply_to_status_id = ""
147
+ if message .inReplyTostatusId is not None :
148
+ in_reply_to_status_id = message .inReplyTostatusId
149
+
150
+ in_reply_to_entity = ""
151
+ if message .inReplyToEntity is not None :
152
+ in_reply_to_entity = message .inReplyToEntity
153
+
154
+ locationObject = "null"
155
+ #if (post.location) {
156
+ # locationObject = [NSString stringWithFormat:@"[%f, %f]", post.location.coordinate.latitude, post.location.coordinate.longitude];
157
+ #}
158
+
159
+ imageFilePath = "null"
160
+ if message .imageFilePath is not None :
161
+ mimeType = subprocess .check_output (['file' , '-b' , '--mime' , message .imageFilePath ]).split (";" )[0 ]
162
+ base64 = open (message .imageFilePath , "rb" ).read ().encode ("base64" ).replace ("\n " , "" )
163
+ imageFilePath = "\" data:{};base64,{}\" " .format (mimeType , base64 )
164
+
165
+ isPrivate = "false" ;
166
+ if message .isPrivate :
167
+ isPrivate = "true"
168
+
169
+ func = u"bungloo_instance.sendNewMessage(\" {}\" , \" {}\" , \" {}\" , {}, {}, {});" .format (text , in_reply_to_status_id , in_reply_to_entity , locationObject , imageFilePath , isPrivate )
170
+ self .app .timeline .evaluateJavaScript (func )
171
+
172
+ @QtCore .pyqtSlot (str , str )
173
+ def showConversationForPostIdandEntity (self , postId , entity ):
174
+ func = "bungloo_instance.showStatus('{}', '{}');" .format (postId , entity )
175
+ self .app .conversation .evaluateJavaScript (func )
176
+ self .app .conversation .show ()
177
+
178
+ @QtCore .pyqtSlot (str )
179
+ def showProfileForEntity (self , entity ):
180
+ func = "bungloo_instance.showProfileForEntity('{}');" .format (entity )
181
+ self .app .profile .evaluateJavaScript (func )
182
+ self .app .profile .show ()
183
+
184
+ @QtCore .pyqtSlot (str , str )
185
+ def notificateViewsAboutDeletedPostWithIdbyEntity (self , post_id , entity ):
186
+ func = "bungloo_instance.postDeleted('{}', '{}')" .format (post_id , entity );
187
+ self .app .timeline .evaluateJavaScript (func )
188
+ self .app .mentions .evaluateJavaScript (func )
189
+ self .app .conversation .evaluateJavaScript (func )
190
+ self .app .profile .evaluateJavaScript (func )
191
+
192
+ @QtCore .pyqtSlot (str )
193
+ def authentificationDidNotSucceed (self , errorMessage ):
194
+ msgBox = QtGui .QMessageBox ()
195
+ msgBox .setText (errorMessage )
196
+ msgBox .exec_ ()
197
+
198
+ @QtCore .pyqtSlot (str , str )
199
+ def alertTitleWithMessage (self , title , message ):
200
+ msgBox = QtGui .QMessageBox ()
201
+ msgBox .setText (title )
202
+ msgBox .setInformativeText (message )
203
+ msgBox .exec_ ()
204
+
205
+ def logout (self , sender ):
206
+ print "logout is not implemented yet"
207
+
208
+
209
+ class Console (QtCore .QObject ):
210
+
211
+ @QtCore .pyqtSlot (str )
212
+ def log (self , string ):
213
+ print "<js>: " + string
214
+
215
+ @QtCore .pyqtSlot (str )
216
+ def error (self , string ):
217
+ print "<js ERROR>: " + string
218
+
219
+ @QtCore .pyqtSlot (str )
220
+ def warn (self , string ):
221
+ print "<js WARN>: " + string
222
+
223
+ @QtCore .pyqtSlot (str )
224
+ def notice (self , string ):
225
+ print "<js NOTICE>: " + string
226
+
227
+ @QtCore .pyqtSlot (str )
228
+ def debug (self , string ):
229
+ print "<js DEBUG>: " + string
230
+
231
+
232
+ if __name__ == "__main__" :
233
+ Tentia ()
0 commit comments