{"action":"created","comment":{"url":"https://api.github.com/repos/slaclab/pydm/pulls/comments/203834369","pull_request_review_id":138803798,"id":203834369,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwMzgzNDM2OQ==","diff_hunk":"@@ -0,0 +1,128 @@\n+# Utility to handle importing the global stylesheet for PyDM widgets\n+\n+from ..PyQt.QtGui import QApplication\n+import os\n+from functools import partial\n+\n+import logging\n+logger = logging.getLogger(__name__)\n+from . import is_pydm_app\n+\n+\n+# Fallback global stylesheet if there is no global stylesheet provided via env variable or command line parameter\n+# TODO: Expand this global stylesheet\n+GLOBAL_STYLESHEET = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../default_stylesheet.qss')\n+\n+\n+def apply_stylesheet(stylesheet_file_path, timer=None):\n+    \"\"\"\n+    Apply a stylesheet to the current Qt Designer form (a .ui file) or to a Designer form using the PyDM Launcher.\n+\n+    Parameters\n+    ----------\n+    stylesheet_file_path : str\n+        The full path to a global CSS stylesheet file\n+    timer : QTimer\n+        A timer to launch the set stylesheet method for Qt Designer. For the PyDM Launcher, the timer is not needed,\n+        and can be set to None\n+    \"\"\"\n+    if not stylesheet_file_path:\n+        # If there is no stylesheet path provided by a command parameter, check for the env variable\n+        stylesheet_file_path = os.getenv(\"PYDM_STYLESHEET\", None)\n+\n+    # Load style data from the stylesheet file. Otherwise, the fallback is already in place, i.e. PyDM will be\n+    # using the data from the global stylesheet\n+    style_data = _get_style_data(stylesheet_file_path)\n+\n+    if timer:\n+        # For PyDM Launcher, the timer should be None. This code is to handle Qt Designer only\n+        timer.timeout.connect(partial(_set_style_data, style_data, timer))\n+        timer.start()\n+    else:\n+        # For running PyDM Launcher\n+        _set_style_data(style_data, None)\n+\n+    return style_data\n+\n+\n+def _get_style_data(stylesheet_file_path):\n+    \"\"\"\n+    Read the global stylesheet file and provide the style data as a str.\n+\n+    Parameters\n+    ----------\n+    stylesheet_file_path : str\n+        The path to the global stylesheet.\n+\n+    Returns\n+    -------\n+    The style data read from the stylesheet file : str\n+    \"\"\"\n+    style_data = None\n+    if stylesheet_file_path is not None:\n+        try:\n+            with open(stylesheet_file_path, 'r') as stylesheet_file:\n+                logger.info(\"Opening style file '{0}'...\".format(stylesheet_file_path))\n+                style_data = stylesheet_file.read()\n+        except Exception as ex:\n+            logger.error(\"Error reading the stylesheet file '{0}'. Exception: {1}\".format(stylesheet_file_path,\n+                                                                                          str(ex)))\n+    else:\n+        try:\n+            with open(GLOBAL_STYLESHEET) as default_stylesheet:\n+                logger.info(\"Opening the default stylesheet '{0}'...\".format(GLOBAL_STYLESHEET))\n+                style_data = default_stylesheet.read()\n+        except Exception as ex:\n+            logger.error(\"Cannot find the default stylesheet file '{0}'. Exception: {1}\".format(GLOBAL_STYLESHEET,\n+                                                                                                str(ex)))\n+    return style_data\n+\n+\n+def _set_style_data(style_data, timer):\n+    \"\"\"\n+    Apply the global stylesheet data to a .ui form.\n+\n+    If the PyDM Launcher opens this .ui form, apply the stylesheet directly to the app. Otherwise, in Qt Designer, apply\n+    the stylesheet to the root object (\"formContainer\").\n+\n+    Parameters\n+    ----------\n+    style_data : str\n+        The style data obtained from a stylesheet file\n+    timer : QTimer\n+        The timer to launch the style data applying method (for the Qt Designer environment only)\n+    \"\"\"\n+    app = QApplication.instance()\n+    if is_pydm_app():\n+        _set_stylesheet_for_app(app, style_data)\n+    else:\n+        for w in app.allWidgets():\n+            try:\n+                name = w.objectName()\n+            except:\n+                name = ''\n+            # Set the stylesheet to the root form object\n+            if name == \"formContainer\":\n+                # This will be loaded from the file set by users to define the global stylesheet for the facility in\n+                # use\n+                w.setStyleSheet(style_data)\n+                # A timer is fully expected here. If a timer cannot be provided for whatever reason, we must re-evaluate\n+                # the current Qt Designer stylesheet application methodology\n+                timer.stop()\n+\n+\n+def _set_stylesheet_for_app(app, style_data):","path":"pydm/utilities/stylesheet.py","position":114,"original_position":114,"commit_id":"09cfbfc046ad3319fbee8d9608ef4d86dc5dcc49","original_commit_id":"09cfbfc046ad3319fbee8d9608ef4d86dc5dcc49","user":{"login":"hhslepicka","id":8185425,"node_id":"MDQ6VXNlcjgxODU0MjU=","avatar_url":"https://avatars0.githubusercontent.com/u/8185425?v=4","gravatar_id":"","url":"https://api.github.com/users/hhslepicka","html_url":"https://github.com/hhslepicka","followers_url":"https://api.github.com/users/hhslepicka/followers","following_url":"https://api.github.com/users/hhslepicka/following{/other_user}","gists_url":"https://api.github.com/users/hhslepicka/gists{/gist_id}","starred_url":"https://api.github.com/users/hhslepicka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hhslepicka/subscriptions","organizations_url":"https://api.github.com/users/hhslepicka/orgs","repos_url":"https://api.github.com/users/hhslepicka/repos","events_url":"https://api.github.com/users/hhslepicka/events{/privacy}","received_events_url":"https://api.github.com/users/hhslepicka/received_events","type":"User","site_admin":false},"body":"Do we need a method for just one line of code?","created_at":"2018-07-19T18:49:17Z","updated_at":"2018-07-19T18:58:28Z","html_url":"https://github.com/slaclab/pydm/pull/361#discussion_r203834369","pull_request_url":"https://api.github.com/repos/slaclab/pydm/pulls/361","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/slaclab/pydm/pulls/comments/203834369"},"html":{"href":"https://github.com/slaclab/pydm/pull/361#discussion_r203834369"},"pull_request":{"href":"https://api.github.com/repos/slaclab/pydm/pulls/361"}}},"pull_request":{"url":"https://api.github.com/repos/slaclab/pydm/pulls/361","id":199595406,"node_id":"MDExOlB1bGxSZXF1ZXN0MTk5NTk1NDA2","html_url":"https://github.com/slaclab/pydm/pull/361","diff_url":"https://github.com/slaclab/pydm/pull/361.diff","patch_url":"https://github.com/slaclab/pydm/pull/361.patch","issue_url":"https://api.github.com/repos/slaclab/pydm/issues/361","number":361,"state":"open","locked":false,"title":"ENH: Add external stylesheet support","user":{"login":"hmbui","id":36712473,"node_id":"MDQ6VXNlcjM2NzEyNDcz","avatar_url":"https://avatars3.githubusercontent.com/u/36712473?v=4","gravatar_id":"","url":"https://api.github.com/users/hmbui","html_url":"https://github.com/hmbui","followers_url":"https://api.github.com/users/hmbui/followers","following_url":"https://api.github.com/users/hmbui/following{/other_user}","gists_url":"https://api.github.com/users/hmbui/gists{/gist_id}","starred_url":"https://api.github.com/users/hmbui/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hmbui/subscriptions","organizations_url":"https://api.github.com/users/hmbui/orgs","repos_url":"https://api.github.com/users/hmbui/repos","events_url":"https://api.github.com/users/hmbui/events{/privacy}","received_events_url":"https://api.github.com/users/hmbui/received_events","type":"User","site_admin":false},"body":"ENH: Add a utility to generate alarm stylesheet for different PyDM widget types.\r\nTST: Add external stylesheet support and alarm stylesheet generating unit tests","created_at":"2018-07-05T21:46:37Z","updated_at":"2018-07-19T18:58:28Z","closed_at":null,"merged_at":null,"merge_commit_sha":"b6c7c11ec92580c451cf8e8ef6284636231bd29f","assignee":{"login":"hhslepicka","id":8185425,"node_id":"MDQ6VXNlcjgxODU0MjU=","avatar_url":"https://avatars0.githubusercontent.com/u/8185425?v=4","gravatar_id":"","url":"https://api.github.com/users/hhslepicka","html_url":"https://github.com/hhslepicka","followers_url":"https://api.github.com/users/hhslepicka/followers","following_url":"https://api.github.com/users/hhslepicka/following{/other_user}","gists_url":"https://api.github.com/users/hhslepicka/gists{/gist_id}","starred_url":"https://api.github.com/users/hhslepicka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hhslepicka/subscriptions","organizations_url":"https://api.github.com/users/hhslepicka/orgs","repos_url":"https://api.github.com/users/hhslepicka/repos","events_url":"https://api.github.com/users/hhslepicka/events{/privacy}","received_events_url":"https://api.github.com/users/hhslepicka/received_events","type":"User","site_admin":false},"assignees":[{"login":"hhslepicka","id":8185425,"node_id":"MDQ6VXNlcjgxODU0MjU=","avatar_url":"https://avatars0.githubusercontent.com/u/8185425?v=4","gravatar_id":"","url":"https://api.github.com/users/hhslepicka","html_url":"https://github.com/hhslepicka","followers_url":"https://api.github.com/users/hhslepicka/followers","following_url":"https://api.github.com/users/hhslepicka/following{/other_user}","gists_url":"https://api.github.com/users/hhslepicka/gists{/gist_id}","starred_url":"https://api.github.com/users/hhslepicka/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hhslepicka/subscriptions","organizations_url":"https://api.github.com/users/hhslepicka/orgs","repos_url":"https://api.github.com/users/hhslepicka/repos","events_url":"https://api.github.com/users/hhslepicka/events{/privacy}","received_events_url":"https://api.github.com/users/hhslepicka/received_events","type":"User","site_admin":false}],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/slaclab/pydm/pulls/361/commits","review_comments_url":"https://api.github.com/repos/slaclab/pydm/pulls/361/comments","review_comment_url":"https://api.github.com/repos/slaclab/pydm/pulls/comments{/number}","comments_url":"https://api.github.com/repos/slaclab/pydm/issues/361/comments","statuses_url":"https://api.github.com/repos/slaclab/pydm/statuses/09cfbfc046ad3319fbee8d9608ef4d86dc5dcc49","head":{"label":"hmbui:css","ref":"css","sha":"09cfbfc046ad3319fbee8d9608ef4d86dc5dcc49","user":{"login":"hmbui","id":36712473,"node_id":"MDQ6VXNlcjM2NzEyNDcz","avatar_url":"https://avatars3.githubusercontent.com/u/36712473?v=4","gravatar_id":"","url":"https://api.github.com/users/hmbui","html_url":"https://github.com/hmbui","followers_url":"https://api.github.com/users/hmbui/followers","following_url":"https://api.github.com/users/hmbui/following{/other_user}","gists_url":"https://api.github.com/users/hmbui/gists{/gist_id}","starred_url":"https://api.github.com/users/hmbui/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hmbui/subscriptions","organizations_url":"https://api.github.com/users/hmbui/orgs","repos_url":"https://api.github.com/users/hmbui/repos","events_url":"https://api.github.com/users/hmbui/events{/privacy}","received_events_url":"https://api.github.com/users/hmbui/received_events","type":"User","site_admin":false},"repo":{"id":122418877,"node_id":"MDEwOlJlcG9zaXRvcnkxMjI0MTg4Nzc=","name":"pydm","full_name":"hmbui/pydm","owner":{"login":"hmbui","id":36712473,"node_id":"MDQ6VXNlcjM2NzEyNDcz","avatar_url":"https://avatars3.githubusercontent.com/u/36712473?v=4","gravatar_id":"","url":"https://api.github.com/users/hmbui","html_url":"https://github.com/hmbui","followers_url":"https://api.github.com/users/hmbui/followers","following_url":"https://api.github.com/users/hmbui/following{/other_user}","gists_url":"https://api.github.com/users/hmbui/gists{/gist_id}","starred_url":"https://api.github.com/users/hmbui/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/hmbui/subscriptions","organizations_url":"https://api.github.com/users/hmbui/orgs","repos_url":"https://api.github.com/users/hmbui/repos","events_url":"https://api.github.com/users/hmbui/events{/privacy}","received_events_url":"https://api.github.com/users/hmbui/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/hmbui/pydm","description":"Python Display Manager","fork":true,"url":"https://api.github.com/repos/hmbui/pydm","forks_url":"https://api.github.com/repos/hmbui/pydm/forks","keys_url":"https://api.github.com/repos/hmbui/pydm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/hmbui/pydm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/hmbui/pydm/teams","hooks_url":"https://api.github.com/repos/hmbui/pydm/hooks","issue_events_url":"https://api.github.com/repos/hmbui/pydm/issues/events{/number}","events_url":"https://api.github.com/repos/hmbui/pydm/events","assignees_url":"https://api.github.com/repos/hmbui/pydm/assignees{/user}","branches_url":"https://api.github.com/repos/hmbui/pydm/branches{/branch}","tags_url":"https://api.github.com/repos/hmbui/pydm/tags","blobs_url":"https://api.github.com/repos/hmbui/pydm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/hmbui/pydm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/hmbui/pydm/git/refs{/sha}","trees_url":"https://api.github.com/repos/hmbui/pydm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/hmbui/pydm/statuses/{sha}","languages_url":"https://api.github.com/repos/hmbui/pydm/languages","stargazers_url":"https://api.github.com/repos/hmbui/pydm/stargazers","contributors_url":"https://api.github.com/repos/hmbui/pydm/contributors","subscribers_url":"https://api.github.com/repos/hmbui/pydm/subscribers","subscription_url":"https://api.github.com/repos/hmbui/pydm/subscription","commits_url":"https://api.github.com/repos/hmbui/pydm/commits{/sha}","git_commits_url":"https://api.github.com/repos/hmbui/pydm/git/commits{/sha}","comments_url":"https://api.github.com/repos/hmbui/pydm/comments{/number}","issue_comment_url":"https://api.github.com/repos/hmbui/pydm/issues/comments{/number}","contents_url":"https://api.github.com/repos/hmbui/pydm/contents/{+path}","compare_url":"https://api.github.com/repos/hmbui/pydm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/hmbui/pydm/merges","archive_url":"https://api.github.com/repos/hmbui/pydm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/hmbui/pydm/downloads","issues_url":"https://api.github.com/repos/hmbui/pydm/issues{/number}","pulls_url":"https://api.github.com/repos/hmbui/pydm/pulls{/number}","milestones_url":"https://api.github.com/repos/hmbui/pydm/milestones{/number}","notifications_url":"https://api.github.com/repos/hmbui/pydm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/hmbui/pydm/labels{/name}","releases_url":"https://api.github.com/repos/hmbui/pydm/releases{/id}","deployments_url":"https://api.github.com/repos/hmbui/pydm/deployments","created_at":"2018-02-22T02:06:21Z","updated_at":"2018-07-11T20:09:09Z","pushed_at":"2018-07-11T20:09:07Z","git_url":"git://github.com/hmbui/pydm.git","ssh_url":"git@github.com:hmbui/pydm.git","clone_url":"https://github.com/hmbui/pydm.git","svn_url":"https://github.com/hmbui/pydm","homepage":"http://slaclab.github.io/pydm/","size":6151,"stargazers_count":0,"watchers_count":0,"language":"Python","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"slaclab:master","ref":"master","sha":"72f7ef69b4783715e7ca7727c416a013563bac82","user":{"login":"slaclab","id":16196854,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE2MTk2ODU0","avatar_url":"https://avatars2.githubusercontent.com/u/16196854?v=4","gravatar_id":"","url":"https://api.github.com/users/slaclab","html_url":"https://github.com/slaclab","followers_url":"https://api.github.com/users/slaclab/followers","following_url":"https://api.github.com/users/slaclab/following{/other_user}","gists_url":"https://api.github.com/users/slaclab/gists{/gist_id}","starred_url":"https://api.github.com/users/slaclab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slaclab/subscriptions","organizations_url":"https://api.github.com/users/slaclab/orgs","repos_url":"https://api.github.com/users/slaclab/repos","events_url":"https://api.github.com/users/slaclab/events{/privacy}","received_events_url":"https://api.github.com/users/slaclab/received_events","type":"Organization","site_admin":false},"repo":{"id":59700161,"node_id":"MDEwOlJlcG9zaXRvcnk1OTcwMDE2MQ==","name":"pydm","full_name":"slaclab/pydm","owner":{"login":"slaclab","id":16196854,"node_id":"MDEyOk9yZ2FuaXphdGlvbjE2MTk2ODU0","avatar_url":"https://avatars2.githubusercontent.com/u/16196854?v=4","gravatar_id":"","url":"https://api.github.com/users/slaclab","html_url":"https://github.com/slaclab","followers_url":"https://api.github.com/users/slaclab/followers","following_url":"https://api.github.com/users/slaclab/following{/other_user}","gists_url":"https://api.github.com/users/slaclab/gists{/gist_id}","starred_url":"https://api.github.com/users/slaclab/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/slaclab/subscriptions","organizations_url":"https://api.github.com/users/slaclab/orgs","repos_url":"https://api.github.com/users/slaclab/repos","events_url":"https://api.github.com/users/slaclab/events{/privacy}","received_events_url":"https://api.github.com/users/slaclab/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/slaclab/pydm","description":"Python Display Manager","fork":false,"url":"https://api.github.com/repos/slaclab/pydm","forks_url":"https://api.github.com/repos/slaclab/pydm/forks","keys_url":"https://api.github.com/repos/slaclab/pydm/keys{/key_id}","collaborators_url":"https://api.github.com/repos/slaclab/pydm/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/slaclab/pydm/teams","hooks_url":"https://api.github.com/repos/slaclab/pydm/hooks","issue_events_url":"https://api.github.com/repos/slaclab/pydm/issues/events{/number}","events_url":"https://api.github.com/repos/slaclab/pydm/events","assignees_url":"https://api.github.com/repos/slaclab/pydm/assignees{/user}","branches_url":"https://api.github.com/repos/slaclab/pydm/branches{/branch}","tags_url":"https://api.github.com/repos/slaclab/pydm/tags","blobs_url":"https://api.github.com/repos/slaclab/pydm/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/slaclab/pydm/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/slaclab/pydm/git/refs{/sha}","trees_url":"https://api.github.com/repos/slaclab/pydm/git/trees{/sha}","statuses_url":"https://api.github.com/repos/slaclab/pydm/statuses/{sha}","languages_url":"https://api.github.com/repos/slaclab/pydm/languages","stargazers_url":"https://api.github.com/repos/slaclab/pydm/stargazers","contributors_url":"https://api.github.com/repos/slaclab/pydm/contributors","subscribers_url":"https://api.github.com/repos/slaclab/pydm/subscribers","subscription_url":"https://api.github.com/repos/slaclab/pydm/subscription","commits_url":"https://api.github.com/repos/slaclab/pydm/commits{/sha}","git_commits_url":"https://api.github.com/repos/slaclab/pydm/git/commits{/sha}","comments_url":"https://api.github.com/repos/slaclab/pydm/comments{/number}","issue_comment_url":"https://api.github.com/repos/slaclab/pydm/issues/comments{/number}","contents_url":"https://api.github.com/repos/slaclab/pydm/contents/{+path}","compare_url":"https://api.github.com/repos/slaclab/pydm/compare/{base}...{head}","merges_url":"https://api.github.com/repos/slaclab/pydm/merges","archive_url":"https://api.github.com/repos/slaclab/pydm/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/slaclab/pydm/downloads","issues_url":"https://api.github.com/repos/slaclab/pydm/issues{/number}","pulls_url":"https://api.github.com/repos/slaclab/pydm/pulls{/number}","milestones_url":"https://api.github.com/repos/slaclab/pydm/milestones{/number}","notifications_url":"https://api.github.com/repos/slaclab/pydm/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/slaclab/pydm/labels{/name}","releases_url":"https://api.github.com/repos/slaclab/pydm/releases{/id}","deployments_url":"https://api.github.com/repos/slaclab/pydm/deployments","created_at":"2016-05-25T21:50:56Z","updated_at":"2018-07-18T18:06:26Z","pushed_at":"2018-07-19T00:36:27Z","git_url":"git://github.com/slaclab/pydm.git","ssh_url":"git@github.com:slaclab/pydm.git","clone_url":"https://github.com/slaclab/pydm.git","svn_url":"https://github.com/slaclab/pydm","homepage":"http://slaclab.github.io/pydm/","size":13610,"stargazers_count":33,"watchers_count":33,"language":"Python","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":24,"mirror_url":null,"archived":false,"open_issues_count":57,"license":{"key":"other","name":"Other","spdx_id":null,"url":null,"node_id":"MDc6TGljZW5zZTA="},"forks":24,"open_issues":57,"watchers":33,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/slaclab/pydm/pulls/361"},"html":{"href":"https://github.com/slaclab/pydm/pull/361"},"issue":{"href":"https://api.github.com/repos/slaclab/pydm/issues/361"},"comments":{"href":"https://api.github.com/repos/slaclab/pydm/issues/361/comments"},"review_comments":{"href":"https://api.github.com/repos/slaclab/pydm/pulls/361/comments"},"review_comment":{"href":"https://api.github.com/repos/slaclab/pydm/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/slaclab/pydm/pulls/361/commits"},"statuses":{"href":"https://api.github.com/repos/slaclab/pydm/statuses/09cfbfc046ad3319fbee8d9608ef4d86dc5dcc49"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"hhslepicka"}}