def get_logged_in_user(self): """returns the logged in user """ local_session = LocalSession() logged_in_user = local_session.logged_in_user if not logged_in_user: from anima.ui import login_dialog dialog = login_dialog.MainDialog(parent=self) dialog.exec_() logger.debug("dialog.DialogCode: %s" % dialog.DialogCode) try: # PySide accepted = QtGui.QDialog.DialogCode.Accepted except AttributeError: # PyQt4 accepted = QtGui.QDialog.Accepted if dialog.DialogCode == accepted: local_session = LocalSession() logged_in_user = local_session.logged_in_user else: # close the ui # logged_in_user = self.get_logged_in_user() logger.debug("no logged in user") self.close() return logged_in_user
def get_logged_in_user(self): """returns the logged in user """ local_session = LocalSession() from stalker.db.session import DBSession with DBSession.no_autoflush: logged_in_user = local_session.logged_in_user if not logged_in_user: from anima.ui import login_dialog dialog = login_dialog.MainDialog(parent=self) # dialog.deleteLater() dialog.exec_() result = dialog.result() try: # PySide accepted = QtWidgets.QDialog.DialogCode.Accepted except AttributeError: # PyQt4 accepted = QtWidgets.QDialog.Accepted if result == accepted: local_session = LocalSession() logged_in_user = local_session.logged_in_user else: # close the ui # logged_in_user = self.get_logged_in_user() logger.debug("no logged in user") self.close() return logged_in_user
def test_delete_will_delete_the_session_cache(self): """testing if the LocalSession.delete() will delete the current cache file """ # create a new user from stalker import db, User new_user = User( name='Test User', login='******', email='*****@*****.**', password='******' ) # save it to the Database db.DBSession.add(new_user) db.DBSession.commit() self.assertTrue(new_user.id is not None) # save it to the local storage from stalker import LocalSession local_session = LocalSession() local_session.store_user(new_user) # save the session local_session.save() # check if the file is created # check if a file is created in the users local storage import os from stalker import defaults self.assertTrue( os.path.exists( os.path.join( defaults.local_storage_path, defaults.local_session_data_file_name ) ) ) # now delete the session by calling delete() local_session.delete() # check if the file is gone # check if a file is created in the users local storage self.assertFalse( os.path.exists( os.path.join( defaults.local_storage_path, defaults.local_session_data_file_name ) ) ) # delete a second time # this should not raise an OSError local_session.delete()
def logout(self): """log the current user out """ from stalker import LocalSession session = LocalSession() session.delete() self.logged_in_user = None # update file menu actions # self.logout_action.setVisible(False) # self.login_action.setVisible(True) self.close()
def logout(self): """log the current user out """ from stalker import LocalSession session = LocalSession() session.delete() self.logged_in_user = None # update file menu actions # self.logout_action.setVisible(False) # self.login_action.setVisible(True) self.close()
def test_LocalSession_will_not_use_the_stored_data_if_it_is_invalid(self): """testing if the LocalSession will not use the stored session if it is not valid anymore """ # create a new user from stalker import db, User, LocalSession new_user = User( name='Test User', login='******', email='*****@*****.**', password='******' ) # save it to the Database db.DBSession.add(new_user) db.DBSession.commit() self.assertTrue(new_user.id is not None) # save it to the local storage local_session = LocalSession() local_session.store_user(new_user) # save the session local_session.save() # set the valid time to an early date import pytz import datetime local_session.valid_to = \ datetime.datetime.now(pytz.utc) - datetime.timedelta(10) # pickle the data import json data = json.dumps( { 'valid_to': local_session.valid_to, 'logged_in_user_id': -1 }, default=local_session.default_json_serializer ) print('data: %s' % data) local_session._write_data(data) # now get it back with a new local_session local_session2 = LocalSession() self.assertEqual( local_session2.logged_in_user_id, None ) self.assertTrue(local_session2.logged_in_user is None)
def test_save_serializes_the_class_itself(self): """testing if the save function serializes the class to the filesystem """ from stalker import LocalSession new_local_session = LocalSession() new_local_session.save() # check if a file is created in the users local storage import os from stalker import defaults assert os.path.exists( os.path.join(defaults.local_storage_path, defaults.local_session_data_file_name))
def fix_reference_namespace(cls): """fixes reference namespace """ ref_count = len(pm.listReferences(recursive=True)) if ref_count > 25: result = pm.windows.confirmBox( 'Fix Reference Namespace', 'You have %s references in your scene,\n' 'this will take too much time\n\nIs that Ok?' % ref_count ) if not result: return from stalker import LocalSession from anima.env import mayaEnv m = mayaEnv.Maya() local_session = LocalSession() logged_in_user = local_session.logged_in_user if not logged_in_user: raise RuntimeError('Please login before running the script') versions = m.fix_reference_namespaces() for version in versions: version.created_by = logged_in_user from stalker.db.session import DBSession DBSession.commit()
def test_logged_in_user_returns_the_stored_User_instance_from_last_time( self): """testing if logged_in_user returns the logged in user """ # create a new user from stalker import User new_user = User(name='Test User', login='******', email='*****@*****.**', password='******') # save it to the Database from stalker.db.session import DBSession DBSession.add(new_user) DBSession.commit() assert new_user.id is not None # save it to the local storage from stalker import LocalSession local_session = LocalSession() local_session.store_user(new_user) # save the session local_session.save() # now get it back with a new local_session local_session2 = LocalSession() assert local_session2.logged_in_user_id == new_user.id assert local_session2.logged_in_user == new_user
def __init__(self, version=None): local_session = LocalSession() self.logged_in_user = local_session.logged_in_user if not self.logged_in_user: raise RuntimeError('Please login first!') from anima.env.mayaEnv import Maya self.maya_env = Maya() self.base_take_name = None self.version = version
def get_logged_in_user(cls): """returns the logged in user """ # get logged in user from stalker import LocalSession from stalker.db.session import DBSession local_session = LocalSession() with DBSession.no_autoflush: logged_in_user = local_session.logged_in_user if not logged_in_user: raise RuntimeError("Please login first!") return logged_in_user
def update_audit_info(): """updates the audit info of the version """ from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user if logged_in_user: # update the version updated_by from anima.env import mayaEnv m_env = mayaEnv.Maya() v = m_env.get_current_version() if v: v.updated_by = logged_in_user from stalker import db db.DBSession.commit()
def check_smartass_animator(): """checks if the smartass animator is trying to create a new version for a completed animation scene silently """ from stalker.models import walk_hierarchy # check the status of this task v = staging.get('version') t = v.task if t.status.code in ['CMPL']: # get the dependent tasks dependent_tasks = t.dependent_of # generate a white list for the resources # so anybody in the white list can publish it white_list_resources = [] dependent_tasks_all_hierarchy = [] for dt in dependent_tasks: for task in walk_hierarchy(dt, 'dependent_of'): white_list_resources.extend(task.resources) white_list_resources.extend(task.responsible) dependent_tasks_all_hierarchy.append(task) white_list_resources = list(set(white_list_resources)) # get the logged in user from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user # if any of the dependent task has been started so the status is not # WFD or RTS in any of then # # also check if the logged in user is one of the resources of the # dependent tasks if any([t.status.code not in ['WFD', 'RTS'] for t in dependent_tasks_all_hierarchy]) \ and logged_in_user not in white_list_resources: # so the animator is trying to stab behind us # simply f**k him/her # by not allowing to publish the file raise PublishError( "You're not allowed to publish for this task:<br><br>" "Please <b>Request a REVISION</b>!!!!<br>")
def save_as(self, shot_name, child_task_name='Previs'): """saves the file under the given shot name """ # first find the shot from stalker import Version, Shot, Task shot = Shot.query.filter(Shot.name == shot_name).first() if not shot: raise RuntimeError('No shot found with shot name: %s' % shot_name) # get the child task child_task = Task.query\ .filter(Task.parent == shot)\ .filter(Task.name == child_task_name)\ .first() logged_in_user = LocalSession().logged_in_user v = Version(task=child_task, created_by=logged_in_user) self.m_env.save_as(v)
def export_camera(): """exports camera and the related shot node """ from stalker import Task, Version from anima.env import mayaEnv m = mayaEnv.Maya() v = m.get_current_version() shot = pm.ls(type='shot')[0] try: sequencer = pm.ls(shot.message.connections(), type='sequencer')[0] except IndexError: sequencer = None camera = None if shot: camera = shot.currentCamera.get() camera_task = \ Task.query\ .filter(Task.parent == v.task.parent)\ .filter(Task.name == 'Camera').first() if camera_task: from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user cam_v = Version(task=camera_task, description='Exported from %s task on Publish' % v.task.name) cam_v.update_paths() cam_v.extension = '.ma' cam_v.is_published = True cam_v.created_by = cam_v.updated_by = logged_in_user pm.select([shot, camera, sequencer]) m.export_as(cam_v)
def test_LocalSession_initialized_with_previous_session_data(self): """testing if the when creating a new LocalSession instance the class is restored from previous time """ # test data logged_in_user_id = -10 # create a local_session from stalker import LocalSession local_session = LocalSession() # store some data local_session.logged_in_user_id = logged_in_user_id local_session.save() # now create a new LocalSession local_session2 = LocalSession() # now try to get the data back assert local_session2.logged_in_user_id == logged_in_user_id
def setUp(self): """setup the tests """ # ----------------------------------------------------------------- # start of the setUp # create the environment variable and point it to a temp directory db.setup() db.init() self.temp_repo_path = tempfile.mkdtemp() self.user1 = User(name='User 1', login='******', email='*****@*****.**', password='******') db.DBSession.add(self.user1) db.DBSession.commit() # login as self.user1 from stalker import LocalSession local_session = LocalSession() local_session.store_user(self.user1) local_session.save() self.repo1 = Repository(name='Test Project Repository', linux_path=self.temp_repo_path, windows_path=self.temp_repo_path, osx_path=self.temp_repo_path) self.status_new = Status.query.filter_by(code='NEW').first() self.status_wip = Status.query.filter_by(code='WIP').first() self.status_comp = Status.query.filter_by(code='CMPL').first() self.task_template = FilenameTemplate( name='Task Template', target_entity_type='Task', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.asset_template = FilenameTemplate( name='Asset Template', target_entity_type='Asset', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.shot_template = FilenameTemplate( name='Shot Template', target_entity_type='Shot', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.sequence_template = FilenameTemplate( name='Sequence Template', target_entity_type='Sequence', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.structure = Structure(name='Project Struture', templates=[ self.task_template, self.asset_template, self.shot_template, self.sequence_template ]) self.project_status_list = StatusList( name='Project Statuses', target_entity_type='Project', statuses=[self.status_new, self.status_wip, self.status_comp]) self.image_format = ImageFormat(name='HD 1080', width=1920, height=1080, pixel_aspect=1.0) # create a test project self.project = Project(name='Test Project', code='TP', repository=self.repo1, status_list=self.project_status_list, structure=self.structure, image_format=self.image_format) self.task_status_list =\ StatusList.query.filter_by(target_entity_type='Task').first() self.asset_status_list =\ StatusList.query.filter_by(target_entity_type='Asset').first() self.shot_status_list =\ StatusList.query.filter_by(target_entity_type='Shot').first() self.sequence_status_list =\ StatusList.query.filter_by(target_entity_type='Sequence').first() self.character_type = Type(name='Character', code='CHAR', target_entity_type='Asset') # create a test series of root task self.task1 = Task(name='Test Task 1', project=self.project) self.task2 = Task(name='Test Task 2', project=self.project) self.task3 = Task(name='Test Task 3', project=self.project) # then a couple of child tasks self.task4 = Task(name='Test Task 4', parent=self.task1) self.task5 = Task(name='Test Task 5', parent=self.task1) self.task6 = Task(name='Test Task 6', parent=self.task1) # create a root asset self.asset1 = Asset(name='Asset 1', code='asset1', type=self.character_type, project=self.project) # create a child asset self.asset2 = Asset(name='Asset 2', code='asset2', type=self.character_type, parent=self.task4) # create a root Sequence self.sequence1 = Sequence(name='Sequence1', code='SEQ1', project=self.project) # create a child Sequence self.sequence2 = Sequence(name='Sequence2', code='SEQ2', parent=self.task2) # create a root Shot self.shot1 = Shot(name='SH001', code='SH001', project=self.project) # create a child Shot (child of a Sequence) self.shot2 = Shot(name='SH002', code='SH002', parent=self.sequence1) # create a child Shot (child of a child Sequence) self.shot3 = Shot(name='SH003', code='SH003', parent=self.sequence2) # commit everything db.DBSession.add_all([ self.repo1, self.status_new, self.status_wip, self.status_comp, self.project_status_list, self.project, self.task_status_list, self.asset_status_list, self.shot_status_list, self.sequence_status_list, self.task1, self.task2, self.task3, self.task4, self.task5, self.task6, self.asset1, self.asset2, self.shot1, self.shot2, self.shot3, self.sequence1, self.sequence2, self.task_template, self.asset_template, self.shot_template, self.sequence_template ]) db.DBSession.commit() # now create versions def create_version(task, take_name): """Creates a new version :param task: the task :param take_name: the take_name name :return: the version """ # just renew the scene #pymel.core.newFile(force=True) v = Version(task=task, take_name=take_name) v.update_paths() db.DBSession.add(v) db.DBSession.commit() #self.maya_env.save_as(v) return v # asset2 self.version1 = create_version(self.asset2, 'Main') self.version2 = create_version(self.asset2, 'Main') self.version3 = create_version(self.asset2, 'Main') self.version3.description = 'Test Description' self.version4 = create_version(self.asset2, 'Take1') self.version5 = create_version(self.asset2, 'Take1') self.version6 = create_version(self.asset2, 'Take1') # task5 self.version7 = create_version(self.task5, 'Main') self.version8 = create_version(self.task5, 'Main') self.version9 = create_version(self.task5, 'Main') self.version10 = create_version(self.task5, 'Take1') self.version11 = create_version(self.task5, 'Take1') self.version12 = create_version(self.task5, 'Take1') # task6 self.version13 = create_version(self.task6, 'Main') self.version14 = create_version(self.task6, 'Main') self.version15 = create_version(self.task6, 'Main') self.version16 = create_version(self.task6, 'Take1') self.version17 = create_version(self.task6, 'Take1') self.version18 = create_version(self.task6, 'Take1') # shot3 self.version19 = create_version(self.shot3, 'Main') self.version20 = create_version(self.shot3, 'Main') self.version21 = create_version(self.shot3, 'Main') self.version22 = create_version(self.shot3, 'Take1') self.version23 = create_version(self.shot3, 'Take1') self.version24 = create_version(self.shot3, 'Take1') # task3 self.version25 = create_version(self.task3, 'Main') self.version26 = create_version(self.task3, 'Main') self.version27 = create_version(self.task3, 'Main') self.version28 = create_version(self.task3, 'Take1') self.version29 = create_version(self.task3, 'Take1') self.version30 = create_version(self.task3, 'Take1') # asset1 self.version31 = create_version(self.asset1, 'Main') self.version32 = create_version(self.asset1, 'Main') self.version33 = create_version(self.asset1, 'Main') self.version34 = create_version(self.asset1, 'Take1') self.version35 = create_version(self.asset1, 'Take1') self.version36 = create_version(self.asset1, 'Take1') # shot2 self.version37 = create_version(self.shot2, 'Main') self.version38 = create_version(self.shot2, 'Main') self.version39 = create_version(self.shot2, 'Main') self.version40 = create_version(self.shot2, 'Take1') self.version41 = create_version(self.shot2, 'Take1') self.version42 = create_version(self.shot2, 'Take1') # shot1 self.version43 = create_version(self.shot1, 'Main') self.version44 = create_version(self.shot1, 'Main') self.version45 = create_version(self.shot1, 'Main') self.version46 = create_version(self.shot1, 'Take1') self.version47 = create_version(self.shot1, 'Take1') self.version48 = create_version(self.shot1, 'Take1') # +- task1 # | | # | +- task4 # | | | # | | +- asset2 # | | +- Main # | | | +- version1 # | | | +- version2 (P) # | | | +- version3 (P) # | | +- Take1 # | | +- version4 (P) # | | +- version5 # | | +- version6 (P) # | | # | +- task5 # | | +- Main # | | | +- version7 # | | | +- version8 # | | | +- version9 # | | +- Take1 # | | +- version10 # | | +- version11 # | | +- version12 (P) # | | # | +- task6 # | +- Main # | | +- version13 # | | +- version14 # | | +- version15 # | +- Take1 # | +- version16 (P) # | +- version17 # | +- version18 (P) # | # +- task2 # | | # | +- sequence2 # | | # | +- shot3 # | +- Main # | | +- version19 # | | +- version20 # | | +- version21 # | +- Take1 # | +- version22 # | +- version23 # | +- version24 # | # +- task3 # | +- Main # | | +- version25 # | | +- version26 # | | +- version27 # | +- Take1 # | +- version28 # | +- version29 # | +- version30 # | # +- asset1 # | +- Main # | | +- version31 # | | +- version32 # | | +- version33 # | +- Take1 # | +- version34 # | +- version35 # | +- version36 # | # +- sequence1 # | | # | +- shot2 # | +- Main # | | +- version37 # | | +- version38 # | | +- version39 # | +- Take1 # | +- version40 # | +- version41 # | +- version42 # | # +- shot1 # +- Main # | +- version43 # | +- version44 # | +- version45 # +- Take1 # +- version46 # +- version47 # +- version48 # Start Condition: # # version15 # version12 # version5 # version2 -> has new published version (version3) # version5 -> Referenced a second time # version2 -> has new published version (version3) # version12 -> Referenced a second time # version5 # version2 -> has new published version (version3) # version5 # version2 -> has new published version (version3) # version45 -> no change # version48 -> no change # # Expected Final Result # version15A -> Derived from version15 # version12A -> Derived from version12 # version5A -> Derived from version5 # version3 -> has new published version (version3) # version5A -> Derived from version5 # version3 -> has new published version (version3) # version12A -> Derived from version12 - The second reference # version5A -> Derived from version5 # version3 -> has new published version (version3) # version5A -> Derived from version5 # version3 -> has new published version (version3) # version45 -> no change # version48 -> no change # create a deep relation self.version2.is_published = True self.version3.is_published = True # new scene # version5 references version2 self.version5.inputs.append(self.version2) self.version5.is_published = True # version12 references version5 self.version12.inputs.append(self.version5) self.version12.is_published = True # version45 references version48 self.version45.is_published = True self.version48.is_published = True self.version45.inputs.append(self.version48) # version15 references version12 and version48 self.version15.inputs.append(self.version12) self.version15.inputs.append(self.version45) # reference_resolution self.reference_resolution = { 'root': [self.version12, self.version45], 'leave': [self.version48, self.version45], 'update': [self.version2], 'create': [self.version5, self.version12] } # create a buffer for extra created files, which are to be removed self.remove_these_files_buffer = [] self.test_environment = TestEnvironment(name='Test Environment') self.test_environment._version = self.version15 if not QtGui.QApplication.instance(): logger.debug('creating a new QApplication') self.app = QtGui.QApplication(sys.argv) else: logger.debug('using the present QApplication: %s' % QtGui.qApp) # self.app = QtGui.qApp self.app = QtGui.QApplication.instance() self.dialog = version_updater.MainDialog( environment=self.test_environment, reference_resolution=self.reference_resolution)
def show_context_menu(self, position): """the custom context menu """ # convert the position to global screen position global_position = self.mapToGlobal(position) index = self.indexAt(position) model = self.model() item = model.itemFromIndex(index) logger.debug('itemAt(position) : %s' % item) task_id = None entity = None # if not item: # return # if item and not hasattr(item, 'task'): # return from anima.ui.models.task import TaskItem #if not isinstance(item, TaskItem): # return if item and item.task: task_id = item.task.id # if not task_id: # return from anima import utils file_browser_name = utils.file_browser_name() # create the menu menu = QtWidgets.QMenu() # Open in browser # sub menus create_sub_menu = menu.addMenu('Create') update_sub_menu = menu.addMenu('Update') # ----------------------------------- # actions created in different scopes create_time_log_action = None create_project_action = None update_task_action = None upload_thumbnail_action = None create_child_task_action = None duplicate_task_hierarchy_action = None delete_task_action = None no_deps_action = None create_project_structure_action = None create_task_structure_action = None update_project_action = None assign_users_action = None open_in_web_browser_action = None open_in_file_browser_action = None copy_url_action = None copy_id_to_clipboard = None fix_task_status_action = None change_status_menu_actions = [] from anima import defaults from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user from stalker import SimpleEntity, Task, Project # TODO: Update this to use only task_id if task_id: entity = SimpleEntity.query.get(task_id) if defaults.is_power_user(logged_in_user): # create the Create Project menu item create_project_action = \ create_sub_menu.addAction(u'\uf0e8 Create Project...') if isinstance(entity, Project): # this is a project! if defaults.is_power_user(logged_in_user): update_project_action = \ update_sub_menu.addAction(u'\uf044 Update Project...') assign_users_action = \ menu.addAction(u'\uf0c0 Assign Users...') create_project_structure_action = \ create_sub_menu.addAction( u'\uf115 Create Project Structure' ) create_child_task_action = \ create_sub_menu.addAction( u'\uf0ae Create Child Task...' ) if entity: # separate the Project and Task related menu items menu.addSeparator() open_in_web_browser_action = \ menu.addAction(u'\uf14c Open In Web Browser...') open_in_file_browser_action = \ menu.addAction(u'\uf07c Browse Folders...') copy_url_action = menu.addAction(u'\uf0c5 Copy URL') copy_id_to_clipboard = \ menu.addAction(u'\uf0c5 Copy ID to clipboard') if isinstance(entity, Task): # this is a task create_task_structure_action = \ create_sub_menu.addAction( u'\uf115 Create Task Folder Structure' ) task = entity from stalker import Status status_wfd = Status.query.filter(Status.code == 'WFD').first() status_prev = \ Status.query.filter(Status.code == 'PREV').first() status_cmpl = \ Status.query.filter(Status.code == 'CMPL').first() if logged_in_user in task.resources \ and task.status not in [status_wfd, status_prev, status_cmpl]: create_sub_menu.addSeparator() create_time_log_action = \ create_sub_menu.addAction(u'\uf073 Create TimeLog...') # Add Depends To menu menu.addSeparator() depends = task.depends if depends: depends_to_menu = menu.addMenu(u'\uf090 Depends To') for dTask in depends: action = depends_to_menu.addAction(dTask.name) action.task = dTask # Add Dependent Of Menu dependent_of = task.dependent_of if dependent_of: dependent_of_menu = menu.addMenu(u'\uf08b Dependent Of') for dTask in dependent_of: action = dependent_of_menu.addAction(dTask.name) action.task = dTask if not depends and not dependent_of: no_deps_action = menu.addAction(u'\uf00d No Dependencies') no_deps_action.setEnabled(False) # update task and create child task menu items menu.addSeparator() if defaults.is_power_user(logged_in_user): create_sub_menu.addSeparator() update_task_action = \ update_sub_menu.addAction(u'\uf044 Update Task...') upload_thumbnail_action = \ update_sub_menu.addAction( u'\uf03e Upload Thumbnail...' ) create_child_task_action = \ create_sub_menu.addAction( u'\uf0ae Create Child Task...' ) duplicate_task_hierarchy_action = \ create_sub_menu.addAction( u'\uf0c5 Duplicate Task Hierarchy...' ) delete_task_action = \ menu.addAction(u'\uf1f8 Delete Task...') # create the status_menu status_menu = update_sub_menu.addMenu('Status') fix_task_status_action = \ status_menu.addAction(u'\uf0e8 Fix Task Status') assert isinstance(status_menu, QtWidgets.QMenu) status_menu.addSeparator() # get all task statuses from anima import defaults menu_style_sheet = '' defaults_status_colors = defaults.status_colors for status_code in defaults.status_colors: change_status_menu_action = \ status_menu.addAction(status_code) change_status_menu_action.setObjectName('status_%s' % status_code) change_status_menu_actions.append( change_status_menu_action) menu_style_sheet = "%s %s" % ( menu_style_sheet, "QMenu#status_%s { background: %s %s %s}" % ( status_code, defaults_status_colors[status_code][0], defaults_status_colors[status_code][1], defaults_status_colors[status_code][2], )) # change the BG Color of the status status_menu.setStyleSheet(menu_style_sheet) try: # PySide and PySide2 accepted = QtWidgets.QDialog.DialogCode.Accepted except AttributeError: # PyQt4 accepted = QtWidgets.QDialog.Accepted selected_item = menu.exec_(global_position) if selected_item: if create_project_action \ and selected_item == create_project_action: from anima.ui import project_dialog project_main_dialog = project_dialog.MainDialog(parent=self, project=None) project_main_dialog.exec_() result = project_main_dialog.result() # refresh the task list if result == accepted: self.fill() project_main_dialog.deleteLater() if entity: from anima import defaults url = 'http://%s/%ss/%s/view' % ( defaults.stalker_server_internal_address, entity.entity_type.lower(), entity.id) if selected_item is open_in_web_browser_action: import webbrowser webbrowser.open(url) elif selected_item is open_in_file_browser_action: from anima import utils try: utils.open_browser_in_location(entity.absolute_path) except IOError as e: QtWidgets.QMessageBox.critical( self, "Error", "%s" % e, QtWidgets.QMessageBox.Ok) elif selected_item is copy_url_action: clipboard = QtWidgets.QApplication.clipboard() clipboard.setText(url) # and warn the user about a new version is created and the # clipboard is set to the new version full path QtWidgets.QMessageBox.warning( self, "URL Copied To Clipboard", "URL:<br><br>%s<br><br>is copied to clipboard!" % url, QtWidgets.QMessageBox.Ok) elif selected_item is copy_id_to_clipboard: clipboard = QtWidgets.QApplication.clipboard() clipboard.setText('%s' % entity.id) # and warn the user about a new version is created and the # clipboard is set to the new version full path QtWidgets.QMessageBox.warning( self, "ID Copied To Clipboard", "ID %s is copied to clipboard!" % entity.id, QtWidgets.QMessageBox.Ok) elif selected_item is create_time_log_action: from anima.ui import time_log_dialog time_log_dialog_main_dialog = time_log_dialog.MainDialog( parent=self, task=entity, ) time_log_dialog_main_dialog.exec_() result = time_log_dialog_main_dialog.result() time_log_dialog_main_dialog.deleteLater() if result == accepted: # refresh the task list if item.parent: item.parent.reload() else: self.fill() # reselect the same task self.find_and_select_entity_item(entity) elif selected_item is update_task_action: from anima.ui import task_dialog task_main_dialog = task_dialog.MainDialog(parent=self, task=entity) task_main_dialog.exec_() result = task_main_dialog.result() task_main_dialog.deleteLater() # refresh the task list if result == accepted: # just reload the same item if item.parent: item.parent.reload() else: # reload the entire self.fill() self.find_and_select_entity_item(entity) elif selected_item is upload_thumbnail_action: from anima.ui import utils as ui_utils thumbnail_full_path = ui_utils.choose_thumbnail(self) # if the thumbnail_full_path is empty do not do anything if thumbnail_full_path == "": return # get the current task ui_utils.upload_thumbnail(entity, thumbnail_full_path) elif selected_item == create_child_task_action: from anima.ui import task_dialog task_main_dialog = task_dialog.MainDialog( parent=self, parent_task=entity) task_main_dialog.exec_() result = task_main_dialog.result() task = task_main_dialog.task task_main_dialog.deleteLater() if result == accepted and task: # reload the parent item if item.parent: item.parent.reload() else: self.fill() self.find_and_select_entity_item(task) elif selected_item is duplicate_task_hierarchy_action: duplicate_task_hierarchy_dialog = \ DuplicateTaskHierarchyDialog( parent=self, duplicated_task_name=item.task.name ) duplicate_task_hierarchy_dialog.exec_() result = duplicate_task_hierarchy_dialog.result() if result == accepted: new_task_name = \ duplicate_task_hierarchy_dialog.line_edit.text() keep_resources = \ duplicate_task_hierarchy_dialog\ .check_box.checkState() from anima import utils from stalker import Task task = Task.query.get(item.task.id) new_task = utils.duplicate_task_hierarchy( task, None, new_task_name, description='Duplicated from Task(%s)' % task.id, user=logged_in_user, keep_resources=keep_resources) if new_task: from stalker.db.session import DBSession DBSession.commit() item.parent.reload() self.find_and_select_entity_item(new_task) elif selected_item is delete_task_action: answer = QtWidgets.QMessageBox.question( self, 'Delete Task?', "Delete the task and children?<br><br>(NO UNDO!!!!)", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from stalker.db.session import DBSession from stalker import Task task = Task.query.get(item.task.id) DBSession.delete(task) DBSession.commit() # reload the parent if item.parent: item.parent.reload() else: self.fill() self.find_and_select_entity_item(item.parent.task) elif selected_item == create_project_structure_action: answer = QtWidgets.QMessageBox.question( self, 'Create Project Folder Structure?', "This will create project folders, OK?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from anima import utils try: utils.create_project_structure(entity) except Exception as e: pass finally: QtWidgets.QMessageBox.information( self, 'Project Folder Structure is created!', 'Project Folder Structure is created!', ) else: return elif selected_item == create_task_structure_action: answer = QtWidgets.QMessageBox.question( self, 'Create Folder Structure?', "This will create task folders, OK?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from anima import utils try: utils.create_task_structure(entity) except Exception as e: pass finally: QtWidgets.QMessageBox.information( self, 'Folder Structure is created!', 'Folder Structure is created!', ) else: return elif selected_item == fix_task_status_action: from stalker import Task if isinstance(entity, Task): from anima import utils utils.fix_task_statuses(entity) from stalker.db.session import DBSession DBSession.add(entity) DBSession.commit() if item.parent: item.parent.reload() elif selected_item == update_project_action: from anima.ui import project_dialog project_main_dialog = project_dialog.MainDialog( parent=self, project=entity) project_main_dialog.exec_() result = project_main_dialog.result() # refresh the task list if result == accepted: self.fill() # reselect the same task self.find_and_select_entity_item(entity) project_main_dialog.deleteLater() elif selected_item == assign_users_action: from anima.ui import project_users_dialog project_users_main_dialog = \ project_users_dialog.MainDialog( parent=self, project=entity ) project_users_main_dialog.exec_() result = project_users_main_dialog.result() project_users_main_dialog.deleteLater() elif selected_item in change_status_menu_actions: # get the status code status_code = selected_item.text() from sqlalchemy import func status = \ Status.query.filter( func.lower(Status.code) == func.lower(status_code) ).first() # change the status of the entity # if it is a leaf task # if it doesn't have any dependent_of # assert isinstance(entity, Task) if isinstance(entity, Task): if entity.is_leaf and not entity.dependent_of: # then we can update it entity.status = status # # fix other task statuses # from anima import utils # utils.fix_task_statuses(entity) # refresh the tree from stalker.db.session import DBSession DBSession.add(entity) DBSession.commit() if item.parent: item.parent.reload() self.find_and_select_entity_item(entity) else: try: # go to the dependencies dep_task = selected_item.task self.find_and_select_entity_item(dep_task, self) except AttributeError: pass
def show_context_menu(self, position): """the custom context menu """ # convert the position to global screen position global_position = self.mapToGlobal(position) index = self.indexAt(position) model = self.model() item = model.itemFromIndex(index) logger.debug('itemAt(position) : %s' % item) task_id = None entity = None # if not item: # return # if item and not hasattr(item, 'task'): # return if item and item.task: task_id = item.task.id # if not task_id: # return from anima import utils file_browser_name = utils.file_browser_name() # create the menu menu = QtWidgets.QMenu() # Open in browser # ----------------------------------- # actions created in different scopes create_time_log_action = None create_project_action = None update_task_action = None create_child_task_action = None duplicate_task_hierarchy_action = None delete_task_action = None no_deps_action = None create_project_structure_action = None create_task_structure_action = None update_project_action = None open_in_web_browser_action = None open_in_file_browser_action = None copy_url_action = None copy_id_to_clipboard = None from anima import defaults from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user from stalker import SimpleEntity, Task, Project # TODO: Update this to use only task_id if task_id: entity = SimpleEntity.query.get(task_id) if defaults.is_power_user(logged_in_user): # create the Create Project menu item create_project_action = menu.addAction(u'\uf0e8 Create Project...') if isinstance(entity, Project): # this is a project! if defaults.is_power_user(logged_in_user): update_project_action = \ menu.addAction(u'\uf044 Update Project...') create_project_structure_action = \ menu.addAction(u'\uf115 Create Project Structure') create_child_task_action = \ menu.addAction(u'\uf0ae Create Child Task...') if entity: # separate the Project and Task related menu items menu.addSeparator() open_in_web_browser_action = \ menu.addAction(u'\uf14c Open In Web Browser...') open_in_file_browser_action = \ menu.addAction(u'\uf07c Open In %s...' % file_browser_name) copy_url_action = menu.addAction(u'\uf0c5 Copy URL') copy_id_to_clipboard = \ menu.addAction(u'\uf0c5 Copy ID to clipboard') if isinstance(entity, Task): # this is a task create_task_structure_action = \ menu.addAction(u'\uf115 Create Task Structure') task = entity from stalker import Status status_wfd = Status.query.filter(Status.code == 'WFD').first() status_prev = \ Status.query.filter(Status.code == 'PREV').first() status_cmpl = \ Status.query.filter(Status.code == 'CMPL').first() if logged_in_user in task.resources \ and task.status not in [status_wfd, status_prev, status_cmpl]: menu.addSeparator() create_time_log_action = \ menu.addAction(u'\uf073 Create TimeLog...') # update task and create child task menu items if defaults.is_power_user(logged_in_user): menu.addSeparator() update_task_action = \ menu.addAction(u'\uf044 Update Task...') create_child_task_action = \ menu.addAction(u'\uf0ae Create Child Task...') duplicate_task_hierarchy_action = \ menu.addAction(u'\uf0c5 Duplicate Task Hierarchy...') delete_task_action = \ menu.addAction(u'\uf1f8 Delete Task...') menu.addSeparator() # Add Depends To menu depends = task.depends if depends: depends_to_menu = menu.addMenu(u'\uf090 Depends To') for dTask in depends: action = depends_to_menu.addAction(dTask.name) action.task = dTask # Add Dependent Of Menu dependent_of = task.dependent_of if dependent_of: dependent_of_menu = menu.addMenu(u'\uf08b Dependent Of') for dTask in dependent_of: action = dependent_of_menu.addAction(dTask.name) action.task = dTask if not depends and not dependent_of: no_deps_action = menu.addAction(u'\uf00d No Dependencies') no_deps_action.setEnabled(False) try: # PySide and PySide2 accepted = QtWidgets.QDialog.DialogCode.Accepted except AttributeError: # PyQt4 accepted = QtWidgets.QDialog.Accepted selected_item = menu.exec_(global_position) if selected_item: if create_project_action \ and selected_item == create_project_action: from anima.ui import project_dialog project_main_dialog = project_dialog.MainDialog(parent=self, project=None) project_main_dialog.exec_() result = project_main_dialog.result() # refresh the task list if result == accepted: self.fill() project_main_dialog.deleteLater() if entity: from anima import defaults url = 'http://%s/%ss/%s/view' % ( defaults.stalker_server_internal_address, entity.entity_type.lower(), entity.id) if selected_item is open_in_web_browser_action: import webbrowser webbrowser.open(url) elif selected_item is open_in_file_browser_action: from anima import utils utils.open_browser_in_location(entity.absolute_path) elif selected_item is copy_url_action: clipboard = QtWidgets.QApplication.clipboard() clipboard.setText(url) # and warn the user about a new version is created and the # clipboard is set to the new version full path QtWidgets.QMessageBox.warning( self, "URL Copied To Clipboard", "URL:<br><br>%s<br><br>is copied to clipboard!" % url, QtWidgets.QMessageBox.Ok) elif selected_item is copy_id_to_clipboard: clipboard = QtWidgets.QApplication.clipboard() clipboard.setText('%s' % entity.id) # and warn the user about a new version is created and the # clipboard is set to the new version full path QtWidgets.QMessageBox.warning( self, "ID Copied To Clipboard", "ID %s is copied to clipboard!" % entity.id, QtWidgets.QMessageBox.Ok) elif selected_item is create_time_log_action: from anima.ui import time_log_dialog time_log_dialog_main_dialog = time_log_dialog.MainDialog( parent=self, task=entity, ) time_log_dialog_main_dialog.exec_() result = time_log_dialog_main_dialog.result() time_log_dialog_main_dialog.deleteLater() if result == accepted: # refresh the task list if item.parent: item.parent.reload() else: self.fill() # reselect the same task self.find_and_select_entity_item(entity) elif selected_item is update_task_action: from anima.ui import task_dialog task_main_dialog = task_dialog.MainDialog(parent=self, task=entity) task_main_dialog.exec_() result = task_main_dialog.result() task_main_dialog.deleteLater() # refresh the task list if result == accepted: # just reload the same item if item.parent: item.parent.reload() else: # reload the entire self.fill() self.find_and_select_entity_item(entity) elif selected_item == create_child_task_action: from anima.ui import task_dialog task_main_dialog = task_dialog.MainDialog( parent=self, parent_task=entity) task_main_dialog.exec_() result = task_main_dialog.result() task = task_main_dialog.task task_main_dialog.deleteLater() if result == accepted and task: # reload the parent item if item.parent: item.parent.reload() else: self.fill() self.find_and_select_entity_item(task) elif selected_item is duplicate_task_hierarchy_action: new_task_name, result = QtWidgets.QInputDialog.getText( self, "Input Dialog", "Duplicated Task Name:", QtWidgets.QLineEdit.Normal, item.task.name) if result: from anima import utils from stalker import Task task = Task.query.get(item.task.id) new_task = utils.duplicate_task_hierarchy( task, None, new_task_name, description='Duplicated from Task(%s)' % task.id, user=logged_in_user) if new_task: from stalker.db.session import DBSession DBSession.commit() item.parent.reload() self.find_and_select_entity_item(new_task) elif selected_item is delete_task_action: answer = QtWidgets.QMessageBox.question( self, 'Delete Task?', "Delete the task and children?<br><br>(NO UNDO!!!!)", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from stalker.db.session import DBSession from stalker import Task task = Task.query.get(item.task.id) DBSession.delete(task) DBSession.commit() # reload the parent if item.parent: item.parent.reload() else: self.fill() self.find_and_select_entity_item(item.parent.task) elif selected_item == create_project_structure_action: answer = QtWidgets.QMessageBox.question( self, 'Create Project Structure?', "This will create project folders, OK?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from anima import utils try: utils.create_project_structure(entity) except Exception as e: pass finally: QtWidgets.QMessageBox.information( self, 'Project Structure is created!', 'Project Structure is created!', ) else: return elif selected_item == create_task_structure_action: answer = QtWidgets.QMessageBox.question( self, 'Create Task Structure?', "This will create task folders, OK?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from anima import utils try: utils.create_task_structure(entity) except Exception as e: pass finally: QtWidgets.QMessageBox.information( self, 'Task Structure is created!', 'Task Structure is created!', ) else: return elif selected_item == update_project_action: from anima.ui import project_dialog project_main_dialog = project_dialog.MainDialog( parent=self, project=entity) project_main_dialog.exec_() result = project_main_dialog.result() # refresh the task list if result == accepted: self.fill() # reselect the same task self.find_and_select_entity_item(entity) project_main_dialog.deleteLater() else: # go to the dependencies dep_task = selected_item.task self.find_and_select_entity_item(dep_task, self)
def __init__(self): from anima.utils import do_db_setup from stalker import Type, LocalSession from anima.env import mayaEnv do_db_setup() m = mayaEnv.Maya() local_session = LocalSession() self.logged_in_user = local_session.logged_in_user if not self.logged_in_user: raise RuntimeError('Please login to Stalker') if not m.get_current_version(): raise RuntimeError('This scene is not saved with Stalker') self.anim_type = Type.query.filter(Type.name == "Animation").first() self.prev_type = Type.query.filter(Type.name == "Previs").first() # get current task info self.current_version = m.get_current_version() self.current_task = self.current_version.task self.current_type = self.current_task.type # check task type if self.current_type not in [self.anim_type, self.prev_type]: raise RuntimeError( 'Task must be either an Animation or Previs Task.') # query sequenceManager if len(pm.ls(type='sequenceManager')) is not 1: raise RuntimeError('There must be just 1 sequenceManager.') self.sm = pm.ls('sequenceManager1')[0] # query sequencer seqs = [ seq for seq in pm.ls(type='sequencer') if seq.referenceFile() is None ] if len(seqs) is not 1: raise RuntimeError('There must be just 1 sequencer.') self.sequencer = self.sm.sequences.get()[0] # query all shots in sequencer self.shot_list = self.sequencer.shots.get() # query shots in time based descending order shots = self.shot_list shots_sorted = [] shots_mid_frames = [] mid_frames = [] for shot in shots: start = shot.getSequenceStartTime() end = shot.getSequenceEndTime() mid_frame = int(start + ((end - start) / 2)) shots_mid_frames.append([shot, mid_frame]) mid_frames.append(mid_frame) mid_frames.sort() inc = -1 for frame in mid_frames: inc += 1 for shot in shots_mid_frames: if frame == shot[1]: if shot[0] not in shots_sorted: shots_sorted.append(shot[0]) self.shots_descending = shots_sorted # query all shot tasks from current scene shot_task = None parent_task = None if self.current_type is self.prev_type: parent_task = self.current_task.parent elif self.current_type is self.anim_type: parent_task = self.current_task.parent.parent if parent_task is None: raise RuntimeError('Current Task does not have Proper Parents.') for task in parent_task.walk_hierarchy(): if task.nice_name == 'Shots': shot_task = task break if shot_task is None: raise RuntimeError('Shots Task can not be found.') self.scene_shot_tasks = shot_task.tasks
def show_context_menu(self, position): """the custom context menu """ # convert the position to global screen position global_position = self.mapToGlobal(position) index = self.indexAt(position) model = self.model() item = model.itemFromIndex(index) logger.debug('itemAt(position) : %s' % item) task_id = None entity = None # if not item: # return # if item and not hasattr(item, 'task'): # return # from anima.ui.models.task import TaskItem # if not isinstance(item, TaskItem): # return if item: try: if item.task: task_id = item.task.id except AttributeError: return # if not task_id: # return from anima import utils file_browser_name = utils.file_browser_name() # create the menu menu = QtWidgets.QMenu() # Open in browser # ----------------------------------- # actions created in different scopes create_time_log_action = None create_project_action = None update_task_action = None upload_thumbnail_action = None create_child_task_action = None duplicate_task_hierarchy_action = None delete_task_action = None export_to_json_action = None import_from_json_action = None no_deps_action = None create_project_structure_action = None update_project_action = None assign_users_action = None open_in_web_browser_action = None open_in_file_browser_action = None copy_url_action = None copy_id_to_clipboard = None fix_task_status_action = None change_status_menu_actions = [] from anima import defaults from stalker import LocalSession local_session = LocalSession() logged_in_user = local_session.logged_in_user from stalker import SimpleEntity, Task, Project # TODO: Update this to use only task_id if task_id: entity = SimpleEntity.query.get(task_id) reload_action = menu.addAction(u'\uf0e8 Reload') # sub menus create_sub_menu = menu.addMenu('Create') update_sub_menu = menu.addMenu('Update') if defaults.is_power_user(logged_in_user): # create the Create Project menu item create_project_action = create_sub_menu.addAction( u'\uf0e8 Create Project...') if isinstance(entity, Project): # this is a project! if defaults.is_power_user(logged_in_user): update_project_action = update_sub_menu.addAction( u'\uf044 Update Project...') assign_users_action = menu.addAction( u'\uf0c0 Assign Users...') create_project_structure_action = create_sub_menu.addAction( u'\uf115 Create Project Structure') create_child_task_action = create_sub_menu.addAction( u'\uf0ae Create Child Task...') # Export and Import JSON create_sub_menu.addSeparator() # export_to_json_action = create_sub_menu.addAction(u'\uf1f8 Export To JSON...') import_from_json_action = create_sub_menu.addAction( u'\uf1f8 Import From JSON...') if entity: # separate the Project and Task related menu items menu.addSeparator() open_in_web_browser_action = menu.addAction( u'\uf14c Open In Web Browser...') open_in_file_browser_action = menu.addAction( u'\uf07c Browse Folders...') copy_url_action = menu.addAction(u'\uf0c5 Copy URL') copy_id_to_clipboard = menu.addAction( u'\uf0c5 Copy ID to clipboard') if isinstance(entity, Task): # this is a task create_project_structure_action = create_sub_menu.addAction( u'\uf115 Create Task Folder Structure') task = entity from stalker import Status status_wfd = Status.query.filter(Status.code == 'WFD').first() status_prev = Status.query.filter( Status.code == 'PREV').first() status_cmpl = Status.query.filter( Status.code == 'CMPL').first() if logged_in_user in task.resources and task.status not in [ status_wfd, status_prev, status_cmpl ]: create_sub_menu.addSeparator() create_time_log_action = create_sub_menu.addAction( u'\uf073 Create TimeLog...') # Add Depends To menu menu.addSeparator() depends = task.depends if depends: depends_to_menu = menu.addMenu(u'\uf090 Depends To') for dTask in depends: action = depends_to_menu.addAction(dTask.name) action.task = dTask # Add Dependent Of Menu dependent_of = task.dependent_of if dependent_of: dependent_of_menu = menu.addMenu(u'\uf08b Dependent Of') for dTask in dependent_of: action = dependent_of_menu.addAction(dTask.name) action.task = dTask if not depends and not dependent_of: no_deps_action = menu.addAction(u'\uf00d No Dependencies') no_deps_action.setEnabled(False) # update task and create child task menu items menu.addSeparator() if defaults.is_power_user(logged_in_user): create_sub_menu.addSeparator() update_task_action = update_sub_menu.addAction( u'\uf044 Update Task...') upload_thumbnail_action = update_sub_menu.addAction( u'\uf03e Upload Thumbnail...') # Export and Import JSON create_sub_menu.addSeparator() export_to_json_action = create_sub_menu.addAction( u'\uf1f8 Export To JSON...') import_from_json_action = create_sub_menu.addAction( u'\uf1f8 Import From JSON...') create_sub_menu.addSeparator() create_child_task_action = create_sub_menu.addAction( u'\uf0ae Create Child Task...') duplicate_task_hierarchy_action = create_sub_menu.addAction( u'\uf0c5 Duplicate Task Hierarchy...') delete_task_action = menu.addAction( u'\uf1f8 Delete Task...') menu.addSeparator() # create the status_menu status_menu = update_sub_menu.addMenu('Status') fix_task_status_action = status_menu.addAction( u'\uf0e8 Fix Task Status') assert isinstance(status_menu, QtWidgets.QMenu) status_menu.addSeparator() # get all task statuses from anima import defaults menu_style_sheet = '' defaults_status_colors = defaults.status_colors for status_code in defaults.status_colors: change_status_menu_action = status_menu.addAction( status_code) change_status_menu_action.setObjectName('status_%s' % status_code) change_status_menu_actions.append( change_status_menu_action) menu_style_sheet = "%s %s" % ( menu_style_sheet, "QMenu#status_%s { background: %s %s %s}" % ( status_code, defaults_status_colors[status_code][0], defaults_status_colors[status_code][1], defaults_status_colors[status_code][2], )) # change the BG Color of the status status_menu.setStyleSheet(menu_style_sheet) try: # PySide and PySide2 accepted = QtWidgets.QDialog.DialogCode.Accepted except AttributeError: # PyQt4 accepted = QtWidgets.QDialog.Accepted selected_action = menu.exec_(global_position) if selected_action: if selected_action is reload_action: if isinstance(entity, Project): self.fill() self.find_and_select_entity_item(item.task) else: for item in self.get_selected_task_items(): item.reload() if create_project_action \ and selected_action is create_project_action: from anima.ui import project_dialog project_main_dialog = project_dialog.MainDialog(parent=self, project=None) project_main_dialog.exec_() result = project_main_dialog.result() # refresh the task list if result == accepted: self.fill() project_main_dialog.deleteLater() if entity: from anima import defaults url = 'http://%s/%ss/%s/view' % ( defaults.stalker_server_internal_address, entity.entity_type.lower(), entity.id) if selected_action is open_in_web_browser_action: import webbrowser webbrowser.open(url) elif selected_action is open_in_file_browser_action: from anima import utils try: utils.open_browser_in_location(entity.absolute_path) except IOError as e: QtWidgets.QMessageBox.critical( self, "Error", "%s" % e, QtWidgets.QMessageBox.Ok) elif selected_action is copy_url_action: clipboard = QtWidgets.QApplication.clipboard() clipboard.setText(url) # and warn the user about a new version is created and the # clipboard is set to the new version full path QtWidgets.QMessageBox.warning( self, "URL Copied To Clipboard", "URL:<br><br>%s<br><br>is copied to clipboard!" % url, QtWidgets.QMessageBox.Ok) elif selected_action is copy_id_to_clipboard: clipboard = QtWidgets.QApplication.clipboard() selected_entity_ids = ', '.join( list(map(str, self.get_selected_task_ids()))) clipboard.setText(selected_entity_ids) # and warn the user about a new version is created and the # clipboard is set to the new version full path QtWidgets.QMessageBox.warning( self, "ID Copied To Clipboard", "IDs are copied to clipboard!<br>%s" % selected_entity_ids, QtWidgets.QMessageBox.Ok) elif selected_action is create_time_log_action: from anima.ui import time_log_dialog time_log_dialog_main_dialog = time_log_dialog.MainDialog( parent=self, task=entity, ) time_log_dialog_main_dialog.exec_() result = time_log_dialog_main_dialog.result() time_log_dialog_main_dialog.deleteLater() if result == accepted: # refresh the task list if item.parent: item.parent.reload() else: self.fill() # reselect the same task self.find_and_select_entity_item(entity) elif selected_action is update_task_action: from anima.ui import task_dialog task_main_dialog = task_dialog.MainDialog( parent=self, tasks=self.get_selected_tasks()) task_main_dialog.exec_() result = task_main_dialog.result() task_main_dialog.deleteLater() # refresh the task list if result == accepted: # just reload the same item if item.parent: item.parent.reload() else: # reload the entire self.fill() self.find_and_select_entity_item(entity) elif selected_action is upload_thumbnail_action: from anima.ui import utils as ui_utils thumbnail_full_path = ui_utils.choose_thumbnail( self, start_path=entity.absolute_path, dialog_title="Choose Thumbnail For: %s" % entity.name) # if the thumbnail_full_path is empty do not do anything if thumbnail_full_path == "": return # get the current task anima.utils.upload_thumbnail(entity, thumbnail_full_path) elif selected_action is create_child_task_action: from anima.ui import task_dialog task_main_dialog = task_dialog.MainDialog( parent=self, parent_task=entity) task_main_dialog.exec_() result = task_main_dialog.result() tasks = task_main_dialog.tasks task_main_dialog.deleteLater() if result == accepted and tasks: # reload the parent item if item.parent: item.parent.reload() else: self.fill() self.find_and_select_entity_item(tasks[0]) elif selected_action is duplicate_task_hierarchy_action: duplicate_task_hierarchy_dialog = \ DuplicateTaskHierarchyDialog( parent=self, duplicated_task_name=item.task.name ) duplicate_task_hierarchy_dialog.exec_() result = duplicate_task_hierarchy_dialog.result() if result == accepted: new_task_name = duplicate_task_hierarchy_dialog.line_edit.text( ) keep_resources = duplicate_task_hierarchy_dialog.check_box.checkState( ) from anima import utils from stalker import Task task = Task.query.get(item.task.id) new_task = utils.duplicate_task_hierarchy( task, None, new_task_name, description='Duplicated from Task(%s)' % task.id, user=logged_in_user, keep_resources=keep_resources) if new_task: from stalker.db.session import DBSession DBSession.commit() item.parent.reload() self.find_and_select_entity_item(new_task) elif selected_action is delete_task_action: answer = QtWidgets.QMessageBox.question( self, 'Delete Task?', "Delete the task and children?<br><br>(NO UNDO!!!!)", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from stalker.db.session import DBSession from stalker import Task tasks = self.get_selected_tasks() logger.debug("tasks : %s" % tasks) task = Task.query.get(item.task.id) # get the next sibling or the previous # to select after deletion select_task = item.parent.task if task.parent: all_siblings = list( Task.query.filter( Task.parent == task.parent).order_by( Task.name).all()) if len(all_siblings) > 1: sibling_index = all_siblings.index(task) if sibling_index < len(all_siblings) - 1: # this is not the last task in the list # select next one select_task = all_siblings[sibling_index + 1] elif sibling_index == len(all_siblings) - 1: # this is the last task # select previous task select_task = all_siblings[sibling_index - 1] for task in tasks: DBSession.delete(task) DBSession.commit() # reload the parent unique_parent_items = [] for item in self.get_selected_task_items(): if item.parent and item.parent not in unique_parent_items: unique_parent_items.append(item.parent) if unique_parent_items: for parent_item in unique_parent_items: parent_item.reload() else: self.fill() # either select the next or previous task or the parent self.find_and_select_entity_item(select_task) elif selected_action is export_to_json_action: # show a file browser dialog = QtWidgets.QFileDialog(self, "Choose file") dialog.setNameFilter("JSON Files (*.json)") dialog.setFileMode(QtWidgets.QFileDialog.AnyFile) if dialog.exec_(): file_path = dialog.selectedFiles()[0] if file_path: import os import json from anima.utils import task_hierarchy_io # check file extension parts = os.path.splitext(file_path) if not parts[1]: file_path = '%s%s' % (parts[0], '.json') data = json.dumps( entity, cls=task_hierarchy_io.StalkerEntityEncoder, check_circular=False, indent=4) try: with open(file_path, 'w') as f: f.write(data) except Exception as e: pass finally: QtWidgets.QMessageBox.information( self, 'Task data Export to JSON!', 'Task data Export to JSON!', ) elif selected_action is import_from_json_action: # show a file browser dialog = QtWidgets.QFileDialog(self, "Choose file") dialog.setNameFilter("JSON Files (*.json)") dialog.setFileMode(QtWidgets.QFileDialog.ExistingFile) if dialog.exec_(): file_path = dialog.selectedFiles()[0] if file_path: import json with open(file_path) as f: data = json.load(f) from anima.utils import task_hierarchy_io if isinstance(entity, Task): project = entity.project elif isinstance(entity, Project): project = entity parent = None if isinstance(entity, Task): parent = entity decoder = \ task_hierarchy_io.StalkerEntityDecoder( project=project ) loaded_entity = decoder.loads(data, parent=parent) try: from stalker.db.session import DBSession DBSession.add(loaded_entity) DBSession.commit() except Exception as e: QtWidgets.QMessageBox.critical( self, "Error!", "%s" % e, QtWidgets.QMessageBox.Ok) else: item.reload() QtWidgets.QMessageBox.information( self, 'New Tasks are created!', 'New Tasks are created', ) elif selected_action is create_project_structure_action: answer = QtWidgets.QMessageBox.question( self, 'Create Project Folder Structure?', "This will create project folders, OK?", QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No) if answer == QtWidgets.QMessageBox.Yes: from anima import utils try: for task in self.get_selected_tasks(): utils.create_structure(task) except Exception as e: QtWidgets.QMessageBox.critical( self, "Error", str(e)) finally: QtWidgets.QMessageBox.information( self, 'Project Folder Structure is created!', 'Project Folder Structure is created!', ) else: return elif selected_action is fix_task_status_action: from stalker.db.session import DBSession from stalker import SimpleEntity, Task from anima import utils for entity in self.get_selected_tasks(): if isinstance(entity, Task): utils.fix_task_statuses(entity) utils.fix_task_computed_time(entity) DBSession.add(entity) DBSession.commit() unique_parent_items = [] for item in self.get_selected_task_items(): if item.parent and item.parent not in unique_parent_items: unique_parent_items.append(item.parent) for parent_item in unique_parent_items: parent_item.reload() elif selected_action is update_project_action: from anima.ui import project_dialog project_main_dialog = project_dialog.MainDialog( parent=self, project=entity) project_main_dialog.exec_() result = project_main_dialog.result() # refresh the task list if result == accepted: self.fill() # reselect the same task self.find_and_select_entity_item(entity) project_main_dialog.deleteLater() elif selected_action is assign_users_action: from anima.ui import project_users_dialog project_users_main_dialog = \ project_users_dialog.MainDialog( parent=self, project=entity ) project_users_main_dialog.exec_() result = project_users_main_dialog.result() project_users_main_dialog.deleteLater() elif selected_action in change_status_menu_actions: # get the status code status_code = selected_action.text() from sqlalchemy import func status = Status.query.filter( func.lower(Status.code) == func.lower( status_code)).first() # change the status of the entity # if it is a leaf task # if it doesn't have any dependent_of # assert isinstance(entity, Task) for task in self.get_selected_tasks(): if task.is_leaf and not task.dependent_of: # then we can update it task.status = status # # fix other task statuses # from anima import utils # utils.fix_task_statuses(entity) # refresh the tree from stalker.db.session import DBSession DBSession.add(task) DBSession.commit() if item.parent: item.parent.reload() self.find_and_select_entity_item(entity) else: try: # go to the dependencies dep_task = selected_action.task self.find_and_select_entity_item(dep_task, self) except AttributeError: pass
def publish_model_as_look_dev(cls): """Publishes Model versions as LookDev versions of the same task. Also handles references etc. """ # # Create LookDev for Current Model Task # from stalker import Task, Version, Type, LocalSession from stalker.db.session import DBSession from anima import defaults from anima.env import mayaEnv do_db_setup() m = mayaEnv.Maya() local_session = LocalSession() logged_in_user = local_session.logged_in_user if not logged_in_user: raise RuntimeError('Please login to Stalker') model_type = Type.query.filter(Type.name=="Model").first() look_dev_type = \ Type.query.filter(Type.name=="Look Development").first() current_version = m.get_current_version() model_task = current_version.task if model_task.type != model_type: raise RuntimeError('This is not a Model version') if not current_version.is_published: raise RuntimeError('Please Publish this maya scene') if current_version.take_name != 'Main': raise RuntimeError('This is not the Main take') # find lookDev look_dev = Task.query\ .filter(Task.parent == model_task.parent)\ .filter(Task.type == look_dev_type).first() if not look_dev: raise RuntimeError( 'There is no LookDev task, please inform your Stalker admin' ) previous_look_dev_version = \ Version.query\ .filter(Version.task == look_dev)\ .filter(Version.take_name == 'Main')\ .first() description = 'Auto Created By %s ' % logged_in_user.name take_name = defaults.version_take_name if not previous_look_dev_version: # do the trick pm.newFile(f=1) # create a new version new_version = Version( task=look_dev, description=description, take_name=take_name, created_by=logged_in_user ) new_version.is_published = True m.save_as(new_version) # reference the model version pm.createReference( current_version.absolute_full_path, gl=True, namespace=current_version.nice_name, options='v=0' ) pm.saveFile() DBSession.add(new_version) else: latest_look_dev_version = previous_look_dev_version.latest_version reference_resolution = m.open(latest_look_dev_version, force=True, skip_update_check=True) m.update_versions(reference_resolution) if reference_resolution['update'] \ or reference_resolution['create']: # create a new version new_version = Version( task=look_dev, description=description, take_name=take_name, created_by=logged_in_user, parent=latest_look_dev_version ) new_version.is_published = True m.save_as(new_version) # reopen model scene m.open(current_version, force=True, skip_update_check=True)
def setUp(self): """setup the tests """ # ----------------------------------------------------------------- # start of the setUp # create the environment variable and point it to a temp directory db.setup() db.init() self.temp_repo_path = tempfile.mkdtemp() self.user1 = User( name='User 1', login='******', email='*****@*****.**', password='******' ) db.DBSession.add(self.user1) db.DBSession.commit() # login as self.user1 from stalker import LocalSession local_session = LocalSession() local_session.store_user(self.user1) local_session.save() self.repo1 = Repository( name='Test Project Repository', linux_path=self.temp_repo_path, windows_path=self.temp_repo_path, osx_path=self.temp_repo_path ) self.status_new = Status.query.filter_by(code='NEW').first() self.status_wip = Status.query.filter_by(code='WIP').first() self.status_comp = Status.query.filter_by(code='CMPL').first() self.task_template = FilenameTemplate( name='Task Template', target_entity_type='Task', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.asset_template = FilenameTemplate( name='Asset Template', target_entity_type='Asset', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.shot_template = FilenameTemplate( name='Shot Template', target_entity_type='Shot', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.sequence_template = FilenameTemplate( name='Sequence Template', target_entity_type='Sequence', path='{{project.code}}/' '{%- for parent_task in parent_tasks -%}' '{{parent_task.nice_name}}/' '{%- endfor -%}', filename='{{version.nice_name}}' '_v{{"%03d"|format(version.version_number)}}', ) self.structure = Structure( name='Project Struture', templates=[self.task_template, self.asset_template, self.shot_template, self.sequence_template] ) self.project_status_list = StatusList( name='Project Statuses', target_entity_type='Project', statuses=[self.status_new, self.status_wip, self.status_comp] ) self.image_format = ImageFormat( name='HD 1080', width=1920, height=1080, pixel_aspect=1.0 ) # create a test project self.project = Project( name='Test Project', code='TP', repository=self.repo1, status_list=self.project_status_list, structure=self.structure, image_format=self.image_format ) self.task_status_list =\ StatusList.query.filter_by(target_entity_type='Task').first() self.asset_status_list =\ StatusList.query.filter_by(target_entity_type='Asset').first() self.shot_status_list =\ StatusList.query.filter_by(target_entity_type='Shot').first() self.sequence_status_list =\ StatusList.query.filter_by(target_entity_type='Sequence').first() self.character_type = Type( name='Character', code='CHAR', target_entity_type='Asset' ) # create a test series of root task self.task1 = Task( name='Test Task 1', project=self.project ) self.task2 = Task( name='Test Task 2', project=self.project ) self.task3 = Task( name='Test Task 3', project=self.project ) # then a couple of child tasks self.task4 = Task( name='Test Task 4', parent=self.task1 ) self.task5 = Task( name='Test Task 5', parent=self.task1 ) self.task6 = Task( name='Test Task 6', parent=self.task1 ) # create a root asset self.asset1 = Asset( name='Asset 1', code='asset1', type=self.character_type, project=self.project ) # create a child asset self.asset2 = Asset( name='Asset 2', code='asset2', type=self.character_type, parent=self.task4 ) # create a root Sequence self.sequence1 = Sequence( name='Sequence1', code='SEQ1', project=self.project ) # create a child Sequence self.sequence2 = Sequence( name='Sequence2', code='SEQ2', parent=self.task2 ) # create a root Shot self.shot1 = Shot( name='SH001', code='SH001', project=self.project ) # create a child Shot (child of a Sequence) self.shot2 = Shot( name='SH002', code='SH002', parent=self.sequence1 ) # create a child Shot (child of a child Sequence) self.shot3 = Shot( name='SH003', code='SH003', parent=self.sequence2 ) # commit everything db.DBSession.add_all([ self.repo1, self.status_new, self.status_wip, self.status_comp, self.project_status_list, self.project, self.task_status_list, self.asset_status_list, self.shot_status_list, self.sequence_status_list, self.task1, self.task2, self.task3, self.task4, self.task5, self.task6, self.asset1, self.asset2, self.shot1, self.shot2, self.shot3, self.sequence1, self.sequence2, self.task_template, self.asset_template, self.shot_template, self.sequence_template ]) db.DBSession.commit() # now create versions def create_version(task, take_name): """Creates a new version :param task: the task :param take_name: the take_name name :return: the version """ # just renew the scene #pymel.core.newFile(force=True) v = Version(task=task, take_name=take_name) v.update_paths() db.DBSession.add(v) db.DBSession.commit() #self.maya_env.save_as(v) return v # asset2 self.version1 = create_version(self.asset2, 'Main') self.version2 = create_version(self.asset2, 'Main') self.version3 = create_version(self.asset2, 'Main') self.version3.description = 'Test Description' self.version4 = create_version(self.asset2, 'Take1') self.version5 = create_version(self.asset2, 'Take1') self.version6 = create_version(self.asset2, 'Take1') # task5 self.version7 = create_version(self.task5, 'Main') self.version8 = create_version(self.task5, 'Main') self.version9 = create_version(self.task5, 'Main') self.version10 = create_version(self.task5, 'Take1') self.version11 = create_version(self.task5, 'Take1') self.version12 = create_version(self.task5, 'Take1') # task6 self.version13 = create_version(self.task6, 'Main') self.version14 = create_version(self.task6, 'Main') self.version15 = create_version(self.task6, 'Main') self.version16 = create_version(self.task6, 'Take1') self.version17 = create_version(self.task6, 'Take1') self.version18 = create_version(self.task6, 'Take1') # shot3 self.version19 = create_version(self.shot3, 'Main') self.version20 = create_version(self.shot3, 'Main') self.version21 = create_version(self.shot3, 'Main') self.version22 = create_version(self.shot3, 'Take1') self.version23 = create_version(self.shot3, 'Take1') self.version24 = create_version(self.shot3, 'Take1') # task3 self.version25 = create_version(self.task3, 'Main') self.version26 = create_version(self.task3, 'Main') self.version27 = create_version(self.task3, 'Main') self.version28 = create_version(self.task3, 'Take1') self.version29 = create_version(self.task3, 'Take1') self.version30 = create_version(self.task3, 'Take1') # asset1 self.version31 = create_version(self.asset1, 'Main') self.version32 = create_version(self.asset1, 'Main') self.version33 = create_version(self.asset1, 'Main') self.version34 = create_version(self.asset1, 'Take1') self.version35 = create_version(self.asset1, 'Take1') self.version36 = create_version(self.asset1, 'Take1') # shot2 self.version37 = create_version(self.shot2, 'Main') self.version38 = create_version(self.shot2, 'Main') self.version39 = create_version(self.shot2, 'Main') self.version40 = create_version(self.shot2, 'Take1') self.version41 = create_version(self.shot2, 'Take1') self.version42 = create_version(self.shot2, 'Take1') # shot1 self.version43 = create_version(self.shot1, 'Main') self.version44 = create_version(self.shot1, 'Main') self.version45 = create_version(self.shot1, 'Main') self.version46 = create_version(self.shot1, 'Take1') self.version47 = create_version(self.shot1, 'Take1') self.version48 = create_version(self.shot1, 'Take1') # +- task1 # | | # | +- task4 # | | | # | | +- asset2 # | | +- Main # | | | +- version1 # | | | +- version2 (P) # | | | +- version3 (P) # | | +- Take1 # | | +- version4 (P) # | | +- version5 # | | +- version6 (P) # | | # | +- task5 # | | +- Main # | | | +- version7 # | | | +- version8 # | | | +- version9 # | | +- Take1 # | | +- version10 # | | +- version11 # | | +- version12 (P) # | | # | +- task6 # | +- Main # | | +- version13 # | | +- version14 # | | +- version15 # | +- Take1 # | +- version16 (P) # | +- version17 # | +- version18 (P) # | # +- task2 # | | # | +- sequence2 # | | # | +- shot3 # | +- Main # | | +- version19 # | | +- version20 # | | +- version21 # | +- Take1 # | +- version22 # | +- version23 # | +- version24 # | # +- task3 # | +- Main # | | +- version25 # | | +- version26 # | | +- version27 # | +- Take1 # | +- version28 # | +- version29 # | +- version30 # | # +- asset1 # | +- Main # | | +- version31 # | | +- version32 # | | +- version33 # | +- Take1 # | +- version34 # | +- version35 # | +- version36 # | # +- sequence1 # | | # | +- shot2 # | +- Main # | | +- version37 # | | +- version38 # | | +- version39 # | +- Take1 # | +- version40 # | +- version41 # | +- version42 # | # +- shot1 # +- Main # | +- version43 # | +- version44 # | +- version45 # +- Take1 # +- version46 # +- version47 # +- version48 # Start Condition: # # version15 # version12 # version5 # version2 -> has new published version (version3) # version5 -> Referenced a second time # version2 -> has new published version (version3) # version12 -> Referenced a second time # version5 # version2 -> has new published version (version3) # version5 # version2 -> has new published version (version3) # version45 -> no change # version48 -> no change # # Expected Final Result # version15A -> Derived from version15 # version12A -> Derived from version12 # version5A -> Derived from version5 # version3 -> has new published version (version3) # version5A -> Derived from version5 # version3 -> has new published version (version3) # version12A -> Derived from version12 - The second reference # version5A -> Derived from version5 # version3 -> has new published version (version3) # version5A -> Derived from version5 # version3 -> has new published version (version3) # version45 -> no change # version48 -> no change # create a deep relation self.version2.is_published = True self.version3.is_published = True # new scene # version5 references version2 self.version5.inputs.append(self.version2) self.version5.is_published = True # version12 references version5 self.version12.inputs.append(self.version5) self.version12.is_published = True # version45 references version48 self.version45.is_published = True self.version48.is_published = True self.version45.inputs.append(self.version48) # version15 references version12 and version48 self.version15.inputs.append(self.version12) self.version15.inputs.append(self.version45) # reference_resolution self.reference_resolution = { 'root': [self.version12, self.version45], 'leave': [self.version48, self.version45], 'update': [self.version2], 'create': [self.version5, self.version12] } # create a buffer for extra created files, which are to be removed self.remove_these_files_buffer = [] self.test_environment = TestEnvironment(name='Test Environment') self.test_environment._version = self.version15 if not QtGui.QApplication.instance(): logger.debug('creating a new QApplication') self.app = QtGui.QApplication(sys.argv) else: logger.debug('using the present QApplication: %s' % QtGui.qApp) # self.app = QtGui.qApp self.app = QtGui.QApplication.instance() self.dialog = version_updater.MainDialog( environment=self.test_environment, reference_resolution=self.reference_resolution )