def generateGeometry(self, path='',element=None):
    	'''
    		Function for generating geometry for Maya files.
    		Creates the following output formats:
    			.obj
    		@return: True if all files were created successfully
    				False if some files were not created
    		@post: Missing filenames are printed out to both the Maya terminal as well
    				as presented in a Maya confirm dialog.
    	'''

    	path = os.path.dirname(mc.file(q=True, sceneName=True))
    	if not os.path.exists (os.path.join(path, 'cache')):
    		os.makedirs(os.path.join(path, 'cache'))

    	ABCPATH = os.path.join(path, 'cache', 'abcFiles')

    	if os.path.exists(ABCPATH):
    		shutil.rmtree(ABCPATH)

    	filePath = mc.file(q=True, sceneName=True)
    	fileDir = os.path.dirname(filePath)

    	abcFilePath = self.getElementCacheDirectory(fileDir, element)
    	if abcFilePath is None:
    		return False

    	selection = mc.ls(geometry=True, visible=True)
    	selection_long = mc.ls(geometry=True, visible=True, long=True)

    	project = Project()
    	if element is None:
    		checkout = project.get_checkout(path)
    		if checkout is None:
    			qd.error('There was a problem exporting the alembic to the correct location. Checkout the asset again and try one more time.')
    			return None
    		body = project.get_body(checkout.get_body_name())
    		element = body.get_element(checkout.get_department_name(), checkout.get_element_name())
    	else:
    		body = project.get_body(element.get_parent())

    	# We decided to try exporting all the geo into one alembic file instead of many. This is the line that does many
    	# abcs = abcExport(selection_long, ABCPATH)
    	# if body.is_asset():
    	# 	if body.get_type() == AssetType.SET:
    	# 		abcs = self.abcExportLoadedReferences(ABCPATH)
    	# 	else:
    	# 		abcs = self.abcExportAll(element.get_long_name(), ABCPATH)
    	# else:

    	abcs = self.abcExportAll(element.get_long_name(), ABCPATH)

    	if not len(self.checkFiles(abcs)) == 0:
    		return False

    	return True
Beispiel #2
0
    def rollback_element(self, node, department, name):
        self.node = node
        self.department = department

        project = Project()
        body = project.get_body(name)
        element = body.get_element(department)

        self.publishes = element.list_publishes()
        print("publishes: ", self.publishes)

        if not self.publishes:
            qd.error("There have been no publishes for this department. Rollback failed.")
            return

        # make the list a list of strings, not tuples
        self.sanitized_publish_list = []
        for publish in self.publishes:
            path = publish[3]
            file_ext = path.split('.')[-1]
            if not file_ext == "hda" and not file_ext =="hdanc":
                continue

            label = publish[0] + " " + publish[1] + " " + publish[2]
            self.sanitized_publish_list.append(label)

        self.item_gui = sfl.SelectFromList(l=self.sanitized_publish_list, parent=houdini_main_window(), title="Select publish to clone")
        self.item_gui.submitted.connect(self.publish_selection_results)
Beispiel #3
0
    def shot_comment(self, value):
        comment = value
        if comment is None:
            comment = "publish by " + str(
                user.get_username()) + " in department " + str(department)

        chosen_asset = self.chosen_asset

        project = Project()
        self.body = project.get_body(chosen_asset)

        department = Department.LIGHTING
        element = self.body.get_element(department)  #, Element.DEFAULT_NAME)

        hou.hipFile.save()
        src = hou.hipFile.name()

        #Publish
        user = Environment().get_user()
        pipeline_io.set_permissions(src)
        dst = self.publish_element(element, user, src, comment)
        pipeline_io.set_permissions(dst)

        message = "Successfully published " + str(self.body.get_name()) + "!"
        self.print_success_message(message)
Beispiel #4
0
    def results(self, value):
        print("Final value: ", value[0])
        filename = value[0]

        project = Project()
        body = project.get_body(filename)

        element = body.get_element("model")

        filepath = body.get_filepath()

        self.publishes = element.list_publishes()
        print("publishes: ", self.publishes)
        print("path: ", filepath)

        # make the list a list of strings, not tuples
        self.sanitized_publish_list = []
        for publish in self.publishes:
            path = publish[3]
            file_ext = path.split('.')[-1]
            if not file_ext == "mb":
                continue
            label = publish[0] + " " + publish[1] + " " + publish[2]
            self.sanitized_publish_list.append(label)

        self.item_gui = sfl.SelectFromList(
            l=self.sanitized_publish_list,
            parent=maya_utils.maya_main_window(),
            title="Select publish to clone")
        self.item_gui.submitted.connect(self.publish_selection_results)
Beispiel #5
0
    def confirmWritePropReference(self, body=None):
        filepath = pm.sceneName()
        fileDir = os.path.dirname(filepath)
        project = Project()

        if not body:
            checkout = project.get_checkout(fileDir)
            bodyName = checkout.get_body_name()
            body = project.get_body(bodyName)

        if body.is_asset() and body.get_type() == AssetType.PROP:
            element = body.get_element(Department.MODEL)
            filepath = os.path.join(project.get_assets_dir(),
                                    element.get_cache_dir())
            assemblies = pm.ls(assemblies=True)
            pm.select(pm.listCameras(), replace=True)
            cameras = pm.selected()
            pm.select([])
            non_cameras = [
                assembly for assembly in assemblies if assembly not in cameras
            ]
            self.exportPropJSON(filepath,
                                non_cameras[0],
                                isReference=False,
                                name=body.get_name())
            print("JSON references written successfully.")
Beispiel #6
0
    def shot_results(self, value):
        shot_name = value[0]
        project = Project()

        body = project.get_body(shot_name)
        element = body.get_element("lighting")

        self.publishes = element.list_publishes()
        print("publishes: ", self.publishes)

        if not self.publishes:
            # has not been imported. Import it first.
            importer = Importer()
            importer.import_shot([shot_name])
            return

        # make the list a list of strings, not tuples
        self.sanitized_publish_list = []
        for publish in self.publishes:
            path = publish[3]
            file_ext = path.split('.')[-1]
            if not file_ext == "hip" and not file_ext == "hipnc":
                continue
            label = publish[0] + " " + publish[1] + " " + publish[2]
            self.sanitized_publish_list.append(label)

        self.item_gui = sfl.SelectFromList(l=self.sanitized_publish_list,
                                           parent=houdini_main_window(),
                                           title="Select publish to clone")
        self.item_gui.submitted.connect(self.publish_selection_results)
    def asset_results(self, value):
        chosen_asset = value[0]

        project = Project()
        self.frame_range = qd.input("Enter frame range (as numeric input) or leave blank if none:")

        if self.frame_range is None or self.frame_range == u'':
            self.frame_range = 1

        self.frame_range = str(self.frame_range)
        if not self.frame_range.isdigit():
            qd.error("Invalid frame range input. Setting to 1.")

        self.body = project.get_body(chosen_asset)
        self.body.set_frame_range(self.frame_range)

        department_list = []
        asset_type = self.body.get_type()
        if str(asset_type) == 'prop':
            department_list = self.body.prop_export_departments()
            self.department_results(department_list)
        elif str(asset_type) == 'character':
            department_list = self.body.char_export_departments()
        elif str(asset_type) == 'set':
            department_list = self.body.set_export_departments()
        elif str(asset_type) == 'shot':
            department_list = self.body.shot_export_departments()

        self.item_gui = sfl.SelectFromList(l=department_list, multiple_selection=True, parent=maya_main_window(), title="Select department(s) for this export: ")
        self.item_gui.submitted.connect(self.department_results)
    def export(self, element, selection=None, startFrame=None, endFrame=None):
        project = Project()
        bodyName = element.get_parent()
        body = project.get_body(bodyName)
        abcFilePath = element.get_cache_dir()

        self.element = element

        if startFrame is None:
            startFrame = pm.playbackOptions(q=True, animationStartTime=True)
        if endFrame is None:
            endFrame = pm.playbackOptions(q=True, animationEndTime=True)

        if body.is_shot():
            startFrame -= 1
            endFrame = int(endFrame)
            endFrame += 1
            endFrame = str(endFrame)
            files = self.exportReferences(abcFilePath,
                                          tag='DCC_Alembic_Export_Flag',
                                          startFrame=startFrame,
                                          endFrame=endFrame)
            if self.cameras:
                files.extend(self.export_cameras(body, startFrame, endFrame))

        elif body.is_asset():
            if body.get_type() == AssetType.SET:
                files = self.exportReferences(abcFilePath)
            else:
                files = self.exportAll(abcFilePath,
                                       tag='DCC_Alembic_Export_Flag',
                                       element=element)

        elif body.is_crowd_cycle():
            files = self.exportAll(abcFilePath,
                                   tag='DCC_Alembic_Export_Flag',
                                   startFrame=startFrame,
                                   endFrame=endFrame,
                                   element=element)

        if not files:
            #Maybe this is a bad distinction but None is if it was canceled or something and empty is if it went but there weren't any alembics
            if files is None:
                return
            qd.error(
                'No alembics were exported. Make sure the top-level group is tagged.'
            )
            return

        for abcFile in files:
            os.system('chmod 774 ' + abcFile)

        exported_asset_names = ""
        for file in files:
            asset_file_name = str(file).rpartition('/')[2]
            exported_asset_names += asset_file_name + '\n'
        qd.info("Alembics exported successfully: " + '\n' +
                exported_asset_names)

        return files
