From e8cabc03d39bb7103df545da4c8ccb24d68be6ef Mon Sep 17 00:00:00 2001 From: Et0h Date: Fri, 11 Jul 2014 20:44:01 +0100 Subject: [PATCH] New GuiConfig etc, upver to 1.2.6 --- buildPy2exe.py | 3 +- resources/bullet_black.png | Bin 0 -> 211 bytes resources/cog_delete.png | Bin 0 -> 847 bytes resources/comments.png | Bin 0 -> 557 bytes resources/eye.png | Bin 0 -> 750 bytes resources/film_link.png | Bin 0 -> 830 bytes resources/house.png | Bin 0 -> 806 bytes syncplay/__init__.py | 2 +- syncplay/client.py | 18 +- syncplay/constants.py | 32 +- syncplay/messages.py | 45 ++- syncplay/players/mpc.py | 3 - syncplay/players/mplayer.py | 1 - syncplay/players/vlc.py | 1 - syncplay/ui/ConfigurationGetter.py | 42 ++- syncplay/ui/GuiConfiguration.py | 490 ++++++++++++++++++++--------- syncplay/ui/gui.py | 58 +++- syncplay/utils.py | 4 +- 18 files changed, 491 insertions(+), 208 deletions(-) create mode 100644 resources/bullet_black.png create mode 100644 resources/cog_delete.png create mode 100644 resources/comments.png create mode 100644 resources/eye.png create mode 100644 resources/film_link.png create mode 100644 resources/house.png diff --git a/buildPy2exe.py b/buildPy2exe.py index ae7f4f5..699c137 100644 --- a/buildPy2exe.py +++ b/buildPy2exe.py @@ -578,7 +578,8 @@ guiIcons = ['resources/accept.png', 'resources/arrow_undo.png', 'resources/clock 'resources/folder_explore.png', 'resources/help.png', 'resources/table_refresh.png', 'resources/timeline_marker.png','resources/control_play_blue.png', 'resources/mpc-hc.png','resources/mpc-hc64.png','resources/mplayer.png', - 'resources/mpv.png','resources/vlc.png' + 'resources/mpv.png','resources/vlc.png', 'resources/house.png', 'resources/film_link.png', + 'resources/eye.png', 'resources/comments.png', 'resources/cog_delete.png', 'resources/bullet_black.png' ] resources = ["resources/icon.ico", "resources/syncplay.png"] resources.extend(guiIcons) diff --git a/resources/bullet_black.png b/resources/bullet_black.png new file mode 100644 index 0000000000000000000000000000000000000000..57619706d10d9736b1849a83f2c5694fbe09c53b GIT binary patch literal 211 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!60wlNoGJgf6SkfJR9T^zbpD<_bdI{u9mbgZg z1m~xflqVLYGB~E>C#5QQ<|d}62BjvZR2H60wE-$h^>lFz(Kw&{<9vg>5sw~gS5O!4 zr|{HuUFIBKiQyL}eBJ-L{`UVT|6_O~L{G%N{Wbre{kQtZ_0LvEh+9wmSwoOxbVANu8-ICvC9OZP{@IRIMx}06RoYSO|-wdx|%W=3>I87B3X;u?cVu^ z;VyxF2;9b|J!~>#$>nkxsI*$GOl#-o=X+S&e!t&$gfL`&i~u zsRYGh5fnus!hPJgpcSsMv2k#EdU}ko0zHtGOC%EHg^{A!Y!*3=Bk!t;!{MNHk@g~y z2m}IwDw1%=pitc_W_G{D{G&il8C{Xwocj8wwNOO=jZ1qtXAtNDN$f_3b9yBRcuLaf+-$^4woBr_S;YlEx^y^MLD~>^I9dCo11%s zD&sf-J3c;EC!nGep|SJt`oQ_@73jlX0pi~POgA7c*kE&E`L}uxFarexVtT!vE)|5s z;XF=Y=;`TUL;&dnsI%Aso($J=5#CyXS6Exkg4gTyWipxP7|vlsL&N?0`ufe@-d?(u zkQ{#`KYZH9i_y_eG49s=LNp*;OMt7gCr{Rxm*rXsT4${yX7A% zfy$qf9&)?}vKa=y;!H;A_w0Y4^U%=H0D}AJh#6!4Va@lZeCFUKFEg9WSL2BK@OYsz Z`4?5=&N;mrg`ofd002ovPDHLkV1fozjIRIy literal 0 HcmV?d00001 diff --git a/resources/comments.png b/resources/comments.png new file mode 100644 index 0000000000000000000000000000000000000000..39433cf78a3e9869f24b0a95f04b1819391596e8 GIT binary patch literal 557 zcmV+|0@D47P)kO-!8JjERGZgNx4o8zwI5pnrkJT^AW7B+k01lLkoCLBu@bfRhnJSkT}{ z5cwz-C?AEk;`Q7|NyO0V@Jst%?>X<@)8|?6hNplZoH}p}R=_wBd4A);huvr*D{8ta zv>weaRZy(zA{a{x)NMK$oUyoq;&Q_jA9Yid>V_!Q3{lkDazCTg+2GL8fKO$yVv7pZ zw#ZdlB3o|B^q?JFdAt+nq80!As0d}1Z|KFR(*lEh^G}{es&~_I}wY;n4d5jAs0d}gj@(+ z%6*K*29I(Myv%_UPWDD&5qS@s3~ZAJGDH vT*SlN0ce3)r#d%-F%SaNZe6;L@E^Vb!Ji3~dec0&00000NkvXXu0mjflI-*P literal 0 HcmV?d00001 diff --git a/resources/eye.png b/resources/eye.png new file mode 100644 index 0000000000000000000000000000000000000000..564a1a9714ff37aee1c8758109113e434eff7862 GIT binary patch literal 750 zcmVWW=I5Rl}zuENrQ28Pt;CX(qKOcDU|M8F&Z%jVGSZA7t& zSX&s1bi|{*v*DgAz3ST9+K6Us3~0Q9*~BWe6PID=&0x|wWdf!IWgI(}6lv9v-FpSS zw1U9OL{Ex%ACuJL>=wxTZg0 zEf8`!jsrze5UvA~SqG-HeEY!{P)iC{?3#nq?S616TB~hnMW{0-6j9tLvf?&u+XiC{ z?O_E0jiYQZlqIojGL$5a1qk9N)mlxpmZq1W6gHT`ec`8K>j$jl3}`WfukS z{=!u2#P1a^U!H8Xl5T`7??NT1t zUc_pqB=&-xQ}oxwg~5^6HaUDuDLGXE;y3!@QP_pOFSc-kKKIu gX8xa5{%_a#2W_ovs9z>%07*qoM6N<$f|edvg8%>k literal 0 HcmV?d00001 diff --git a/resources/film_link.png b/resources/film_link.png new file mode 100644 index 0000000000000000000000000000000000000000..0f24e86e4028717876f6650558d2451ec644bd4e GIT binary patch literal 830 zcmV-E1Ht@>P)eQoKk~sHiA| zy6GknK~N$Di6V+pM#z)~t~qt4t~PV$oSpR?5enUb-^F>~=l_46=Y8InX>V^2D~jSG z7J7SoD^TDI27})uNve=#`TNk&(C+{DG$i!oa=918m8Pbqd?5o8t8^15H}7dk$P;JC zU9z=w%S9{?QO-kDfL7aml<9%y8}BtFt|h8A8?YptARZEtkJ`sVMo0;4u~o7C+z3$g3Wm`ywrg46(2578e}zzE>{|?IQQR=7K4GtbjwyzWa%4Ap;|E+HSYk4Bw0wm;p;Ih?Q!L8e7QV7cmfxMrH4vfqeo^LCOIl4YbAj2s`x* z4h23>Qk8=g7u;e%?mF5iC%6yUPV7M=bW?HImnZPWX2zR^X&8-0eL9`4s;{rF?Ca~x zClZO}cs$-24u>CbZnwKb6%)MSXsR^vb_9pDMqIpb4o;^N2Gb7EJux^O4p%4?5d32QMl4!Ru*;t~bnPGpGe5lS$Bf`J>Tj&QeIm zWHRxp0coWtI-TxW?A;nT_m6dhvD>SRA~ERd>Ox6L$@*F*lL5=JJXO=L{!1KIqEP)v;U&v3%|^C`Ga3?LtY&4dQB4Oz;1v;J%z!D&%WRH@BZ?x; z3)8@IUIv@hG|@IwyHLC`l{1<4BK>wam95g|i|?Cfzt876&-Zx_0f5*l-9`IJI&mHu zE6$@xB)6N}7VeR;!X8D!TAw;;&0Bsj?A071cO>X3K0wl7WZ1;Tg!4LHyNcnzoeQ7t zNW`aSlm8WXYkek&ir$13=ngczvf zV0vnjNpCF&K8px}dunv+`LIb-sOC$_jD(;IBI$xC|7`(+9cA>Vir_V#z{?k7SX^Ah z^71m~W@q439Ycqfhi7+gp#A14n1n1!e>$EdeATG|f798Y=ggzwEKH2Q!qU2QA(Se?dwqG69%>n$6rtE z%F(845Az8c{w(XgimJg96!jLMz?zS6I1HUm2baqQx7&@nx;lhHA!r6vs2|fqJETOu zLxeu2OQ(3(au%dg>AcZsWI(zXn9XJg1cLe8k~0h0wOL=&HK}7X k{AKr*U4z7Szv)i%9gTgghwgU$Q~&?~07*qoM6N<$g31kYk^lez literal 0 HcmV?d00001 diff --git a/syncplay/__init__.py b/syncplay/__init__.py index c2a8ec7..48abde3 100644 --- a/syncplay/__init__.py +++ b/syncplay/__init__.py @@ -1,3 +1,3 @@ -version = '1.2.8' +version = '1.2.9' milestone = 'Hammer' projectURL = 'http://syncplay.pl/' diff --git a/syncplay/client.py b/syncplay/client.py index b0546ea..7aaf40d 100644 --- a/syncplay/client.py +++ b/syncplay/client.py @@ -55,6 +55,12 @@ class SyncClientFactory(ClientFactory): class SyncplayClient(object): def __init__(self, playerClass, ui, config): + constants.SHOW_OSD = config['showOSD'] + constants.SHOW_OSD_WARNINGS = config['showOSDWarnings'] + constants.SHOW_SLOWDOWN_OSD = config['showSlowdownOSD'] + constants.SHOW_DIFFERENT_ROOM_OSD = config['showDifferentRoomOSD'] + constants.SHOW_SAME_ROOM_OSD = config['showSameRoomOSD'] + constants.SHOW_DURATION_NOTIFICATION = config['showDurationNotification'] self.lastLeftTime = 0 self.lastLeftUser = u"" self.protocolFactory = SyncClientFactory(self) @@ -226,11 +232,10 @@ class SyncplayClient(object): self._lastGlobalUpdate = time.time() if doSeek: madeChangeOnPlayer = self._serverSeeked(position, setBy) - if diff > self._config['rewindThreshold'] and not doSeek and not self._config['rewindThreshold'] == 0.0: + if diff > self._config['rewindThreshold'] and not doSeek and not self._config['rewindOnDesync'] == False: madeChangeOnPlayer = self._rewindPlayerDueToTimeDifference(position, setBy) - if self._player.speedSupported and not doSeek and not paused: - if self._config['slowMeOnDesync'] == constants.OPTION_ALWAYS or (self._config['slowMeOnDesync'] == constants.OPTION_AUTO and self._player.speedRecommended): - madeChangeOnPlayer = self._slowDownToCoverTimeDifference(diff, setBy) + if (self._player.speedSupported and not doSeek and not paused and not self._config['slowOnDesync'] == False): + madeChangeOnPlayer = self._slowDownToCoverTimeDifference(diff, setBy) if paused == False and pauseChanged: madeChangeOnPlayer = self._serverUnpaused(setBy) elif paused == True and pauseChanged: @@ -357,6 +362,9 @@ class SyncplayClient(object): def getRoom(self): return self.userlist.currentUser.room + def getConfig(self): + return self._config + def getUserList(self): if self._protocol and self._protocol.logged: self._protocol.sendList() @@ -501,7 +509,7 @@ class SyncplayUserlist(object): def __showUserChangeMessage(self, username, room, file_, oldRoom=None): if room: if self.isRoomSame(room) or self.isRoomSame(oldRoom): - showOnOSD = constants.SHOW_SAME_ROOM_OSD + showOnOSD = constants.SHOW_OSD_WARNINGS else: showOnOSD = constants.SHOW_DIFFERENT_ROOM_OSD hideFromOSD = not showOnOSD diff --git a/syncplay/constants.py b/syncplay/constants.py index 30e0de7..ccfad81 100644 --- a/syncplay/constants.py +++ b/syncplay/constants.py @@ -10,29 +10,33 @@ DEFAULT_CONFIG_NAME_WINDOWS = "syncplay.ini" DEFAULT_CONFIG_NAME_LINUX = ".syncplay" RECENT_CLIENT_THRESHOLD = "1.2.8" #This and higher considered 'recent' clients (no warnings) WARN_OLD_CLIENTS = True #Use MOTD to inform old clients to upgrade -SHOW_OSD = True # Sends Syncplay messages to media player OSD -SHOW_OSD_WARNINGS = True # Show warnings if playing different file, alone in room -SHOW_SLOWDOWN_OSD = True # Show notifications of slowing down / reverting on time difference -SHOW_SAME_ROOM_OSD = True # Show OSD notifications for events relating to room user is in -SHOW_DIFFERENT_ROOM_OSD = False # Show OSD notifications for events relating to room user is not in LIST_RELATIVE_CONFIGS = True # Print list of relative configs loaded SHOW_CONTACT_INFO = True # Displays dev contact details below list in GUI SHOW_BUTTON_LABELS = True # If disabled, only shows icons for main GUI buttons SHOW_TOOLTIPS = True +#Overriden by config +SHOW_OSD = True # Sends Syncplay messages to media player OSD +SHOW_OSD_WARNINGS = True # Show warnings if playing different file, alone in room +SHOW_SLOWDOWN_OSD = True # Show notifications of slowing down / reverting on time difference +SHOW_SAME_ROOM_OSD = True # Show OSD notifications for events relating to room user is in +SHOW_DIFFERENT_ROOM_OSD = False # Show OSD notifications for events relating to room user is not in +SHOW_DURATION_NOTIFICATION = True + #Changing these might be ok DEFAULT_REWIND_THRESHOLD = 4 +MINIMUM_REWIND_THRESHOLD = 3 SEEK_THRESHOLD = 1 SLOWDOWN_RATE = 0.95 DEFAULT_SLOWDOWN_KICKIN_THRESHOLD = 1.5 +MINIMUM_SLOWDOWN_THRESHOLD = 1.3 SLOWDOWN_RESET_THRESHOLD = 0.1 -MINIMUM_SLOWDOWN_THRESHOLD = 0.2 DIFFFERENT_DURATION_THRESHOLD = 2.5 PROTOCOL_TIMEOUT = 12.5 RECONNECT_RETRIES = 10 SERVER_STATE_INTERVAL = 1 WARNING_OSD_MESSAGES_LOOP_INTERVAL = 1 -MERGE_PLAYPAUSE_BUTTONS = False +MERGE_PLAYPAUSE_BUTTONS = True SYNC_ON_PAUSE = True # Client seek to global position - subtitles may disappear on some media players #Usually there's no need to adjust these FILENAME_STRIP_REGEX = u"[-~_\.\[\](): ]" @@ -87,6 +91,17 @@ VLC_MIN_PORT = 10000 VLC_MAX_PORT = 55000 #These are not changes you're looking for +STYLE_TABLIST = "QListWidget::item { color: black; border-style: solid; border-width: 1px; border-radius: 2px; } QListWidget::item:selected { background: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(242, 248, 255, 255), stop:1 rgba(208, 229, 255, 255)); border-color: #84ACDD; } QListWidget::item:!selected { border-color: transparent; } QListWidget::item:!selected:hover { background: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(248, 248, 248, 255), stop:1 rgba(229, 229, 229, 255)); border-color: silver; }" +STYLE_SUBCHECKBOX = "QCheckBox, QLabel {{ margin-left: 8px; padding-left: 18px; background:url('{}') left no-repeat }}" #Graphic path +STYLE_SUBLABEL = "QCheckBox, QLabel {{ margin-left: 8px; padding-left: 14px; background:url('{}') left no-repeat }}" #Graphic path +STYLE_ERRORLABEL = "QLabel { color : black; border-style: outset; border-width: 2px; border-radius: 7px; border-color: red; padding: 2px; background: #FFAAAA; }" +STYLE_SUCCESSLABEL = "QLabel { color : black; border-style: outset; border-width: 2px; border-radius: 7px; border-color: green; padding: 2px; background: #AAFFAA; }" +STYLE_NOTIFICATIONBOX = "Username { color: #367AA9; font-weight:bold; }" +STYLE_USERNAME = "color: #367AA9; font-weight:bold;" +STYLE_ERRORNOTIFICATION = "color: red;" +STYLE_DIFFERENTITEM_COLOR = 'red' +STYLE_NOFILEITEM_COLOR = 'blue' + MPLAYER_SLAVE_ARGS = ['-slave', '--hr-seek=always', '-nomsgcolor', '-msglevel', 'all=1:global=4:cplayer=4'] # --quiet works with both mpv 0.2 and 0.3 MPV_SLAVE_ARGS = ['--slave-broken', '--hr-seek=always', '--quiet', '--keep-open'] @@ -104,6 +119,3 @@ PRIVACY_SENDRAW_MODE = "SendRaw" PRIVACY_SENDHASHED_MODE = "SendHashed" PRIVACY_DONTSEND_MODE = "DoNotSend" PRIVACY_HIDDENFILENAME = "**Hidden filename**" -OPTION_AUTO = "Automatic" -OPTION_ALWAYS = "Always" -OPTION_NEVER = "Never" diff --git a/syncplay/messages.py b/syncplay/messages.py index aa6ea2c..997c77d 100644 --- a/syncplay/messages.py +++ b/syncplay/messages.py @@ -4,6 +4,8 @@ from syncplay import constants en = { # Client notifications + "config-cleared-notification" : "Settings cleared. Changes will be saved when you store a valid configuration.", + "relative-config-notification" : "Loaded relative configuration file(s): {}", "connection-attempt-notification" : "Attempting to connect to {}:{}", # Port, IP @@ -131,14 +133,25 @@ en = { "privacy-dontsend-option" : "Don't send", "filename-privacy-label" : "Filename information:", "filesize-privacy-label" : "File size information:", - "slowdown-label" : "Slow down on desync:", - "slowdown-auto-option" : "Automatic", - "slowdown-always-option" : "Always", - "slowdown-never-option" : "Never", + "slowondesync-label" : "Slow down on minor desync (not supported on MPC-HC)", "dontslowdownwithme-label" : "Never slow down or rewind others", - "pauseonleave-label" : "Pause when user leaves", - "forceguiprompt-label" : "Do not always show this dialog", # (Inverted) - "nostore-label" : "Do not store this configuration", # (Inverted) + "pauseonleave-label" : "Pause when user leaves (e.g. if they are disconnected)", + "forceguiprompt-label" : "Don't always show this dialog", # (Inverted) + "nostore-label" : "Don't store this configuration", # (Inverted) + "showosd-label" : "Enable OSD Messages", + + "showosdwarnings-label" : "Include warnings (e.g. when files are different)", + "showsameroomosd-label" : "Include events in your room", + "showdifferentroomosd-label" : "Include events in other rooms", + "showslowdownosd-label" :"Include slowing down / reverting notification", + "showcontactinfo-label" : "Show contact info box", + "showbuttonlabels-label" : "Show labels on buttons", + "showtooltips-label" : "Show tooltips", + "showdurationnotification-label" : "Warn about media duration mismatches", + "basics-label" : "Basics", + "sync-label" : "Sync", + "messages-label" : "Messages", + "privacy-label" : "Privacy", "help-label" : "Help", "run-label" : "Run Syncplay", @@ -186,20 +199,28 @@ en = { "more-tooltip" : "Display less frequently used settings.", "slowdown-threshold-tooltip" : "Time ahead of slowest client before temporarily reducing playback speed (default: {} secs).".format(constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD), - "rewind-threshold-tooltip" : "Time ahead slowest client before seeking to get back in sync (default: {} secs). 'Never' can result in major desync!".format(constants.DEFAULT_REWIND_THRESHOLD), + "rewind-threshold-tooltip" : "Time ahead slowest client before seeking to get back in sync (default: {} secs).".format(constants.DEFAULT_REWIND_THRESHOLD), "filename-privacy-tooltip" : "Privacy mode for sending currently playing filename to server.", "filesize-privacy-tooltip" : "Privacy mode for sending size of currently playing file to server.", "privacy-sendraw-tooltip" : "Send this information without obfuscation. This is the default option with most functionality.", "privacy-sendhashed-tooltip" : "Send a hashed version of the information, making it less visible to other clients.", "privacy-dontsend-tooltip" : "Do not send this information to the server. This provides for maximum privacy.", - "slowdown-tooltip" : "Reduce playback rate temporarily when needed to bring you back in sync with other viewers.", - "slowdown-auto-tooltip" : "Slow down on desync unless it causes problems (i.e. MPC-HC).", - "slowdown-always-tooltip" : "Always slow down on desync (even on players where this causes playback issues).", - "slowdown-never-tooltip" : "Never slow down on desync (even on players where this is probably better than rewinding).", + "slowondesync-tooltip" : "Reduce playback rate temporarily when needed to bring you back in sync with other viewers. Not supported on MPC-HC.", "dontslowdownwithme-tooltip" : "Means others do not get slowed down or rewinded if your playback is lagging.", "pauseonleave-tooltip" : "Pause playback if you get disconnected or someone leaves from your room.", + "rewindondesync-label" : "Rewind on major desync (highly recommended)", "forceguiprompt-tooltip" : "Configuration dialogue is not shown when opening a file with Syncplay.", # (Inverted) "nostore-tooltip" : "Run Syncplay with the given configuration, but do not permanently store the changes.", # (Inverted) + "rewindondesync-tooltip" : "Jump back when needed to get back in sync. Disabling this option can result in major desyncs!", + "showosd-tooltip" : "Sends Syncplay messages to media player OSD.", + "showosdwarnings-tooltip" : "Show warnings if playing different file, alone in room.", + "showsameroomosd-tooltip" : "Show OSD notifications for events relating to room user is in.", + "showdifferentroomosd-tooltip" : "Show OSD notifications for events relating to room user is not in.", + "showslowdownosd-tooltip" :"Show notifications of slowing down / reverting on time difference.", + "showcontactinfo-tooltip" : "Show information box about contacting Syncplay developers in main Syncplay window.", + "showbuttonlabels-tooltip" : "Show the text alongside the icons for buttons in the main UI.", + "showtooltips-tooltip" : "Show tooltip help messages when you mouseover an input element in Syncplay.", + "showdurationnotification-tooltip" : "Useful for when a segment in a multi-part file is missing, but can result in false positives.", "help-tooltip" : "Opens the Syncplay.pl user guide.", diff --git a/syncplay/players/mpc.py b/syncplay/players/mpc.py index ae7f75b..0dfef45 100644 --- a/syncplay/players/mpc.py +++ b/syncplay/players/mpc.py @@ -306,7 +306,6 @@ class MpcHcApi: class MPCHCAPIPlayer(BasePlayer): speedSupported = False - speedRecommended = False def __init__(self, client): from twisted.internet import reactor @@ -383,8 +382,6 @@ class MPCHCAPIPlayer(BasePlayer): self.__mpcVersion = self._mpcApi.version.split('.') if self.__mpcVersion[0:3] == ['1', '6', '4']: self.__switchPauseCalls = True - if self.__mpcVersion[0:3] >= ['1', '6', '5']: - self.speedSupported = True if filePath: self.openFile(filePath) diff --git a/syncplay/players/mplayer.py b/syncplay/players/mplayer.py index 1cb3c32..f213209 100644 --- a/syncplay/players/mplayer.py +++ b/syncplay/players/mplayer.py @@ -8,7 +8,6 @@ import os class MplayerPlayer(BasePlayer): speedSupported = True - speedRecommended = True RE_ANSWER = re.compile(constants.MPLAYER_ANSWER_REGEX) SLAVE_ARGS = constants.MPLAYER_SLAVE_ARGS POSITION_QUERY = 'time_pos' diff --git a/syncplay/players/vlc.py b/syncplay/players/vlc.py index dac4649..ba3145f 100644 --- a/syncplay/players/vlc.py +++ b/syncplay/players/vlc.py @@ -14,7 +14,6 @@ import time class VlcPlayer(BasePlayer): speedSupported = True - speedRecommended = True RE_ANSWER = re.compile(constants.VLC_ANSWER_REGEX) SLAVE_ARGS = constants.VLC_SLAVE_ARGS if not sys.platform.startswith('darwin'): diff --git a/syncplay/ui/ConfigurationGetter.py b/syncplay/ui/ConfigurationGetter.py index 5da8ac8..c7d610b 100644 --- a/syncplay/ui/ConfigurationGetter.py +++ b/syncplay/ui/ConfigurationGetter.py @@ -35,15 +35,28 @@ class ConfigurationGetter(object): "playerClass": None, "slowdownThreshold": constants.DEFAULT_SLOWDOWN_KICKIN_THRESHOLD, "rewindThreshold": constants.DEFAULT_REWIND_THRESHOLD, - "slowMeOnDesync": constants.OPTION_AUTO, + "rewindOnDesync": True, + "slowOnDesync": True, "dontSlowDownWithMe": False, "filenamePrivacyMode": constants.PRIVACY_SENDRAW_MODE, "filesizePrivacyMode": constants.PRIVACY_SENDRAW_MODE, "pauseOnLeave": False, "clearGUIData": False, - "language" : "" + "language" : "", + "resetConfig" : False, + "showOSD" : True, + "showOSDWarnings" : True, + "showSlowdownOSD" : True, + "showDifferentRoomOSD" : False, + "showSameRoomOSD" : True, + "showContactInfo" : True, + "showButtonLabels" : True, + "showTooltips" : True, + "showDurationNotification" : True } + self._defaultConfig = self._config.copy() + # # Custom validation in self._validateArguments # @@ -62,18 +75,39 @@ class ConfigurationGetter(object): "noStore", "dontSlowDownWithMe", "pauseOnLeave", - "clearGUIData" + "clearGUIData", + "rewindOnDesync", + "slowOnDesync", + "pauseOnLeave", + "clearGUIData", + "resetConfig", + "showOSD", + "showOSDWarnings", + "showSlowdownOSD", + "showDifferentRoomOSD", + "showSameRoomOSD", + "showContactInfo" , + "showButtonLabels", + "showTooltips", + "showDurationNotification" ] self._iniStructure = { "server_data": ["host", "port", "password"], - "client_settings": ["name", "room", "playerPath", "slowdownThreshold", "rewindThreshold", "slowMeOnDesync", "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "pauseOnLeave"], + "client_settings": ["name", "room", "playerPath", "slowdownThreshold", "rewindThreshold", "slowOnDesync", "rewindOnDesync", "dontSlowDownWithMe", "forceGuiPrompt", "filenamePrivacyMode", "filesizePrivacyMode", "pauseOnLeave"], + "gui": ["showOSD", "showOSDWarnings", "showSlowdownOSD", "showDifferentRoomOSD", "showSameRoomOSD", "showContactInfo" , "showButtonLabels", "showTooltips", "showDurationNotification"], "general": ["language"] } self._playerFactory = PlayerFactory() def _validateArguments(self): + if self._config['resetConfig']: + language = self._config['language'] + self._config = self._defaultConfig + self._config['language'] = language + raise InvalidConfigValue("*"+getMessage("config-cleared-notification")) + def _isPortValid(varToTest): try: if varToTest == "" or varToTest is None: diff --git a/syncplay/ui/GuiConfiguration.py b/syncplay/ui/GuiConfiguration.py index 6d2f5da..1e6c8b0 100644 --- a/syncplay/ui/GuiConfiguration.py +++ b/syncplay/ui/GuiConfiguration.py @@ -9,7 +9,8 @@ from syncplay.messages import getMessage from syncplay import constants class GuiConfiguration: - def __init__(self, config, error=None): + def __init__(self, config, error=None, defaultConfig=None): + self.defaultConfig = defaultConfig self.config = config self._availablePlayerPaths = [] self.error = error @@ -18,7 +19,7 @@ class GuiConfiguration: def run(self): if QCoreApplication.instance() is None: self.app = QtGui.QApplication(sys.argv) - dialog = ConfigDialog(self.config, self._availablePlayerPaths, self.error) + dialog = ConfigDialog(self.config, self._availablePlayerPaths, self.error, self.defaultConfig) dialog.exec_() def setAvailablePaths(self, paths): @@ -39,21 +40,25 @@ class ConfigDialog(QtGui.QDialog): if self.moreToggling == False: self.moreToggling = True - if self.showmoreCheckbox.isChecked() and self.showmoreCheckbox.isVisible(): - self.showmoreCheckbox.setChecked(False) - self.moreSettingsGroup.setChecked(True) - self.moreSettingsGroup.show() - self.showmoreCheckbox.hide() + if self.showmoreCheckbox.isChecked(): + self.tabListFrame.show() + self.resetButton.show() + self.nostoreCheckbox.show() + self.alwaysshowCheckbox.show() self.saveMoreState(True) + self.tabListWidget.setCurrentRow(0) + self.ensureTabListIsVisible() else: - self.moreSettingsGroup.setChecked(False) - self.moreSettingsGroup.hide() - self.showmoreCheckbox.show() + self.tabListFrame.hide() + self.resetButton.hide() + self.nostoreCheckbox.hide() + self.alwaysshowCheckbox.hide() self.saveMoreState(False) + self.stackedLayout.setCurrentIndex(0) - self.moreToggling = False self.adjustSize() self.setFixedSize(self.sizeHint()) + self.moreToggling = False def runButtonTextUpdate(self): if self.nostoreCheckbox.isChecked(): @@ -181,7 +186,10 @@ class ConfigDialog(QtGui.QDialog): def _saveDataAndLeave(self): self.processWidget(self, lambda w: self.saveValues(w)) - self.config['host'] = self.hostTextbox.text() if ":" in self.hostTextbox.text() else self.hostTextbox.text() + ":" + unicode(constants.DEFAULT_PORT) + if self.hostTextbox.text(): + self.config['host'] = self.hostTextbox.text() if ":" in self.hostTextbox.text() else self.hostTextbox.text() + ":" + unicode(constants.DEFAULT_PORT) + else: + self.config['host'] = None self.config['playerPath'] = unicode(self.executablepathCombobox.currentText()) if self.mediapathTextbox.text() == "": self.config['file'] = None @@ -234,7 +242,7 @@ class ConfigDialog(QtGui.QDialog): def loadTooltips(self, widget): tooltipName = widget.objectName().lower().split(":")[0] + "-tooltip" - if tooltipName[:1] == "*" or tooltipName[:1] == "!": + if tooltipName[:1] == "*" or tooltipName[:1] == "!": # * is for notifications tooltipName = tooltipName[1:] widget.setToolTip(getMessage(tooltipName)) @@ -276,36 +284,13 @@ class ConfigDialog(QtGui.QDialog): elif isinstance(widget, QLineEdit): self.config[valueName] = widget.text() - def __init__(self, config, playerpaths, error): - - from syncplay import utils - self.config = config - self.datacleared = False - - if config['clearGUIData'] == True: - settings = QSettings("Syncplay", "PlayerList") - settings.clear() - settings = QSettings("Syncplay", "MediaBrowseDialog") - settings.clear() - settings = QSettings("Syncplay", "MainWindow") - settings.clear() - settings = QSettings("Syncplay", "MoreSettings") - settings.clear() - self.datacleared = True - self.QtGui = QtGui - self.error = error - if sys.platform.startswith('windows'): - resourcespath = utils.findWorkingDir() + "\\resources\\" - else: - resourcespath = utils.findWorkingDir() + "/resources/" - self.resourcespath = resourcespath - - super(ConfigDialog, self).__init__() - - self.setWindowTitle(getMessage("config-window-title")) - self.setWindowFlags(self.windowFlags() & Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint) - self.setWindowIcon(QtGui.QIcon(resourcespath + "syncplay.png")) - + def addBasicTab(self): + config = self.config + playerpaths = self.playerpaths + resourcespath = self.resourcespath + error = self.error + if self.datacleared == True: + error = "*{}".format(getMessage("gui-data-cleared-notification")) if config['host'] == None: host = "" elif ":" in config['host']: @@ -356,8 +341,7 @@ class ConfigDialog(QtGui.QDialog): self.executablepathCombobox.setEditable(True) self.executablepathCombobox.currentIndexChanged.connect(self.updateExecutableIcon) self.executablepathCombobox.setEditText(self._tryToFillPlayerPath(config['playerPath'], playerpaths)) - self.executablepathCombobox.setMinimumWidth(200) - self.executablepathCombobox.setMaximumWidth(200) + self.executablepathCombobox.setFixedWidth(165) self.executablepathCombobox.editTextChanged.connect(self.updateExecutableIcon) self.executablepathLabel = QLabel(getMessage("executable-path-label"), self) @@ -383,11 +367,55 @@ class ConfigDialog(QtGui.QDialog): self.mediaplayerSettingsLayout.addWidget(self.mediabrowseButton , 1, 3) self.mediaplayerSettingsGroup.setLayout(self.mediaplayerSettingsLayout) - self.moreSettingsGroup = QtGui.QGroupBox(getMessage("more-title")) + self.showmoreCheckbox = QCheckBox(getMessage("more-title")) + self.showmoreCheckbox.setObjectName("!more") - self.moreSettingsGroup.setCheckable(True) + self.basicOptionsFrame = QtGui.QFrame() + self.basicOptionsLayout = QtGui.QVBoxLayout() + if error: + self.errorLabel = QLabel(self) + if error[:1] != "*": + self.errorLabel.setStyleSheet(constants.STYLE_ERRORLABEL) + else: + error = error[1:] + self.errorLabel.setStyleSheet(constants.STYLE_SUCCESSLABEL) + self.errorLabel.setText(error) + self.errorLabel.setAlignment(Qt.AlignCenter) + + self.basicOptionsLayout.addWidget(self.errorLabel, 0, 0) + self.basicOptionsLayout.addWidget(self.connectionSettingsGroup) + self.basicOptionsLayout.addSpacing(12) + self.basicOptionsLayout.addWidget(self.mediaplayerSettingsGroup) + + self.basicOptionsFrame.setLayout(self.basicOptionsLayout) + self.stackedLayout.addWidget(self.basicOptionsFrame) + + def addSyncTab(self): + self.syncSettingsFrame = QtGui.QFrame() + self.syncSettingsLayout = QtGui.QVBoxLayout() + + self.desyncSettingsGroup = QtGui.QGroupBox("If others are lagging behind...") + self.desyncOptionsFrame = QtGui.QFrame() + self.desyncSettingsOptionsLayout = QtGui.QHBoxLayout() + config = self.config + + self.slowdownCheckbox = QCheckBox(getMessage("slowondesync-label")) + self.slowdownCheckbox.setObjectName("slowOnDesync") + self.rewindCheckbox = QCheckBox(getMessage("rewindondesync-label")) + self.rewindCheckbox.setObjectName("rewindOnDesync") + + self.spaceLabel = QLabel() + self.spaceLabel.setFixedHeight(5) + + self.desyncSettingsLayout = QtGui.QGridLayout() + self.desyncSettingsLayout.setSpacing(2) + self.desyncFrame = QtGui.QFrame() + self.desyncFrame.setLineWidth(0) + self.desyncFrame.setMidLineWidth(0) self.slowdownThresholdLabel = QLabel(getMessage("slowdown-threshold-label"), self) + self.slowdownThresholdLabel.setStyleSheet(constants.STYLE_SUBLABEL.format(self.posixresourcespath + "bullet_black.png")) + self.slowdownThresholdSpinbox = QDoubleSpinBox() try: self.slowdownThresholdSpinbox.setValue(float(config['slowdownThreshold'])) @@ -402,6 +430,7 @@ class ConfigDialog(QtGui.QDialog): self.slowdownThresholdSpinbox.adjustSize() self.rewindThresholdLabel = QLabel(getMessage("rewind-threshold-label"), self) + self.rewindThresholdLabel.setStyleSheet(constants.STYLE_SUBLABEL.format(self.posixresourcespath + "bullet_black.png")) self.rewindThresholdSpinbox = QDoubleSpinBox() try: self.rewindThresholdSpinbox.setValue(float(config['rewindThreshold'])) @@ -410,9 +439,8 @@ class ConfigDialog(QtGui.QDialog): self.rewindThresholdSpinbox.setSizePolicy(QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Minimum) self.rewindThresholdSpinbox.setMinimumWidth(80) self.rewindThresholdSpinbox.setMaximumWidth(80) - self.rewindThresholdSpinbox.setMinimum(0) + self.rewindThresholdSpinbox.setMinimum(constants.MINIMUM_REWIND_THRESHOLD) self.rewindThresholdSpinbox.setSingleStep(0.1) - self.rewindThresholdSpinbox.setSpecialValueText(getMessage("never-rewind-value")) self.rewindThresholdSpinbox.setSuffix(getMessage("seconds-suffix")) self.rewindThresholdSpinbox.adjustSize() @@ -421,14 +449,114 @@ class ConfigDialog(QtGui.QDialog): self.rewindThresholdLabel.setObjectName("rewind-threshold") self.rewindThresholdSpinbox.setObjectName("rewind-threshold") - self.slowdownLabel = QLabel(getMessage("slowdown-label"), self) - self.slowdownButtonGroup = QButtonGroup() - self.slowdownAutoOption = QRadioButton(getMessage("slowdown-auto-option")) - self.slowdownAlwaysOption = QRadioButton(getMessage("slowdown-always-option")) - self.slowdownNeverOption = QRadioButton(getMessage("slowdown-never-option")) - self.slowdownButtonGroup.addButton(self.slowdownAutoOption) - self.slowdownButtonGroup.addButton(self.slowdownAlwaysOption) - self.slowdownButtonGroup.addButton(self.slowdownNeverOption) + self.desyncSettingsLayout.addWidget(self.slowdownCheckbox, 0, 0, 1, 2, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.slowdownThresholdLabel, 1, 0, 1, 1, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.slowdownThresholdSpinbox, 1, 1, 1, 1, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.spaceLabel, 2, 0,1,2, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.rewindCheckbox, 3, 0,1,2, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.rewindThresholdLabel, 4, 0, 1, 1, Qt.AlignLeft) + self.desyncSettingsLayout.addWidget(self.rewindThresholdSpinbox, 4, 1, Qt.AlignLeft) + + self.desyncSettingsLayout.setAlignment(Qt.AlignLeft) + self.desyncSettingsGroup.setLayout(self.desyncSettingsLayout) + self.desyncSettingsOptionsLayout.addWidget(self.desyncFrame) + self.syncSettingsLayout.addWidget(self.desyncSettingsGroup) + self.desyncFrame.setLayout(self.syncSettingsLayout) + + self.othersyncSettingsGroup = QtGui.QGroupBox("Other sync options") + self.othersyncOptionsFrame = QtGui.QFrame() + self.othersyncSettingsLayout = QtGui.QGridLayout() + + + self.dontslowwithmeCheckbox = QCheckBox(getMessage("dontslowdownwithme-label")) + self.pauseonleaveCheckbox = QCheckBox(getMessage("pauseonleave-label")) + self.othersyncSettingsLayout.addWidget(self.dontslowwithmeCheckbox) + self.othersyncSettingsLayout.addWidget(self.pauseonleaveCheckbox) + self.dontslowwithmeCheckbox.setObjectName("dontSlowDownWithMe") + self.pauseonleaveCheckbox.setObjectName("pauseOnLeave") + + self.othersyncSettingsGroup.setLayout(self.othersyncSettingsLayout) + self.syncSettingsLayout.addWidget(self.othersyncSettingsGroup) + + self.syncSettingsFrame.setLayout(self.syncSettingsLayout) + self.desyncSettingsGroup.setMaximumHeight(self.desyncSettingsGroup.minimumSizeHint().height()) + self.syncSettingsLayout.setAlignment(Qt.AlignTop) + self.stackedLayout.addWidget(self.syncSettingsFrame) + + def addMessageTab(self): + self.messageFrame = QtGui.QFrame() + self.messageLayout = QtGui.QVBoxLayout() + + # OSD + self.osdSettingsGroup = QtGui.QGroupBox("On-screen Display settings") + self.osdSettingsLayout = QtGui.QVBoxLayout() + self.osdSettingsFrame = QtGui.QFrame() + + self.showOSDCheckbox = QCheckBox(getMessage("showosd-label")) + self.showOSDCheckbox.setObjectName("showOSD") + self.osdSettingsLayout.addWidget(self.showOSDCheckbox) + + self.showSameRoomOSDCheckbox = QCheckBox(getMessage("showsameroomosd-label")) + self.showSameRoomOSDCheckbox.setObjectName("showSameRoomOSD") + self.showSameRoomOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "bullet_black.png")) + self.osdSettingsLayout.addWidget(self.showSameRoomOSDCheckbox) + + self.showDifferentRoomOSDCheckbox = QCheckBox(getMessage("showdifferentroomosd-label")) + self.showDifferentRoomOSDCheckbox.setObjectName("showDifferentRoomOSD") + self.showDifferentRoomOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "bullet_black.png")) + self.osdSettingsLayout.addWidget(self.showDifferentRoomOSDCheckbox) + + self.slowdownOSDCheckbox = QCheckBox(getMessage("showslowdownosd-label")) + self.slowdownOSDCheckbox.setObjectName("showSlowdownOSD") + self.slowdownOSDCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "bullet_black.png")) + self.osdSettingsLayout.addWidget(self.slowdownOSDCheckbox) + + self.showOSDWarningsCheckbox = QCheckBox(getMessage("showosdwarnings-label")) + self.showOSDWarningsCheckbox.setObjectName("showOSDWarnings") + self.showOSDWarningsCheckbox.setStyleSheet(constants.STYLE_SUBCHECKBOX.format(self.posixresourcespath + "bullet_black.png")) + self.osdSettingsLayout.addWidget(self.showOSDWarningsCheckbox) + + self.osdSettingsGroup.setLayout(self.osdSettingsLayout) + self.osdSettingsLayout.setAlignment(Qt.AlignTop) + self.messageLayout.addWidget(self.osdSettingsGroup) + + # Other display + + self.displaySettingsGroup = QtGui.QGroupBox("Other display settings") + self.displaySettingsLayout = QtGui.QVBoxLayout() + self.displaySettingsFrame = QtGui.QFrame() + + self.showDurationNotificationCheckbox = QCheckBox(getMessage("showdurationnotification-label")) + self.showDurationNotificationCheckbox.setObjectName("showDurationNotification") + self.displaySettingsLayout.addWidget(self.showDurationNotificationCheckbox) + + self.showcontactinfoCheckbox = QCheckBox(getMessage("showcontactinfo-label")) + self.showcontactinfoCheckbox.setObjectName("showContactInfo") + self.displaySettingsLayout.addWidget(self.showcontactinfoCheckbox) + + self.showButtonLabelsCheckbox = QCheckBox(getMessage("showbuttonlabels-label")) + self.showButtonLabelsCheckbox.setObjectName("showButtonLabels") + self.displaySettingsLayout.addWidget(self.showButtonLabelsCheckbox) + + self.showTooltipsCheckbox = QCheckBox(getMessage("showtooltips-label")) + self.showTooltipsCheckbox.setObjectName("showTooltips") + self.displaySettingsLayout.addWidget(self.showTooltipsCheckbox) + + + self.displaySettingsGroup.setLayout(self.displaySettingsLayout) + self.displaySettingsLayout.setAlignment(Qt.AlignTop) + self.messageLayout.addWidget(self.displaySettingsGroup) + + # messageFrame + self.messageFrame.setLayout(self.messageLayout) + self.stackedLayout.addWidget(self.messageFrame) + + def addPrivacyTab(self): + self.privacySettingsGroup = QtGui.QGroupBox("Privacy settings") + self.privacySettingsLayout = QtGui.QVBoxLayout() + self.privacySettingsFrame = QtGui.QFrame() + self.privacyFrame = QtGui.QFrame() + self.privacyLayout = QtGui.QGridLayout() self.filenameprivacyLabel = QLabel(getMessage("filename-privacy-label"), self) self.filenameprivacyButtonGroup = QButtonGroup() @@ -448,11 +576,6 @@ class ConfigDialog(QtGui.QDialog): self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacySendHashedOption) self.filesizeprivacyButtonGroup.addButton(self.filesizeprivacyDontSendOption) - self.dontslowwithmeCheckbox = QCheckBox(getMessage("dontslowdownwithme-label")) - self.pauseonleaveCheckbox = QCheckBox(getMessage("pauseonleave-label")) - self.alwaysshowCheckbox = QCheckBox(getMessage("forceguiprompt-label")) - self.nostoreCheckbox = QCheckBox(getMessage("nostore-label")) - self.filenameprivacyLabel.setObjectName("filename-privacy") self.filenameprivacySendRawOption.setObjectName("privacy-sendraw:filenamePrivacyMode="+ constants.PRIVACY_SENDRAW_MODE) self.filenameprivacySendHashedOption.setObjectName("privacy-sendhashed:filenamePrivacyMode=" + constants.PRIVACY_SENDHASHED_MODE) @@ -462,103 +585,169 @@ class ConfigDialog(QtGui.QDialog): self.filesizeprivacySendHashedOption.setObjectName("privacy-sendhashed:filesizePrivacyMode=" + constants.PRIVACY_SENDHASHED_MODE) self.filesizeprivacyDontSendOption.setObjectName("privacy-dontsend:filesizePrivacyMode=" + constants.PRIVACY_DONTSEND_MODE) + self.privacyLayout.addWidget(self.filenameprivacyLabel, 1, 0) + self.privacyLayout.addWidget(self.filenameprivacySendRawOption, 1, 1, Qt.AlignLeft) + self.privacyLayout.addWidget(self.filenameprivacySendHashedOption, 1, 2, Qt.AlignLeft) + self.privacyLayout.addWidget(self.filenameprivacyDontSendOption, 1, 3, Qt.AlignLeft) + self.privacyLayout.addWidget(self.filesizeprivacyLabel, 2, 0) + self.privacyLayout.addWidget(self.filesizeprivacySendRawOption, 2, 1, Qt.AlignLeft) + self.privacyLayout.addWidget(self.filesizeprivacySendHashedOption, 2, 2, Qt.AlignLeft) + self.privacyLayout.addWidget(self.filesizeprivacyDontSendOption, 2, 3, Qt.AlignLeft) - self.slowdownLabel.setObjectName("slowdown") - self.slowdownAutoOption.setObjectName("slowdown-auto:slowMeOnDesync=" + constants.OPTION_AUTO) - self.slowdownAlwaysOption.setObjectName("slowdown-always:slowMeOnDesync=" + constants.OPTION_ALWAYS) - self.slowdownNeverOption.setObjectName("slowdown-never:slowMeOnDesync=" + constants.OPTION_NEVER) + self.privacyFrame.setLayout(self.privacyLayout) + self.privacySettingsGroup.setLayout(self.privacyLayout) + self.privacySettingsGroup.setMaximumHeight(self.privacySettingsGroup.minimumSizeHint().height()) + self.privacySettingsLayout.addWidget(self.privacySettingsGroup) + self.privacySettingsLayout.setAlignment(Qt.AlignTop) + self.privacyFrame.setLayout(self.privacySettingsLayout) + self.stackedLayout.addWidget(self.privacyFrame) - self.dontslowwithmeCheckbox.setObjectName("dontSlowDownWithMe") - self.pauseonleaveCheckbox.setObjectName("pauseOnLeave") - self.alwaysshowCheckbox.setObjectName("*forceGuiPrompt") - self.nostoreCheckbox.setObjectName("noStore") + def addBottomLayout(self): + config = self.config + resourcespath = self.resourcespath - self.moreSettingsLayout = QtGui.QGridLayout() - - self.thresholdSettingsLayout = QtGui.QGridLayout() - self.thresholdFrame = QtGui.QFrame() - self.thresholdFrame.setLineWidth(0) - self.thresholdFrame.setMidLineWidth(0) - self.thresholdSettingsLayout.setContentsMargins(0, 0, 0, 0) - self.thresholdSettingsLayout.addWidget(self.slowdownThresholdLabel, 0, 0, Qt.AlignLeft) - self.thresholdSettingsLayout.addWidget(self.slowdownThresholdSpinbox, 0, 1, Qt.AlignLeft) - self.thresholdSettingsLayout.addWidget(self.rewindThresholdLabel, 0, 2, Qt.AlignLeft) - self.thresholdSettingsLayout.addWidget(self.rewindThresholdSpinbox, 0, 3, Qt.AlignLeft) - self.thresholdFrame.setLayout(self.thresholdSettingsLayout) - self.moreSettingsLayout.addWidget(self.thresholdFrame, 0, 0, 1, 4, Qt.AlignLeft) - - self.privacySettingsLayout = QtGui.QGridLayout() - self.radioFrame = QtGui.QFrame() - self.radioFrame.setLineWidth(0) - self.radioFrame.setMidLineWidth(0) - self.privacySettingsLayout.setContentsMargins(0, 0, 0, 0) - self.privacySettingsLayout.addWidget(self.slowdownLabel, 0, 0) - self.privacySettingsLayout.addWidget(self.slowdownAutoOption, 0, 1, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.slowdownAlwaysOption, 0, 2, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.slowdownNeverOption, 0, 3, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.filenameprivacyLabel, 1, 0) - self.privacySettingsLayout.addWidget(self.filenameprivacySendRawOption, 1, 1, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.filenameprivacySendHashedOption, 1, 2, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.filenameprivacyDontSendOption, 1, 3, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.filesizeprivacyLabel, 2, 0) - self.privacySettingsLayout.addWidget(self.filesizeprivacySendRawOption, 2, 1, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.filesizeprivacySendHashedOption, 2, 2, Qt.AlignLeft) - self.privacySettingsLayout.addWidget(self.filesizeprivacyDontSendOption, 2, 3, Qt.AlignLeft) - self.radioFrame.setLayout(self.privacySettingsLayout) - - self.moreSettingsLayout.addWidget(self.radioFrame, 1, 0, 1, 4) - - self.moreSettingsLayout.addWidget(self.dontslowwithmeCheckbox, 4, 0, 1, 2) - self.moreSettingsLayout.addWidget(self.pauseonleaveCheckbox, 5, 0, 1, 2) - self.moreSettingsLayout.addWidget(self.alwaysshowCheckbox, 4, 2, 1, 2) - self.moreSettingsLayout.addWidget(self.nostoreCheckbox, 5, 2, 1, 2) - - - self.moreSettingsGroup.setLayout(self.moreSettingsLayout) - - self.showmoreCheckbox = QCheckBox(getMessage("more-title")) - - if self.getMoreState() == False: - self.showmoreCheckbox.setChecked(False) - self.moreSettingsGroup.hide() - else: - self.showmoreCheckbox.hide() - self.showmoreCheckbox.toggled.connect(self.moreToggled) - self.moreSettingsGroup.toggled.connect(self.moreToggled) - - self.showmoreCheckbox.setObjectName("!more") - - - self.nostoreCheckbox.toggled.connect(self.runButtonTextUpdate) - - self.mainLayout = QtGui.QVBoxLayout() - if error: - self.errorLabel = QLabel(error, self) - self.errorLabel.setAlignment(Qt.AlignCenter) - self.errorLabel.setStyleSheet("QLabel { color : red; }") - self.mainLayout.addWidget(self.errorLabel) - self.mainLayout.addWidget(self.connectionSettingsGroup) - self.mainLayout.addSpacing(12) - self.mainLayout.addWidget(self.mediaplayerSettingsGroup) - self.mainLayout.addSpacing(12) - self.mainLayout.addWidget(self.showmoreCheckbox) - self.mainLayout.addWidget(self.moreSettingsGroup) - self.mainLayout.addSpacing(12) - - self.topLayout = QtGui.QHBoxLayout() - self.helpButton = QtGui.QPushButton(QtGui.QIcon(resourcespath + 'help.png'), getMessage("help-label")) + self.bottomButtonFrame = QtGui.QFrame() + self.bottomButtonLayout = QtGui.QHBoxLayout() + self.helpButton = QtGui.QPushButton(QtGui.QIcon(self.resourcespath + 'help.png'), getMessage("help-label")) self.helpButton.setObjectName("help") self.helpButton.setMaximumSize(self.helpButton.sizeHint()) self.helpButton.pressed.connect(self.openHelp) + + self.resetButton = QtGui.QPushButton(QtGui.QIcon(resourcespath + 'cog_delete.png'),"Reset settings") + self.resetButton.setMaximumSize(self.resetButton.sizeHint()) + self.resetButton.pressed.connect(self.resetSettings) + self.runButton = QtGui.QPushButton(QtGui.QIcon(resourcespath + 'accept.png'), getMessage("storeandrun-label")) self.runButton.pressed.connect(self._saveDataAndLeave) + self.bottomButtonLayout.addWidget(self.helpButton) + self.bottomButtonLayout.addWidget(self.resetButton) + self.bottomButtonLayout.addWidget(self.runButton) + self.bottomButtonFrame.setLayout(self.bottomButtonLayout) if config['noStore'] == True: self.runButton.setText(getMessage("run-label")) - self.topLayout.addWidget(self.helpButton, Qt.AlignLeft) - self.topLayout.addWidget(self.runButton, Qt.AlignRight) - self.mainLayout.addLayout(self.topLayout) + self.bottomButtonLayout.setContentsMargins(5,0,5,0) + self.mainLayout.addWidget(self.bottomButtonFrame, 1, 0, 1, 2) + + self.bottomCheckboxFrame = QtGui.QFrame() + self.bottomCheckboxFrame.setContentsMargins(0,0,0,0) + self.bottomCheckboxLayout = QtGui.QGridLayout() + self.alwaysshowCheckbox = QCheckBox(getMessage("forceguiprompt-label")) + + self.nostoreCheckbox = QCheckBox(getMessage("nostore-label")) + self.bottomCheckboxLayout.addWidget(self.showmoreCheckbox) + self.bottomCheckboxLayout.addWidget(self.alwaysshowCheckbox, 0, 1, Qt.AlignLeft) + self.bottomCheckboxLayout.addWidget(self.nostoreCheckbox, 0, 2, Qt.AlignRight) + self.alwaysshowCheckbox.setObjectName("*forceGuiPrompt") + self.nostoreCheckbox.setObjectName("noStore") + self.nostoreCheckbox.toggled.connect(self.runButtonTextUpdate) + self.bottomCheckboxFrame.setLayout(self.bottomCheckboxLayout) + self.mainLayout.addWidget(self.bottomCheckboxFrame, 2, 0, 1, 2) + + def tabList(self): + self.tabListLayout = QtGui.QHBoxLayout() + self.tabListFrame = QtGui.QFrame() + self.tabListWidget = QtGui.QListWidget() + self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "house.png"),getMessage("basics-label"))) + self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "film_link.png"),getMessage("sync-label"))) + self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "comments.png"),getMessage("messages-label"))) + self.tabListWidget.addItem(QtGui.QListWidgetItem(QtGui.QIcon(self.resourcespath + "eye.png"),getMessage("privacy-label"))) + self.tabListLayout.addWidget(self.tabListWidget) + self.tabListFrame.setLayout(self.tabListLayout) + self.tabListFrame.setFixedWidth(self.tabListFrame.minimumSizeHint().width()) + self.tabListWidget.setStyleSheet(constants.STYLE_TABLIST) + + self.tabListWidget.currentItemChanged.connect(self.tabChange) + self.tabListWidget.itemClicked.connect(self.tabChange) + self.tabListWidget.itemPressed.connect(self.tabChange) + self.mainLayout.addWidget(self.tabListFrame, 0, 0, 1, 1) + + def ensureTabListIsVisible(self): + self.stackedFrame.setFixedWidth(self.stackedFrame.width()) + while self.tabListWidget.horizontalScrollBar().isVisible() and self.tabListFrame.width() < 200: + self.tabListFrame.setFixedWidth(self.tabListFrame.width()+1) + + def tabChange(self): + self.setFocus() + self.stackedLayout.setCurrentIndex(self.tabListWidget.currentRow()) + + def resetSettings(self): + self.clearGUIData(leaveMore=True) + self.config['resetConfig'] = True + self.pressedclosebutton = True + self.close() + + def showEvent(self, *args, **kwargs): + self.ensureTabListIsVisible() + + def clearGUIData(self, leaveMore=False): + settings = QSettings("Syncplay", "PlayerList") + settings.clear() + settings = QSettings("Syncplay", "MediaBrowseDialog") + settings.clear() + settings = QSettings("Syncplay", "MainWindow") + settings.clear() + if not leaveMore: + settings = QSettings("Syncplay", "MoreSettings") + settings.clear() + self.datacleared = True + + def __init__(self, config, playerpaths, error, defaultConfig): + + from syncplay import utils + self.config = config + self.defaultConfig = defaultConfig + self.playerpaths = playerpaths + self.datacleared = False + self.config['resetConfig'] = False + + if self.config['clearGUIData'] == True: + self.config['clearGUIData'] = False + self.clearGUIData() + + self.QtGui = QtGui + self.error = error + if sys.platform.startswith('win'): + resourcespath = utils.findWorkingDir() + "\\resources\\" + else: + resourcespath = utils.findWorkingDir() + "/resources/" + self.posixresourcespath = utils.findWorkingDir().replace("\\","/") + "/resources/" + self.resourcespath = resourcespath + + super(ConfigDialog, self).__init__() + + self.setWindowTitle(getMessage("config-window-title")) + self.setWindowFlags(self.windowFlags() & Qt.WindowCloseButtonHint & ~Qt.WindowContextHelpButtonHint) + self.setWindowIcon(QtGui.QIcon(resourcespath + "syncplay.png")) + + self.stackedLayout = QtGui.QStackedLayout() + self.stackedFrame = QtGui.QFrame() + self.stackedFrame.setLayout(self.stackedLayout) + + self.mainLayout = QtGui.QGridLayout() + self.mainLayout.setSpacing(0) + self.mainLayout.setContentsMargins(0,0,0,0) + + self.addBasicTab() + self.addSyncTab() + self.addMessageTab() + self.addPrivacyTab() + self.tabList() + + self.mainLayout.addWidget(self.stackedFrame, 0, 1) + self.addBottomLayout() + + + if self.getMoreState() == False: + self.tabListFrame.hide() + self.nostoreCheckbox.hide() + self.alwaysshowCheckbox.hide() + self.resetButton.hide() + else: + self.showmoreCheckbox.setChecked(True) + self.tabListWidget.setCurrentRow(0) + + self.showmoreCheckbox.toggled.connect(self.moreToggled) - self.mainLayout.addStretch(1) self.setLayout(self.mainLayout) self.runButton.setFocus() self.setFixedSize(self.sizeHint()) @@ -566,7 +755,4 @@ class ConfigDialog(QtGui.QDialog): if constants.SHOW_TOOLTIPS: self.processWidget(self, lambda w: self.loadTooltips(w)) - self.processWidget(self, lambda w: self.loadValues(w)) - - if self.datacleared == True: - QtGui.QMessageBox.information(self, "Syncplay", getMessage("gui-data-cleared-notification")) \ No newline at end of file + self.processWidget(self, lambda w: self.loadValues(w)) \ No newline at end of file diff --git a/syncplay/ui/gui.py b/syncplay/ui/gui.py index 4487953..8f2ca0e 100644 --- a/syncplay/ui/gui.py +++ b/syncplay/ui/gui.py @@ -5,13 +5,38 @@ from syncplay.messages import getMessage import sys import time import re -import os +import os +import threading from syncplay.utils import formatTime, sameFilename, sameFilesize, sameFileduration class MainWindow(QtGui.QMainWindow): def addClient(self, client): self._syncplayClient = client self.roomInput.setText(self._syncplayClient.getRoom()) + self.config = self._syncplayClient.getConfig() + try: + if self.contactLabel and not self.config['showContactInfo']: + self.contactLabel.hide() + if not self.config['showButtonLabels']: + if constants.MERGE_PLAYPAUSE_BUTTONS: + self.playpauseButton.setText("") + else: + self.playButton.setText("") + self.playButton.setFixedWidth(self.playButton.minimumSizeHint().width()) + self.pauseButton.setText("") + self.pauseButton.setFixedWidth(self.pauseButton.minimumSizeHint().width()) + self.roomButton.setText("") + self.roomButton.setFixedWidth(self.roomButton.minimumSizeHint().width()) + self.seekButton.setText("") + self.seekButton.setFixedWidth(self.seekButton.minimumSizeHint().width()) + self.unseekButton.setText("") + self.unseekButton.setFixedWidth(self.unseekButton.minimumSizeHint().width()) + self.roomGroup.setFixedWidth(self.roomGroup.sizeHint().width()) + self.seekGroup.setFixedWidth(self.seekGroup.minimumSizeHint().width()) + self.miscGroup.setFixedWidth(self.miscGroup.minimumSizeHint().width()) + except (): + pass + def promptFor(self, prompt=">", message=""): #TODO: Prompt user @@ -20,7 +45,7 @@ class MainWindow(QtGui.QMainWindow): def showMessage(self, message, noTimestamp=False): message = unicode(message) message = message.replace("&", "&").replace('"', """).replace("<", "<").replace(">", ">") - message = message.replace("<", "<") + message = message.replace("<", "<".format(constants.STYLE_USERNAME)) message = message.replace(">", ">") message = message.replace("\n", "
") if noTimestamp: @@ -65,11 +90,11 @@ class MainWindow(QtGui.QMainWindow): elif differentDuration: fileitem = QtGui.QStandardItem(u"{} ({}) ({})".format(user.file['name'], formatTime(user.file['duration']), getMessage("differentduration-note"))) if sameRoom and (differentName or differentSize or differentDuration): - fileitem.setForeground(QtGui.QBrush(QtGui.QColor('red'))) + fileitem.setForeground(QtGui.QBrush(QtGui.QColor(constants.STYLE_DIFFERENTITEM_COLOR))) else: fileitem = QtGui.QStandardItem(getMessage("nofile-note")) if room == currentUser.room: - fileitem.setForeground(QtGui.QBrush(QtGui.QColor('blue'))) + fileitem.setForeground(QtGui.QBrush(QtGui.QColor(constants.STYLE_NOFILEITEM_COLOR))) if currentUser.username == user.username: font = QtGui.QFont() font.setWeight(QtGui.QFont.Bold) @@ -102,7 +127,7 @@ class MainWindow(QtGui.QMainWindow): QtGui.QMessageBox.critical(self,"Syncplay", message) message = message.replace("&", "&").replace('"', """).replace("<", "<").replace(">", ">") message = message.replace("\n", "
") - message = "" + message + "" + message = "".format(constants.STYLE_ERRORNOTIFICATION) + message + "" self.newMessage(time.strftime(constants.UI_TIME_FORMAT, time.localtime()) + message + "
") def joinRoom(self, room = None): @@ -230,7 +255,7 @@ class MainWindow(QtGui.QMainWindow): window.outputLayout = QtGui.QVBoxLayout() window.outputbox = QtGui.QTextEdit() - window.outputbox.setReadOnly(True) + window.outputbox.setReadOnly(True) window.outputlabel = QtGui.QLabel(getMessage("notifications-heading-label")) window.outputFrame = QtGui.QFrame() window.outputFrame.setLineWidth(0) @@ -252,17 +277,16 @@ class MainWindow(QtGui.QMainWindow): window.listLayout.setContentsMargins(0,0,0,0) window.listLayout.addWidget(window.listlabel) window.listLayout.addWidget(window.listTreeView) - if constants.SHOW_CONTACT_INFO: - window.contactLabel = QtGui.QLabel() - window.contactLabel.setWordWrap(True) - window.contactLabel.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken) - window.contactLabel.setLineWidth(1) - window.contactLabel.setMidLineWidth(0) - window.contactLabel.setMargin(2) - window.contactLabel.setText(getMessage("contact-label")) - window.contactLabel.setTextInteractionFlags(Qt.LinksAccessibleByMouse) - window.contactLabel.setOpenExternalLinks(True) - window.listLayout.addWidget(window.contactLabel) + window.contactLabel = QtGui.QLabel() + window.contactLabel.setWordWrap(True) + window.contactLabel.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken) + window.contactLabel.setLineWidth(1) + window.contactLabel.setMidLineWidth(0) + window.contactLabel.setMargin(2) + window.contactLabel.setText(getMessage("contact-label")) + window.contactLabel.setTextInteractionFlags(Qt.LinksAccessibleByMouse) + window.contactLabel.setOpenExternalLinks(True) + window.listLayout.addWidget(window.contactLabel) window.listFrame.setLayout(window.listLayout) window.topSplit.addWidget(window.outputFrame) diff --git a/syncplay/utils.py b/syncplay/utils.py index f084844..40bf3d2 100644 --- a/syncplay/utils.py +++ b/syncplay/utils.py @@ -176,7 +176,9 @@ def sameFilesize (filesize1, filesize2): return False def sameFileduration (duration1, duration2): - if abs(round(duration1) - round(duration2)) < constants.DIFFFERENT_DURATION_THRESHOLD: + if not constants.SHOW_DURATION_NOTIFICATION: + return True + elif abs(round(duration1) - round(duration2)) < constants.DIFFFERENT_DURATION_THRESHOLD: return True else: return False