Beispiel #9
0
    def asset_results(self, value):
        chosen_asset = value[0]

        project = Project()
        self.body = project.get_body(chosen_asset)
        self.comment = qd.HoudiniInput(parent=houdini_main_window(),
                                       title="Any comments?")
        self.comment.submitted.connect(self.publish_hda)
Beispiel #10
0
    def auto_export(self, asset_name):
        project = Project()
        body = project.get_body(asset_name)

        element = body.get_element(Department.TEXTURE)
        cache_dir = element.get_cache_dir()
        fbx_filepath = os.path.join(cache_dir, element.get_long_name() + '.fbx')

        print("Fbx filepath: ", fbx_filepath)
        pm.mel.FBXExport(f=fbx_filepath)
Beispiel #11
0
    def asset_results(self, asset):
        self.selected_asset = asset[0]

        project = Project()
        self.body = project.get_body(self.selected_asset)

        parent, instances = self.create_hda(self.selected_asset)

        layout_object_level_nodes()

        print("created ", instances, " in ", parent)
    def getElementCacheDirectory(self, path, element=None):

    	if element is None:
    		project = Project()
    		checkout = project.get_checkout(path)
    		if checkout is None:
    			qd.error('There was a problem exporting the alembic to the correct location. Checkout the asset again and try one more time.')
    			return None
    		body = project.get_body(checkout.get_body_name())
    		element = body.get_element(checkout.get_department_name(), checkout.get_element_name())

    	return element.get_cache_dir()
Beispiel #13
0
    def asset_results(self, value):
        print("Selected asset: ", value[0])
        filename = value[0]

        project = Project()
        self.body = project.get_body(filename)

        department_paths = self.get_department_paths(self.body)

        from pipe.tools.houtools.assembler.assembler import Assembler  # we put import here to avoid cross import issue #63 FIXME
        node, created_instances = Assembler().create_hda(
            filename, body=self.body, department_paths=department_paths)
        layout_object_level_nodes()

        return node, created_instances
Beispiel #14
0
    def asset_results(self, value):
        chosen_asset = value[0]

        project = Project()
        self.body = project.get_body(chosen_asset)

        start_frame = mc.playbackOptions(q=True, min=True)
        end_frame = mc.playbackOptions(q=True, max=True)

        playblast_element = self.body.get_element(Department().RENDER)
        playblast_dir = playblast_element.get_render_dir()
        playblast_filename = chosen_asset + "_playblast.mov"
        path = os.path.join(playblast_dir, playblast_filename)

        self.simpleBlast(start_frame, end_frame, path)
        qd.info("Playblast created at " + str(path))
Beispiel #15
0
    def results(self, value):
        print("Final value: ", value[0])
        filename = value[0]

        project = Project()
        body = project.get_body(filename)
        self.body = body
        type = body.get_type()
        element = self.get_element_option(type, body)

        if self.quick:
            latest = element.get_last_publish()
            if not latest:
                qd.error("There have been no publishes in this department.")
                return
            else:
                selected_scene_file = latest[3]
                self.open_scene_file(selected_scene_file)
                return

        if element is None:
            qd.warning("Nothing was cloned.")
            return

        self.publishes = element.list_publishes()
        print("publishes: ", self.publishes)

        if not self.publishes:
            qd.error(
                "There have been no publishes in this department. Maybe you meant model?"
            )
            return

        # make the list a list of strings, not tuples
        self.sanitized_publish_list = []
        for publish in self.publishes:
            path = publish[3]
            file_ext = path.split('.')[-1]
            if not file_ext == "mb":
                continue
            label = publish[0] + " " + publish[1] + " " + publish[2]
            self.sanitized_publish_list.append(label)

        self.item_gui = sfl.SelectFromList(l=self.sanitized_publish_list,
                                           parent=maya_main_window(),
                                           title="Select publish to clone")
        self.item_gui.submitted.connect(self.publish_selection_results)
Beispiel #16
0
    def asset_results(self, value):
        chosen_asset = value[0]

        project = Project()
        self.body = project.get_body(chosen_asset)

        asset_type = self.body.get_type()
        if asset_type == AssetType.ACTOR or asset_type == AssetType.PROP:
            self.export = True

        department_list = get_departments_by_type(asset_type)

        self.item_gui = sfl.SelectFromList(
            l=department_list,
            parent=maya_main_window(),
            title="Select department for this publish")
        self.item_gui.submitted.connect(self.department_results)
Beispiel #17
0
    def confirmWriteShotReferences(self, body=None):
        filePath = pm.sceneName()
        filDir = os.path.dirname(filePath)
        proj = Project()
        if not body:
            checkout = proj.get_checkout(fileDir)
            bodyName = checkout.get_body_name()
            body = proj.get_body(bodyName)

        if body.is_shot():
            print("SHOT OK")
            element = body.get_element(Department.ANIM)
            refsFilePath = os.path.join(Project().get_assets_dir(), element.get_cache_dir())
            self.export_shot(refsFilePath)
        else:
            print("NOT A SHOT")
            qd.error('No set found in current scene.')
    def export(self, element, selection=None, startFrame=None, endFrame=None):
        project = Project()
        bodyName = element.get_parent()
        body = project.get_body(bodyName)
        abcFilePath = element.get_cache_dir()

        self.element = element

        #TODO we don't want to put them into the element cache right away. We want to put them in a seperate place and then copy them over later.

        if startFrame is None:
            startFrame = pm.playbackOptions(q=True, animationStartTime=True)
        if endFrame is None:
            endFrame = pm.playbackOptions(q=True, animationEndTime=True)

        if body.is_shot():
            startFrame -= 5
            endFrame = int(endFrame)
            endFrame += 5
            endFrame = str(endFrame)
            files = self.exportReferences(abcFilePath, tag='DCC_Alembic_Export_Flag', startFrame=startFrame, endFrame=endFrame)
            # result = qd.yes_or_no('Are there any crowds that need to be exported?')
            # if result:
            #     self.exportCrowd(abcFilePath, 'DCC_Crowd_Agent_Flag', tag='DCC_Alembic_Export_Flag', startFrame=startFrame, endFrame=endFrame)
        elif body.is_asset():
            if body.get_type() == AssetType.SET:
                files = self.exportReferences(abcFilePath)
            else:
                files = self.exportAll(abcFilePath, tag='DCC_Alembic_Export_Flag', element=element)
        elif body.is_crowd_cycle():
            files = self.exportAll(abcFilePath, tag='DCC_Alembic_Export_Flag', startFrame=startFrame, endFrame=endFrame, element=element)

        if not files:
            #Maybe this is a bad distinction but None is if it was canceled or something and empty is if it went but there weren't any alembics
            if files is None:
                return
            qd.error('No alembics were exported. Make sure the top-level group is tagged.')
            return

        for abcFile in files:
            os.system('chmod 774 ' + abcFile)

        #TODO install the geometry
        print 'These are the files that we are returning', files
        return files
Beispiel #19
0
def non_gui_publish_hda(hda=None, comment='N/A'):
    if hda is None:
        print('Error with asset')

    project = Project()
    environment = Environment()
    user = environment.get_current_username()
    hdaName = hda.type().name()

    department = None

    if str(hda) not in Department.ALL:
        print 'v1 asset'
        department = Department.ASSEMBLY
    else:
        department = str(hda)

    asset_name = hdaName.replace("_" + department, "") if department not in [
        Department.ASSEMBLY, Department.HDA
    ] else hdaName.replace("_main", "")
    body = project.get_body(asset_name)

    if body is None:
        qd.error('No asset in pipe')
        return

    #TODO: publish tools
    if body.is_tool():
        print(asset_name + ' is tool')
        return
        department = Department.HDA

    hda_src = hda.type().definition().libraryFilePath()
    print hda_src
    element = body.get_element(department,
                               Element.DEFAULT_NAME,
                               force_create=True)

    try:
        hda.type().definition().updateFromNode(hda)
    except hou.OperationFailed, e:
        qd.error('There was a problem publishing the HDA to the pipeline.\n',
                 details=str(e))
        return
    def get_body_and_export(self, chosen_asset, export_all=False):
        project = Project()
        self.body = project.get_body(chosen_asset)
        try:
            print("asset type: " + self.body.get_type())
        except:
            qd.error(
                "Error: Asset does not have a valid type. Was it created properly?"
            )

        type = self.body.get_type()

        if type == AssetType.PROP or type == AssetType.ACTOR:
            creases = qd.yes_or_no("Does this asset use creases?")

            if creases:
                self.crease = True

        if type == AssetType.SHOT:
            export_all = False
            self.frame_range = qd.input("How many frames are in this shot?")

            if self.frame_range is None or self.frame_range == u'':
                self.frame_range = 1

            self.frame_range = str(self.frame_range)
            if not self.frame_range.isdigit():
                qd.error("Invalid frame range input. Setting to 1.")
        else:
            self.frame_range = 1

        self.body.set_frame_range(self.frame_range)

        asset_type = self.body.get_type()
        department_list = get_departments_by_type(asset_type, export=True)

        if export_all:
            # tag top level nodes
            nodes = get_top_level_nodes()
            print("top level: ", nodes)
            for node in nodes:
                tag_node_with_flag(node, "DCC_Alembic_Export_Flag")

        self.department_results(department_list)
Beispiel #21
0
    def confirmWriteSetReferences(self, body=None):
        filePath = pm.sceneName()
        fileDir = os.path.dirname(filePath)
        proj = Project()
        if not body:
            checkout = proj.get_checkout(fileDir)
            bodyName = checkout.get_body_name()
            body = proj.get_body(bodyName)

        if body.is_asset():
            if body.get_type() == AssetType.SET:
                print("SET OK")
                element = body.get_element(Department.MODEL)
                refsFilePath = os.path.join(Project().get_assets_dir(), element.get_cache_dir())
                self.exportReferences(refsFilePath)
                qd.info("JSON references written successfully.")
            else:
                print("NOT A SET")
                qd.error('No set found in current scene.')
Beispiel #22
0
    def shot_results(self, value):
        chosen_asset = value[0]

        project = Project()
        self.body = project.get_body(chosen_asset)

        department = Department.LIGHTING
        element = self.body.get_element(department)  #, Element.DEFAULT_NAME)

        hou.hipFile.save()
        src = hou.hipFile.name()

        #Publish
        user = Environment().get_user()
        comment = "publish by " + str(
            user.get_username()) + " in department " + str(department)
        dst = self.publish_element(element, user, src, comment)

        message = "Successfully published " + str(self.body.get_name()) + "!"
        self.print_success_message(message)
Beispiel #23
0
def writeXML(assetName='None', context='OBJ'):
    project = Project()
    asset_body = project.get_body(assetName)
    icon = os.path.join('$JOB', 'pipe', 'tools', '_resources', '2.png')

    if not asset_body.is_asset():
        print('error me this')
        raise Exception('Failed to generate XML for: ' + assetName +
                        ' \n Object is not an Asset')

    global baseXML
    xml = Template(baseXML).substitute(NAME=assetName,
                                       LABEL=assetName.replace('_',
                                                               ' ').title(),
                                       ICON=icon,
                                       CONTEXT=context)

    try:
        path = os.path.join(project.get_assets_dir(), assetName)
        path = os.path.join(path, assetName + '.shelf')

        file = open(path, 'w')
        file.write(xml)
        file.close()

        if not os.path.exists(project.get_tabs_dir()):
            os.makedirs(project.get_tabs_dir())

        sym = os.path.join(project.get_tabs_dir(), assetName + '.shelf')

        if os.path.exists(sym):
            os.unlink(sym)
        os.link(path, sym)

    except Exception as e:
        print e
        raise Exception('Failed to generate XML for: ' + assetName)
Beispiel #24
0
    def set_results(self, value):
        set_name = value[0]
        project = Project()
        self.body = project.get_body(set_name)

        obj = hou.node("/obj")
        set = obj.node(set_name)

        if set is None:
            qd.error(
                "No set found with that name. Please check naming and try again."
            )
            return

        print("set: ", set)
        inside = set.node("inside")
        children = inside.children()
        set_file = os.path.join(Project().get_assets_dir(), set_name, "model",
                                "main", "cache", "whole_set.json")

        set_data = []
        try:
            with open(set_file) as f:
                set_data = json.load(f)
        except Exception as error:
            qd.error("No valid JSON file for " + str(set_name))
            return

        items_in_set = []
        for item in set_data:
            item_name = item['asset_name']
            item_version = item['version_number']
            items_in_set.append(item_name)

        # TODO: for each child, make sure that it exists in whole_set.json, or add it if it doesn't, or remove it if it does not
        child_names = []
        for child in children:
            child_path = child.path()
            name = child_path.split('/')[-1].lower()
            child_names.append(name)

        for item in set_data:
            if str(item['asset_name']) not in child_names:
                set_data.remove(item)

        for child in children:
            print("child: ", child)
            inside = child.node("inside")
            out = inside.node("OUT")
            set_transform = inside.node("set_dressing_transform")
            child_path = child.path()
            name = child_path.split('/')[-1].lower()

            child_body = project.get_body(name)
            if child_body is None:
                qd.warning(
                    str(name) +
                    " not found in pipe. Please check that node is named correctly."
                )
                continue

            # get transform parms: t is translate, r rotate and s scale (with associated x,y,z vals)
            tx, ty, tz = self.get_transform(set_transform, "tx", "ty", "tz")
            rx, ry, rz = self.get_transform(set_transform, "rx", "ry", "rz")
            sx, sy, sz = self.get_transform(set_transform, "sx", "sy", "sz")

            latest_file, latest_version = self.body.get_latest_json_version(
                name)
            if latest_version == int(9):
                new_version = 0
            else:
                new_version = int(latest_version) + 1

            prop_file = os.path.join(
                Project().get_assets_dir(), set_name, "model", "main", "cache",
                str(name) + "_" + str(latest_version) + ".json")

            if name in items_in_set:
                print("set contains asset: " + str(name))
                try:
                    with open(prop_file) as f:
                        prop_data = json.load(f)
                except Exception as error:
                    qd.warning("No valid JSON file for " + str(name) +
                               ". Skipping changes made to this asset.")
                    continue

                for set_item in set_data:
                    if str(set_item['asset_name']) == str(name):
                        set_item['version_number'] = new_version
                        break

            else:
                print(str(name) + " not found in set file.")
                path = self.get_prim_path(out)
                prop_data = {
                    "asset_name": name,
                    "version_number": 0,
                    "path": str(path),
                    "a": [0, 0, 0],
                    "b": [0, 0, 0],
                    "c": [0, 0, 0]
                }
                set_data.append({"asset_name": str(name), "version_number": 0})
                new_version = 0

            new_prop_file = os.path.join(
                Project().get_assets_dir(), set_name, "model", "main", "cache",
                str(name) + "_" + str(new_version) + ".json")

            # get a b and c from prop_data file. Each is an array of size 3, representing x,y,z coords
            a = prop_data['a']
            b = prop_data['b']
            c = prop_data['c']

            self.update_points_by_geo(out, a, b, c)

            # put the updated coords back into prop_data
            prop_data['a'] = a
            prop_data['b'] = b
            prop_data['c'] = c

            # TODO: add a commit and a publish for this set

            print("prop data (updated): ", prop_data)

            updated_prop_data = json.dumps(prop_data)
            outfile = open(new_prop_file, "w")
            outfile.write(updated_prop_data)
            outfile.close()

            print("prop file updated for " + str(name))

            self.clear_transform(set_transform)
            self.update_version_number(child, new_version)
            import_node = child.node("import")
            read_from_json = import_node.node("read_from_json")
            read_from_json.parm("reload").pressButton()

        outfile = open(set_file, "w")
        print("set data: ", set_data)
        updated_set_data = json.dumps(set_data)
        outfile.write(updated_set_data)
        outfile.close()

        qd.info("Set " + str(set_name) + " published successfully!")
Beispiel #25
0
    def set_results(self, value):
        set_name = value[0]
        project = Project()
        self.body = project.get_body(set_name)

        obj = hou.node("/obj")
        set = obj.node(set_name)

        if set is None:
            qd.error(
                "No set found with that name. Please check naming and try again."
            )
            return

        #migrate transforms for all the children to set_dressing_transform
        self.update_set_dressing_transform(set)

        #create children list (list of houdini objects)
        print("set: ", set)
        inside = set.node("inside")
        children = inside.children()

        set_file = os.path.join(Project().get_assets_dir(), set_name, "model",
                                "main", "cache", "whole_set.json")
        '''
        The idea here is to get the set data from whole_set.json,
        get the set data from Houdini, and then compare the two.
        Here are the possible scenarios:
            1. There are items in the JSON file that aren't in the Houdini Set
                -remove the item from the Json file
                -remove the item's json files
            2. There are items in the Houdini Set that aren't in the JSON file
                -Add those to the JSON file
        '''

        items_to_delete = []
        set_data = []
        items_in_set = []

        items_to_delete, set_data, items_in_set = self.get_set_comparable_lists(
            children, set_file)

        self.delete_asset_json(items_to_delete, set_name)

        # TODO: To allow adding multiple copies of the same prop to a set in houdini, we'll want to add as many copies to the whole_set.json file
        # for child_name in child_names:
        #     child = inside.node(child_name)  # get the child node
        #     inside = child.node("inside")
        #     modify = inside.node("modify")
        #     modify_name = modify.type().name()
        #     name = modify_name.split("_")[0].lower()
        #
        #     if name not in items_in_set:
        #         set_data.append

        print("starting to work on children\n")
        for child in children:

            #find if it is scaled (set to big scale) and initialize variables----------------------------------------------------------
            #inside
            #import_node
            #out
            #set_transform
            #current_version
            #name

            isScaled = False
            print("child: " + str(child))
            print("current set_data: " + str(set_data))
            if child.type().name() == "dcc_geo":
                inside = child.node("inside")
                import_node = child.node("import")
                if child.parm("Scale_Object").evalAsInt() == 1:
                    child.parm("Scale_Object").set(0)
                    isScaled = True
            else:
                inside = child.node("inside")
                geo = inside.node("geo")
                inside = geo.node("inside")
                import_node = geo.node("import")

            out = inside.node("OUT")
            set_transform = inside.node("set_dressing_transform")
            current_version = child.parm("version_number").evalAsInt()
            #need a asset number or letter (I honestly just need to name it something and have that reflected in houdini)
            #import_number = child.parm("import_number").evalAsInt

            name = child.parm("asset_name").evalAsString()

            #---------------------------------------------------------------------------------------------------------------------------

            child_body = project.get_body(name)
            if child_body is None:
                qd.warning(
                    str(name) +
                    " not found in pipe. Please check that node is named correctly."
                )
                continue

            cache_dir = os.path.join(Project().get_assets_dir(), set_name,
                                     "model", "main", "cache")
            print("filepath: ", cache_dir)
            latest_version, version_string = self.body.version_prop_json(
                name, cache_dir)
            print('latest version: ', latest_version)
            new_version = latest_version
            latest_version -= 1

            prop_file = os.path.join(
                cache_dir,
                str(name) + "_" + str(current_version) + ".json")
            print("prop file: ", prop_file)

            #will have to change items_in_set to be checked
            if name in items_in_set:
                print("set contains asset: " + str(name))
                try:
                    with open(prop_file) as f:
                        prop_data = json.load(f)
                except Exception as error:
                    print("No valid JSON file for " + str(name) +
                          ". Skipping changes made to this asset.")
                    continue

                for set_item in set_data:
                    if str(set_item['asset_name']) == str(name):
                        if set_item['version_number'] <= current_version:
                            print("updating ", set_item, " with version ",
                                  new_version)
                            set_item['version_number'] = new_version
                            break

            else:
                # create blank prop data and add it to the set
                print(str(name) + " not found in set file.")
                path = self.get_prim_path(out)
                prop_data = {
                    "asset_name": name,
                    "version_number": 0,
                    "path": str(path),
                    "a": [0, 0, 0],
                    "b": [0, 0, 0],
                    "c": [0, 0, 0]
                }
                set_data.append({"asset_name": str(name), "version_number": 0})
                print("appended set_data: " + str(set_data))
                new_version = 0
                items_in_set.append(name)

            print("current set_data: " + str(set_data))

            new_prop_file = os.path.join(
                Project().get_assets_dir(), set_name, "model", "main", "cache",
                str(name) + "_" + str(new_version) + ".json")

            # get a b and c from prop_data file. Each is an array of size 3, representing x,y,z coords
            a = prop_data['a']
            b = prop_data['b']
            c = prop_data['c']

            self.update_points_by_geo(out, prop_data['path'], a, b, c)

            # put the updated coords back into prop_data
            prop_data['a'] = a
            prop_data['b'] = b
            prop_data['c'] = c
            prop_data['version_number'] = new_version

            # TODO: add a commit and a publish for this set

            print("prop data (updated): ", prop_data)

            updated_prop_data = json.dumps(prop_data)
            outfile = open(new_prop_file, "w")
            outfile.write(updated_prop_data)
            outfile.close()

            print("prop file updated for " + str(name))
            print("")

            self.clear_transform(set_transform)
            self.set_space(child, set_name, name, new_version)

            if isScaled:
                child.parm("Scale_Object").set(1)

        #reloading the new data that was written
        try:
            read_from_json = import_node.node("read_from_json")
            read_from_json.parm("reload").pressButton()
        except:
            print("no nodes are in the set, cannot read from JSON")

        #rewriting the whole_set json file
        outfile = open(set_file, "w")
        print("set data: ", set_data)
        updated_set_data = json.dumps(set_data)
        outfile.write(updated_set_data)
        outfile.close()

        qd.info("Set " + str(set_name) + " published successfully!")
Beispiel #26
0
    def set_results(self, value):
        set_name = value[0]
        project = Project()
        self.body = project.get_body(set_name)

        obj = hou.node("/obj")
        set = obj.node(set_name)

        if set is None:
            qd.error(
                "No set found with that name. Please check naming and try again."
            )
            return

        print("set: ", set)
        inside = set.node("inside")
        children = inside.children()
        set_file = os.path.join(Project().get_assets_dir(), set_name, "model",
                                "main", "cache", "whole_set.json")

        set_data = []
        try:
            with open(set_file) as f:
                set_data = json.load(f)
        except Exception as error:
            qd.error("No valid JSON file for " + str(set_name))
            return

        items_in_set = []
        for item in set_data:
            item_name = item['asset_name']
            item_version = item['version_number']
            items_in_set.append(item_name)

        child_names = []
        for child in children:
            child_path = child.path()
            first_char_to_lower = lambda s: s[:1].lower() + s[1:] if s else ''
            name = child_path.split('/')[-1]
            name = first_char_to_lower(name)
            child_names.append(name)
        print("child names; ", child_names)

        for item in set_data:
            if str(item['asset_name']) not in child_names:
                set_data.remove(item)

        # TODO: To allow adding multiple copies of the same prop to a set in houdini, we'll want to add as many copies to the whole_set.json file
        # for child_name in child_names:
        #     child = inside.node(child_name)  # get the child node
        #     inside = child.node("inside")
        #     modify = inside.node("modify")
        #     modify_name = modify.type().name()
        #     name = modify_name.split("_")[0].lower()
        #
        #     if name not in items_in_set:
        #         set_data.append

        for child in children:
            if child.type().name() == "dcc_geo":
                inside = child.node("inside")
                import_node = child.node("import")
            else:
                inside = child.node("inside")
                geo = inside.node("geo")
                inside = geo.node("inside")
                import_node = geo.node("import")

            out = inside.node("OUT")
            set_transform = inside.node("set_dressing_transform")
            current_version = child.parm("version_number").evalAsInt()

            name = child.parm("asset_name").evalAsString()

            child_body = project.get_body(name)
            if child_body is None:
                qd.warning(
                    str(name) +
                    " not found in pipe. Please check that node is named correctly."
                )
                continue

            # get transform parms: t is translate, r rotate and s scale (with associated x,y,z vals)
            tx, ty, tz = self.get_transform(set_transform, "tx", "ty", "tz")
            rx, ry, rz = self.get_transform(set_transform, "rx", "ry", "rz")
            sx, sy, sz = self.get_transform(set_transform, "sx", "sy", "sz")

            cache_dir = os.path.join(Project().get_assets_dir(), set_name,
                                     "model", "main", "cache")
            print("filepath: ", cache_dir)
            latest_version, version_string = self.body.version_prop_json(
                name, cache_dir)
            print('latest version: ', latest_version)
            new_version = latest_version
            latest_version -= 1

            prop_file = os.path.join(
                cache_dir,
                str(name) + "_" + str(current_version) + ".json")
            print("prop file: ", prop_file)

            if name in items_in_set:
                print("set contains asset: " + str(name))
                try:
                    with open(prop_file) as f:
                        prop_data = json.load(f)
                except Exception as error:
                    qd.warning("No valid JSON file for " + str(name) +
                               ". Skipping changes made to this asset.")
                    continue

                for set_item in set_data:
                    if str(set_item['asset_name']) == str(name):
                        if set_item['version_number'] <= current_version:
                            print("updating ", set_item, " with version ",
                                  new_version)
                            set_item['version_number'] = new_version
                            break

            else:
                print(str(name) + " not found in set file.")
                path = self.get_prim_path(out)
                prop_data = {
                    "asset_name": name,
                    "version_number": 0,
                    "path": str(path),
                    "a": [0, 0, 0],
                    "b": [0, 0, 0],
                    "c": [0, 0, 0]
                }
                set_data.append({"asset_name": str(name), "version_number": 0})
                new_version = 0
                items_in_set.append(name)

            new_prop_file = os.path.join(
                Project().get_assets_dir(), set_name, "model", "main", "cache",
                str(name) + "_" + str(new_version) + ".json")

            # get a b and c from prop_data file. Each is an array of size 3, representing x,y,z coords
            a = prop_data['a']
            b = prop_data['b']
            c = prop_data['c']

            self.update_points_by_geo(out, a, b, c)

            # put the updated coords back into prop_data
            prop_data['a'] = a
            prop_data['b'] = b
            prop_data['c'] = c
            prop_data['version_number'] = new_version

            # TODO: add a commit and a publish for this set

            print("prop data (updated): ", prop_data)

            updated_prop_data = json.dumps(prop_data)
            outfile = open(new_prop_file, "w")
            outfile.write(updated_prop_data)
            outfile.close()

            print("prop file updated for " + str(name))

            self.clear_transform(set_transform)
            self.set_space(child, set_name, name, new_version)

            read_from_json = import_node.node("read_from_json")
            read_from_json.parm("reload").pressButton()

            outfile = open(set_file, "w")
            print("set data: ", set_data)
            updated_set_data = json.dumps(set_data)
            outfile.write(updated_set_data)
            outfile.close()

        qd.info("Set " + str(set_name) + " published successfully!")
Beispiel #27
0
import checkout
from pipe.am.project import Project
from pipe.am.environment import Environment, Department
from pipe.am.element import Element
from pipe.am.body import Body, Asset, Shot, AssetType

import maya.standalone
maya.standalone.initialize(name='python')
import maya.cmds as cmds



project=Project()
environment=Environment()


asset_dir=project.get_assets_dir()


for i,asset in enumerate(project.list_assets(AssetType.PROP)):

    asset_obj=project.get_body(asset)
    element_obj = asset_obj.get_element(Department.MODEL,force_create=True)
    element_path = element_obj.checkout(environment.get_current_username())
    cmds.file(rename='/tmp/lol'+str(i)+'.mb')
    cmds.file(save=True)


    checkout.non_gui_open(element_path,asset)
print 'Done'
Beispiel #28
0
    def non_gui_publish(self, asset_name, department):
        project = Project()
        self.body = project.get_body(asset_name)

        self.department_results([department])
Beispiel #29
0
class CheckoutWindow(QtWidgets.QWidget):

    finished = QtCore.Signal()

    def __init__(self, parent, dept_list=Department.ALL):
        super(CheckoutWindow, self).__init__()
        self.parent = parent
        self.project = Project()
        self.environment = Environment()
        self.initUI(dept_list)

    def initUI(self, dept_list):
        #define gui elements
        self.resize(WINDOW_WIDTH,WINDOW_HEIGHT)
        self.setWindowTitle('Checkout')
        self.dept_tabs = QtWidgets.QTabWidget()
        self.dept_list = dept_list
        self.result = None

        #create checkbox to show only published assets
        self.show_published = QtWidgets.QCheckBox("Display only assets or shots with previous publishes")
        self.show_published.setCheckState(QtCore.Qt.Unchecked)
        self.show_published.stateChanged.connect(self.changeBodyCheckoutVisibility)

        #create Tabs
        self.createTabs()

        #create buttons
        self.checkout_button = QtWidgets.QPushButton('Checkout')
        self.checkout_button.clicked.connect(self.checkout)
        self.cancel_button = QtWidgets.QPushButton('Cancel')
        self.cancel_button.clicked.connect(self.close)

        #create button layout
        button_layout = QtWidgets.QHBoxLayout()
        button_layout.addWidget(self.checkout_button)
        button_layout.addWidget(self.cancel_button)

        self.img = QtWidgets.QLabel()
        banner_path = os.path.join(os.environ['MEDIA_PROJECT_DIR'], 'pipe', 'am', 'gui', '_resources', 'film-banner.jpg')
        pixmap = QtGui.QPixmap(banner_path)
        scaled = pixmap.scaledToWidth(self.size().width())
        self.img.setPixmap(scaled)

        #create main layout
        main_layout = QtWidgets.QVBoxLayout()
        self.setLayout(main_layout)
        main_layout.addWidget(self.img)
        main_layout.setSpacing(5)
        # main_layout.setMargin(6)
        main_layout.addWidget(self.dept_tabs)
        main_layout.addWidget(self.show_published)
        main_layout.addLayout(button_layout)

        self.show()

    #Recursivly goes through the asset's file name
    def recurseTree(self, treeItem, array, asset):
        #This is for setting bottom level text attributes
        if len(array) == 0:
            treeItem.setText(1,asset)
            treeItem.setTextColor(0,"#3c83f9")
            font = QtGui.QFont()
            font.setPointSize(12)
            font.setBold(False)
            treeItem.setFont(0,font)
            return
        else: #This is for setting parent level text attributes and settin up the structure
            item = QtWidgets.QTreeWidgetItem(array[0])
            item.setText(0,array[0])
            item.setText(1,"This is not a file")
            item.setTextColor(0,"#d0d0d0")
            font = QtGui.QFont()
            font.setPointSize(11)
            font.setBold(True)
            item.setFont(0,font)
            skip = False
            # this is to check if the child already exists
            for i in range(0,treeItem.childCount()):
                if treeItem.child(i).text(0) == item.text(0):
                    item = treeItem.child(i)
                    skip = True
            if skip == False: # Executes if the child doesnt already exist
                treeItem.addChild(item)
            newArray = array[1:]
            self.recurseTree(item, newArray,asset)
        return

    def createTabs(self):
        #remember the current index so that we can restore it when we create the tabs
        currIndex = self.dept_tabs.currentIndex()
        #clear out the old tabs
        self.dept_tabs.clear()
        #create tabs
        for dept in self.dept_list:
            tab = DepartmentTab(self)
            self.dept_tabs.addTab(tab, dept)
            tab_layout = QtWidgets.QHBoxLayout()
            element_list = QtWidgets.QTreeWidget()
            element_list.setColumnCount(1)
            commentBox = QtWidgets.QTextEdit()
            commentBox.setReadOnly(False)
            tab.commentBox = commentBox

            if dept in Department.ASSET_DEPTS:
                for asset in self.project.list_assets():
                    #print(asset)
                    if not self.show_published.isChecked() or self.hasPreviousPublish(asset, dept):
                        asset_array = asset.split("_")
                        firstelement = element_list.findItems(asset_array[0], 0, 0)
                        if not firstelement:
                            item = QtWidgets.QTreeWidgetItem(asset_array[0])
                            item.setText(0,asset_array[0])
                            item.setTextColor(0,"#d0d0d0")
                            font = QtGui.QFont()
                            font.setPointSize(11)
                            font.setBold(True)
                            item.setFont(0,font)
                            self.recurseTree(item, asset_array[1:],asset)
                            element_list.insertTopLevelItem(0,item)
                        else:
                            self.recurseTree(firstelement[0], asset_array[1:],asset)
                        element_list.currentItemChanged.connect(self.set_current_item)
            elif dept in Department.SHOT_DEPTS:
                for shot in self.project.list_shots():
                    #print(shot)
                    if not self.show_published.isChecked() or self.hasPreviousPublish(shot, dept):
                        shot_array = shot.split("_")
                        firstelement = element_list.findItems(shot_array[0], 0, 0)
                        if not firstelement:
                            item = QtWidgets.QTreeWidgetItem(shot_array[0])
                            item.setText(0,shot_array[0])
                            item.setTextColor(0,"#d0d0d0")
                            font = QtGui.QFont()
                            font.setPointSize(11)
                            font.setBold(True)
                            item.setFont(0,font)
                            self.recurseTree(item, shot_array[1:],shot)
                            element_list.insertTopLevelItem(0,item)
                        else:
                            self.recurseTree(firstelement[0], shot_array[1:],shot)
                        element_list.currentItemChanged.connect(self.set_current_item)
            elif dept in Department.CROWD_DEPTS:
                for crowdCycle in self.project.list_crowd_cycles():
                    if not self.show_published.isChecked() or self.hasPreviousPublish(crowdCycle, dept):
                        crowdCycle_array = crowdCycle.split("_")
                        firstelement = element_list.findItems(crowdCycle_array[0], 0, 0)
                        if not firstelement:
                            item = QtWidgets.QTreeWidgetItem(crowdCycle_array[0])
                            item.setText(0,crowdCycle_array[0])
                            item.setTextColor(0,"#d0d0d0")
                            font = QtGui.QFont()
                            font.setPointSize(11)
                            font.setBold(True)
                            item.setFont(0,font)
                            self.recurseTree(item, crowdCycle_array[1:],crowdCycle)
                            element_list.insertTopLevelItem(0,item)
                        else:
                            self.recurseTree(firstelement[0], crowdCycle_array[1:],crowdCycle)
                        element_list.currentItemChanged.connect(self.set_current_item)
            tab_layout.addWidget(element_list)
            tab_layout.addWidget(commentBox)
            tab.setLayout(tab_layout)

        #restore the previous index
        self.dept_tabs.setCurrentIndex(currIndex)


    def hasPreviousPublish(self, body, department):
        asset_obj = self.project.get_body(body)
        element_obj = asset_obj.get_element(department)
        last_publish = element_obj.get_last_publish()
        if last_publish is None:
            return False
        return True

    def changeBodyCheckoutVisibility(self):
        #recreate tabs the with the new check option
        self.createTabs()

    def set_current_item(self, index):
        current_dept = self.dept_list[self.dept_tabs.currentIndex()]
        if current_dept in Department.ASSET_DEPTS:
            self.current_item = str(index.text(1))
        elif current_dept in Department.SHOT_DEPTS:
            self.current_item = str(index.text(1))
        elif current_dept in Department.CROWD_DEPTS:
            self.current_item = str(index.text(1))
            #TODO what the heck? Why do we have three identical results from three different conditions? What are we trying to accomplish here? Admitadly the last one I added just following the crowd.

        asset_obj = self.project.get_body(self.current_item)
        element_obj = asset_obj.get_element(current_dept)
        last_publish = element_obj.get_last_publish()
        last_publish_comment = None
        if last_publish is not None:
            last_publish_comment = "Last published {0} by {1} \n \"{2}\"".format(last_publish[1], last_publish[0], last_publish[2])
        else:
            last_publish_comment = "No publishes for this element"
        currentTab = self.dept_tabs.currentWidget()
        currentTab.commentBox.setText(last_publish_comment)

    def checkout(self):
        """
        Checks out the currently selected item
        :return:
        """
        current_user = self.environment.get_current_username()
        current_dept = self.dept_list[self.dept_tabs.currentIndex()]
        asset_obj = self.project.get_body(self.current_item)
        element_obj = asset_obj.get_element(current_dept,force_create=True)
        element_path = element_obj.checkout(current_user)
        if element_path != None:
            self.result = element_path
            self.close()


    def closeEvent(self, event):
        self.finished.emit()
        event.accept()
Beispiel #30
0
class ElementBrowser(QtWidgets.QWidget):

	ASSETS = "Assets"
	#SHOTS = "Shots"

	BODY_DATA_COLUMN = 1
	BODY_DESCRIPTION_COLUMN = 7

	@staticmethod
	def dark_palette():
		palette = QtGui.QPalette()
		base_color = QtGui.QColor(39,39,39)
		alt_color = QtGui.QColor(30,30,30)
		text_color = QtGui.QColor(192,192,192)
		highlight_color = QtGui.QColor(57,86,115)
		highlight_text_color = QtCore.Qt.white
		disabled_alt_color = QtGui.QColor(49,49,49)
		disabled_base_color = QtGui.QColor(40,40,40)
		disabled_text_color = QtGui.QColor(100,100,100)
		palette.setColor(QtGui.QPalette.Window, base_color)
		palette.setColor(QtGui.QPalette.WindowText, text_color)
		palette.setColor(QtGui.QPalette.Base, base_color)
		palette.setColor(QtGui.QPalette.AlternateBase, alt_color)
		palette.setColor(QtGui.QPalette.ToolTipBase, alt_color)
		palette.setColor(QtGui.QPalette.ToolTipText, text_color)
		palette.setColor(QtGui.QPalette.Button, base_color)
		palette.setColor(QtGui.QPalette.ButtonText, text_color)
		palette.setColor(QtGui.QPalette.Text, text_color)
		palette.setColor(QtGui.QPalette.Highlight, highlight_color)
		palette.setColor(QtGui.QPalette.HighlightedText, highlight_text_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Window, disabled_base_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.WindowText, disabled_text_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Base, disabled_text_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.AlternateBase, disabled_alt_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Button, disabled_base_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.ButtonText, disabled_text_color)
		palette.setColor(QtGui.QPalette.Disabled, QtGui.QPalette.Text, disabled_text_color)
		return palette

	def __init__(self):
		QtWidgets.QWidget.__init__(self)
		self.setWindowTitle("Element Browser")
		self.setGeometry(0, 0, REF_WINDOW_WIDTH, REF_WINDOW_HEIGHT)
		self.palette = self.dark_palette()
		self.setPalette(self.palette)

		# initialize project
		self.project = Project()
		self.user_list = self.project.list_users()
		self.user_completer = QtWidgets.QCompleter(self.user_list)

		#filters
		self.filter_label = QtWidgets.QLabel("Filter by: ")

		self.dept_filter_label = QtWidgets.QLabel("Department")
		self.dept_filter_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
		self.dept_filter = QtWidgets.QComboBox()
		self.dept_filter.addItem("all")
		for each in Department.ALL:
			self.dept_filter.addItem(each)
		self.dept_list = Department.ALL

		self.type_filter_label = QtWidgets.QLabel("Asset Type")
		self.type_filter_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
		self.type_filter = QtWidgets.QComboBox()
		self.type_filter.addItem("all")
		for each in AssetType.ALL:
			self.type_filter.addItem(each)

		self.name_filter_label = QtWidgets.QLabel("Name")
		self.name_filter_label.setAlignment(QtCore.Qt.AlignRight | QtCore.Qt.AlignVCenter)
		self.name_filter = QtWidgets.QLineEdit()

		# menu bar
		self.menu_bar = QtWidgets.QMenuBar()
		self.view_menu = QtWidgets.QMenu("View")
		self.menu_bar.addMenu(self.view_menu)
		self.expand_action = self.view_menu.addAction("Expand All")
		self.user_list_action = self.view_menu.addAction("User Directory")
		self.theme_action = self.view_menu.addAction("Default Theme")
		self.theme_action.setCheckable(True)

		# asset/shot menu
		self.body_menu = QtWidgets.QComboBox()
		self.body_menu.addItem(self.ASSETS)
		#self.body_menu.addItem(self.SHOTS)
		self.current_body = self.ASSETS
		self._set_bodies()

		# new button
		self.new_button = QtWidgets.QPushButton("New")

		# refresh button
		self.refresh_button = QtWidgets.QPushButton("Refresh")

		# tree
		self.tree = QtWidgets.QTreeWidget()
		self.tree.setItemDelegate(TreeGridDelegate(self.tree))
		self.columnCount = 8
		self.tree.setColumnCount(self.columnCount)
		tree_header = QtWidgets.QTreeWidgetItem(["name", "", "assigned", "status", "start", "end", "publish", "note"])
		self.tree.setHeaderItem(tree_header)
		tree_header_view = self.tree.header()
		tree_header_view.resizeSection(4, 120)
		tree_header_view.resizeSection(5, 120)

		self.init_tree = [None]*self.columnCount
		self.init_tree[0] = self.init_name
		self.init_tree[1] = self.init_dept
		self.init_tree[2] = self.init_assigned_user
		self.init_tree[3] = self.init_status
		self.init_tree[4] = self.init_start_date
		self.init_tree[5] = self.init_end_date
		self.init_tree[6] = self.init_last_publish
		self.init_tree[7] = self.init_note

		self._build_tree()

		self.update_tree = [None]*self.columnCount
		self.update_tree[0] = self.update_name
		self.update_tree[1] = self.update_dept
		self.update_tree[2] = self.update_assigned_user
		self.update_tree[3] = self.update_status
		self.update_tree[4] = self.update_start_date
		self.update_tree[5] = self.update_end_date
		self.update_tree[6] = self.update_last_publish
		self.update_tree[7] = self.update_note

		# status bar
		self.status_bar = QtWidgets.QStatusBar()

		# connect events
		self.expand_action.triggered.connect(self._expand_all)
		self.user_list_action.triggered.connect(self._show_user_directory)
		self.theme_action.triggered.connect(self._toggle_theme)
		self.body_menu.currentIndexChanged.connect(self._body_changed)
		self.new_button.clicked.connect(self._new_body)
		self.refresh_button.clicked.connect(self._refresh)
		self.tree.itemExpanded.connect(self._load_elements)
		self.tree.itemChanged.connect(self._item_edited)
		self.dept_filter.currentIndexChanged.connect(self._dept_filter_changed)
		self.name_filter.editingFinished.connect(self._filter_by_name)
		self.type_filter.currentIndexChanged.connect(self._refresh)

		# layout
		layout = QtWidgets.QVBoxLayout(self)
		layout.setSpacing(5)
		layout.setMargin(6)
		options_layout = QtWidgets.QGridLayout()
		options_layout.addWidget(self.body_menu, 0, 0)
		options_layout.addWidget(self.new_button, 0, 1)
		options_layout.addWidget(self.refresh_button, 0, 3)
		options_layout.setColumnMinimumWidth(0, 100)
		options_layout.setColumnMinimumWidth(1, 100)
		options_layout.setColumnMinimumWidth(3, 100)
		options_layout.setColumnStretch(2, 1)
		filter_layout = QtWidgets.QGridLayout()
		filter_layout.addWidget(self.filter_label, 0, 0)
		filter_layout.addWidget(self.dept_filter_label, 0, 1)
		filter_layout.addWidget(self.dept_filter, 0, 2)
		filter_layout.addWidget(self.name_filter_label, 0, 3)
		filter_layout.addWidget(self.name_filter, 0, 4)
		filter_layout.addWidget(self.type_filter_label, 0, 5)
		filter_layout.addWidget(self.type_filter, 0, 6)
		filter_layout.setColumnMinimumWidth(0, 50)
		filter_layout.setColumnMinimumWidth(1, 100)
		filter_layout.setColumnMinimumWidth(2, 100)
		filter_layout.setColumnMinimumWidth(3, 100)
		filter_layout.setColumnMinimumWidth(4, 100)
		filter_layout.setColumnMinimumWidth(5, 100)
		filter_layout.setColumnMinimumWidth(6, 100)

		filter_layout.setColumnStretch(7, 1)
		layout.addWidget(self.menu_bar)
		layout.addLayout(options_layout)
		layout.addWidget(self.tree)
		layout.addLayout(filter_layout)

		layout.addWidget(self.status_bar)
		self.setLayout(layout)

		request_email.check_user_email(self)

	def _build_tree(self):
		self.tree.clear()
		tree_state = self.tree.blockSignals(True)
		for body in self.bodies:
			if(str(self.name_filter.text()) in body):
				tree_item = QtWidgets.QTreeWidgetItem([body])
				self.tree.addTopLevelItem(tree_item)
				tree_flags = tree_item.flags()
				tree_item.setFlags(tree_flags | QtCore.Qt.ItemIsEditable)
				# for col in xrange(self.columnCount):
				#	 tree_item.setBackground(col, QtWidgets.QColor(30,30,30))
				body_obj = self.project.get_body(body)
				self._load_body(body_obj, tree_item)
				tree_item.addChild(QtWidgets.QTreeWidgetItem()) # empty item
		self.tree.blockSignals(tree_state)

	def _load_body(self, body, item):
		tree_state = self.tree.blockSignals(True)
		item.setText(0, body.get_name())
		namelabel = TreeLabel(body.get_name())
		self.tree.setItemWidget(item, 0, namelabel)
		if self.current_body==self.ASSETS:
			body_type = body.get_type()
			item.setText(self.BODY_DATA_COLUMN, body_type)
			combobox = TreeComboBoxItem(item, self.BODY_DATA_COLUMN)
			type_idx = 0
			for idx, type in enumerate(AssetType.ALL):
				combobox.addItem(type)
				if type == body_type:
					type_idx = idx
			combobox.setCurrentIndex(type_idx)
			self.tree.setItemWidget(item, self.BODY_DATA_COLUMN, combobox)
		#elif self.current_body==self.SHOTS:
		#	item.setText(self.BODY_DATA_COLUMN, str(body.get_frame_range()))
		else:
			self.status_bar.showMessage("Error: unknown body type")

		description_edit = TreeLineEdit(body.get_description(), item, self.BODY_DESCRIPTION_COLUMN)
		self.tree.setItemWidget(item, self.BODY_DESCRIPTION_COLUMN, description_edit)

		for col in range(self.BODY_DATA_COLUMN+1, self.columnCount-1): # disable remaining columns
			emptylabel = TreeLabel()
			self.tree.setItemWidget(item, col, emptylabel)
		self.tree.blockSignals(tree_state)

	def _load_elements(self, item):
		tree_state = self.tree.blockSignals(True)
		body = str(item.text(0))
		body_obj = self.project.get_body(body)
		elements = []
		for dept in self.dept_list:
			dept_elements = body_obj.list_elements(dept)
			for dept_element in dept_elements:
				elements.append((dept, dept_element))
		item.takeChildren() # clear children
		for dept, element in elements:
			element_obj = body_obj.get_element(dept, element)
			child_item = QtWidgets.QTreeWidgetItem()
			item.addChild(child_item)
			child_item.setFlags(child_item.flags() | QtCore.Qt.ItemIsEditable)
			for col, init in enumerate(self.init_tree):
				init(element_obj, child_item, col)
		self.tree.blockSignals(tree_state)

	def _expand_all(self):
		# self.tree.expandAll()
		count = self.tree.topLevelItemCount()
		for i in xrange(count):
			item = self.tree.topLevelItem(i)
			self.tree.expandItem(item)

	def _show_user_directory(self):
		user_directory = UserListDialog(self)
		user_directory.show()

	def _toggle_theme(self):
		checked = self.theme_action.isChecked()
		if not checked:
			self.palette = self.dark_palette()
		else:
			self.palette = QtGui.QPalette()
		self.setPalette(self.palette)

	def _set_bodies(self):
		if self.current_body == self.ASSETS:
			asset_filter = None
			if(self.type_filter.currentIndex()):
				asset_filter_str = str(self.type_filter.currentText())
				asset_filter = (Asset.TYPE, operator.eq, asset_filter_str)
			self.bodies = self.project.list_assets(asset_filter)
		#elif self.current_body == self.SHOTS:
		#	self.bodies = self.project.list_shots()
		else:
			self.bodies = []

	def _item_edited(self, item, column):
		parent = item.parent()
		if parent is not None:
			body = str(parent.text(0))
			body_obj = self.project.get_body(body)
			element = str(item.text(0))
			dept = str(item.text(1))
			element_obj = body_obj.get_element(dept, element)
			self.update_tree[column](element_obj, item, column)
			# self.tree.resizeColumnToContents(column)
		else:
			body = str(item.text(0))
			body_obj = self.project.get_body(body)
			if column==self.BODY_DATA_COLUMN:
				self._update_body_data(body_obj, item)
			elif column==self.BODY_DESCRIPTION_COLUMN:
				self._update_body_description(body_obj, item)


	def _refresh(self): # TODO: maintain expanded rows on refresh
		self._set_bodies()
		self._build_tree()
		self.status_bar.clearMessage()

	def _body_changed(self, index):
		self.current_body = str(self.body_menu.itemText(index))
		if(self.body_menu.currentIndex()):
			self.type_filter.setEnabled(False)
			self.type_filter_label.setEnabled(False)
		else:
			self.type_filter.setEnabled(True)
			self.type_filter_label.setEnabled(True)
		self._refresh()

	def _dept_filter_changed(self):
		if(self.dept_filter.currentIndex()):
			self.dept_list = [str(self.dept_filter.currentText())]
		else:
			self.dept_list = Department.ALL
		self._refresh()

	def _filter_by_name(self):
		self._refresh()
		# target = str(self.name_filter.text())
		# for i in reversed(xrange(self.tree.topLevelItemCount())):
		#	 if (target not in self.tree.topLevelItem(i).text(0)):
		#		 self.tree.takeTopLevelItem(i)

	def _new_body(self):
		from byugui import new_body_gui
		self.new_body_dialog = new_body_gui.CreateWindow(self)
		if self.current_body == self.ASSETS:
			self.new_body_dialog.setCurrentIndex(self.new_body_dialog.ASSET_INDEX)
		#elif self.current_body == self.SHOTS:
		#	self.new_body_dialog.setCurrentIndex(self.new_body_dialog.SHOT_INDEX)
		self.new_body_dialog.finished.connect(self._refresh)

	def _update_body_data(self, body, item):
		if self.current_body==self.ASSETS:
			body.update_type(str(item.text(self.BODY_DATA_COLUMN)))
		#elif self.current_body==self.SHOTS:
		#	body.update_frame_range(int(item.text(self.BODY_DATA_COLUMN)))
		else:
			self.status_bar.showMessage("Error: unknown body type")

	def _update_body_description(self, body, item):
		body.update_description(str(item.text(self.BODY_DESCRIPTION_COLUMN)))

	def _valid_date(self, date):
		try:
			date_obj = datetime.datetime.strptime(date, "%Y-%m-%d").date()
			return str(date_obj)
		except ValueError:
			self.status_bar.showMessage(date+" not a valid date, please use format: YYYY-MM-DD")
			return None

	def init_name(self, element, item, column):
		item.setText(column, element.get_name())
		namelabel = TreeLabel(element.get_name())
		self.tree.setItemWidget(item, column, namelabel)

	def init_dept(self, element, item, column):
		item.setText(column, element.get_department())
		deptlabel = TreeLabel(element.get_department())
		self.tree.setItemWidget(item, column, deptlabel)

	def init_assigned_user(self, element, item, column):
		user = element.get_assigned_user()
		item.setText(column, user)
		lineedit = TreeLineEdit(user, item, column)
		lineedit.setCompleter(self.user_completer)
		self.tree.setItemWidget(item, column, lineedit)

	def init_status(self, element, item, column):
		item.setText(column, element.get_status())
		combobox = TreeComboBoxItem(item, column)
		element_type = element.get_status()
		type_idx = 0
		for idx, type in enumerate(Status.ALL):
			combobox.addItem(type)
			if type == element_type:
				type_idx = idx
		combobox.setCurrentIndex(type_idx)
		self.tree.setItemWidget(item, column, combobox)

	def init_start_date(self, element, item, column):
		start_date = element.get_start_date()
		item.setText(column, " "+start_date)
		start_dateedit = TreeDateEdit(start_date, item, column, self.tree)
		self.tree.setItemWidget(item, column, start_dateedit)

	def init_end_date(self, element, item, column):
		end_date = element.get_end_date()
		item.setText(column, " "+end_date)
		end_dateedit = TreeDateEdit(end_date, item, column, self.tree)
		self.tree.setItemWidget(item, column, end_dateedit)

	def init_last_publish(self, element, item, column):
		publish = element.get_last_publish()
		if publish is not None:
			item.setText(column, publish[0]+", "+publish[1]+", "+publish[2])
		else:
			item.setText(column, "")

	def init_note(self, element, item, column):
		item.setText(column, element.get_last_note())

	def update_name(self, element, item, column):
		self.status_bar.showMessage("can't change name")

	def update_dept(self, element, item, column):
		self.status_bar.showMessage("can't change department")

	def update_assigned_user(self, element, item, column):
		user = str(item.text(column))
		if user in self.user_list:
			element.update_assigned_user(user)
			self.status_bar.clearMessage()
		else:
			self.tree.itemWidget(item, column).setText(element.get_assigned_user())
			self.status_bar.showMessage('"' + user + '" is not a valid username')

	def update_status(self, element, item, column):
		element.update_status(str(item.text(column)))
		self.status_bar.clearMessage()

	def update_start_date(self, element, item, column):
		date_str = str(item.text(column))
		valid_date_str = self._valid_date(date_str)
		if valid_date_str:
			element.update_start_date(valid_date_str)
			item.setText(column, " "+date_str)
			self.status_bar.clearMessage()
		else:
			self.init_start_date(element, item, column)

	def update_end_date(self, element, item, column):
		date_str = str(item.text(column))
		valid_date_str = self._valid_date(date_str)
		if valid_date_str:
			element.update_end_date(valid_date_str)
			item.setText(column, " "+date_str)
			self.status_bar.clearMessage()
		else:
			self.init_end_date(element, item, column)

	def update_last_publish(self, element, item, column):
		self.status_bar.showMessage("can't modify publish data")
		self.init_last_publish(element, item, column)

	def update_note(self, element, item, column):
		element.update_notes(str(item.text(column)))
		self.status_bar.clearMessage()