123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820 |
- # THIS FILE IS A PART OF VCStudio
- # PYTHON 3
- import os
- import datetime
- import threading
- # GTK module ( Graphical interface
- import gi
- gi.require_version('Gtk', '3.0')
- from gi.repository import Gtk
- from gi.repository import GLib
- from gi.repository import Gdk
- import cairo
- # Own modules
- from settings import settings
- from settings import talk
- from project_manager import pm_project
- from studio import analytics
- from studio import studio_nodes
- from studio import studio_dialogs
- from studio import story
- from studio import analytics
- from studio import checklist
- #UI modules
- from UI import UI_elements
- from UI import UI_color
- ################################################################################
- # This file is going to handle SCHEDULING. Primarily the output of the schedules
- # to the screen. But also probably a lot of other things related to schediles.
- ################################################################################
- def filter(project, dates):
-
- ############################################################################
-
- # This function is called on reading of analytics read. It will check whether
- # schedules are finished. Or if they are even found. Using studio/checklist.py
- # as a help.
-
- ############################################################################
-
- checkcashe = {} # Temporary checklist cashe.
-
- delete = [] # Stuff I want to delete later
-
- for date in dates:
- for i in ["assets", "scenes", "files"]:
- if i in dates[date]:
- for url in dates[date][i]:
- for num, entry in enumerate(dates[date][i][url]):
- if dates[date][i][url][num][1] == "schedule":
-
- # First of all. I didn't think about it when
- # writting the analytics read
- # that I will need to know whether schedules
- # are [Checked] or [Un-Checked]
-
- if not "[Checked]" in dates[date][i][url][num]\
- and not "[Un-Checked]" in dates[date][i][url][num]:
- dates[date][i][url][num].insert(3, "[Un-Checked]")
-
- # Then let's actually try to find whether the task
- # is checked.
-
-
- # For now let's do in a simple way. Because
- # if the whole checklist is 100% done. Then
- # obviously the task is also checked.
-
- path = dates[date][i][url][num][2]
-
-
- try:
-
- # Let's check if path exists in the project first.
- if os.path.exists(project+"/dev"+url+path):
- path = project+"/dev"+url+path
-
-
- elif os.path.exists(project+"/rnd"+url+path):
- path = project+"/rnd"+url+path
-
- elif os.path.exists(project+"/set/"+path):
- path = project+"/set/"+path
-
- elif os.path.exists(project+"/"+path):
- path = project+"/"+path
-
- if path not in checkcashe:
- checkcashe[path] = checklist.get_list(path)
-
- # Here we check whether the checklist is 100%
-
- if checkcashe[path]["fraction"] == 1.0:
- dates[date][i][url][num][3] = "[Checked]"
-
- # But what if it's not? Now we need to check
- # them 1 by one.
-
- else:
-
- dates[date][i][url][num][3] = "[Un-Checked]"
-
- task = checklist.get_task_by_path(checkcashe[path]["subtasks"],dates[date][i][url][num][4])
-
- # Now if the task is not found. We delete the schedule
- if task:
- if task["fraction"] == 1.0:
- dates[date][i][url][num][3] = "[Checked]"
-
- else:
- delete.append([date,i,url,dates[date][i][url][num]])
- except:
- delete.append([date,i,url,dates[date][i][url][num]])
-
- # Deleting all kinds of buddah
-
- for i in delete:
- q,w,e,r = i
- if r in dates[q][w][e]:
- dates[q][w][e].remove(r)
-
-
-
- return dates
-
- def get_schedules(dates):
-
- ############################################################################
-
- # This function will parse the dates data from the analytics. And get only
- # the schedules. In the format {date {url, [list of schedules]}}
-
- ############################################################################
- newdates = {}
-
- for date in dates:
- if date not in newdates:
- newdates[date] = {}
-
- for i in ["assets", "scenes", "files"]:
- if i in dates[date]:
- for url in dates[date][i]:
- for num, entry in enumerate(dates[date][i][url]):
- if entry[1] == "schedule":
- if url not in newdates[date]:
- newdates[date][url] = []
- if [entry, num] not in newdates[date][url]:
- newdates[date][url].append([entry, num])
-
-
- return newdates
-
-
- def draw(outlayer, win):
-
- x = 10
- y = 70
- width = win.current["w"] / 4 - 20
- height = win.current["h"] - 80
-
- # At the top above the schedules. In the bar. i want to put 2
- # buttons. One will hide done schedules, the other will
- # hide everything scheduled for other users.
-
- if "schedule_layer_settings" not in win.current:
- win.current["schedule_layer_settings"] = {
- "checked":False,
- "multiuser":False
- }
-
- for num, button in enumerate(win.current["schedule_layer_settings"]):
-
- if win.current["schedule_layer_settings"][button]:
-
- UI_color.set(outlayer, win, "progress_time")
- UI_elements.roundrect(outlayer, win,
- 20+width-(40*num)-60,
- 15,
- 40,
- 40,
- 10)
-
- def do():
- win.current["schedule_layer_settings"][button] = not win.current["schedule_layer_settings"][button]
-
- UI_elements.roundrect(outlayer, win,
- 20+width-(40*num)-60,
- 15,
- 40,
- 40,
- 10,
- do,
- button)
-
-
- # Now let's make a layer.
-
- # Making the layer
- surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
- layer = cairo.Context(surface)
- layer.select_font_face("Monospace", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
-
- # Clip
- UI_elements.roundrect(layer, win,
- 0,
- 0,
- width,
- height,
- 10,
- fill=False)
- layer.clip()
-
-
- # Getting various screadule data
- schedules = get_schedules(win.analytics["dates"])
- new_date_format = "%Y/%m/%d"
- today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
-
-
- UI_elements.text(outlayer, win, "current_date_setting",
- width-100-(width-6*40),
- 15,
- (width-6*40),
- 40,
- set_text=win.current["date"])
-
- if win.text["current_date_setting"]["text"] != win.current["date"]\
- and analytics.ifdate(win.text["current_date_setting"]["text"]):
- def do():
- win.current["date"] = win.text["current_date_setting"]["text"]
- win.textactive = ""
-
- UI_elements.roundrect(outlayer, win,
- width-140,
- 15,
- 40,
- 40,
- 10,
- button=do,
- icon="ok",
- tip=talk.text("checked"))
-
- elif win.current["date"] != today:
- def do():
- win.current["date"] = today
- win.text["current_date_setting"]["text"] = today
- win.textactive = ""
-
- UI_elements.roundrect(outlayer, win,
- width-140,
- 15,
- 40,
- 40,
- 10,
- button=do,
- icon="cancel",
- tip=talk.text("cancel"))
-
-
-
- slist = []
-
- for date in schedules:
-
- if win.current["date"] != today and date != win.current["date"]:
- continue
-
- for item in schedules[date]:
- if win.cur in item or not win.cur or win.cur == "/set":
-
- slist.append([date, item, schedules[date][item]])
-
-
- # Selection magic
- if "schedule_task_selected" not in win.current:
- win.current["schedule_task_selected"] = False
-
- # Let's draw them to the screen in some way
-
- if "schedule" not in win.scroll:
- win.scroll["schedule"] = 0
-
- current_Y = 0
-
- for entry in slist:
-
- for thing in entry[2]:
-
-
-
- # Parsing the cur to get name and type
- name = entry[1][entry[1].rfind("/")+1:]
- acur = entry[1].replace(name, "").replace("/", "")
-
- if entry[1].count("/") > 1:
- tmp = entry[1].replace("/","",1).split("/")
- acur, name = tmp[0], tmp[1]
- else:
- name = entry[1][entry[1].rfind("/")+1:]
- acur = ""
-
-
- fullurl = ""
- for e in thing[0][4][:-1]:
- fullurl = fullurl+e+" > "
-
-
- if acur in ["chr", "veh", "loc","obj"]:
- itemtype = "assets"
- elif not acur:
- itemtype = "files"
- else:
- itemtype = "scenes"
-
- try:
- if not win.analytics["dates"][entry[0]][itemtype]\
- [entry[1]]:
- continue
- except:
- continue
-
-
- UI_color.set(layer, win, "node_background")
-
- # If not all users show only current user's tasks
- if not win.current["schedule_layer_settings"]["multiuser"]\
- and thing[0][-1] != win.settings["Username"]:
- continue
-
- # If the task is checked
- if thing[0][3] == "[Checked]":
- if not win.current["schedule_layer_settings"]["checked"]:
- continue
- UI_color.set(layer, win, "node_blendfile") # The Green
-
-
- elif entry[0] != "1997/07/30":
-
- if entry[0] < today:
- UI_color.set(layer, win, "node_badfile") # The Red
- elif entry[0] > today:
- UI_color.set(layer, win, "node_asset") # The Purple
-
- UI_elements.roundrect(layer, win,
- 0,
- win.scroll["schedule"] + current_Y,
- width,
- 75,
- 10)
-
- # Selection button
- def do():
-
- if win.current["tool"] == "selection":
-
- if win.current["schedule_task_selected"] != [ thing, entry[1] ]:
- win.current["schedule_task_selected"] = [ thing, entry[1] ]
- else:
- win.current["schedule_task_selected"] = False
-
- # Clearing the text
- try:
- del win.text["schedule_username_setting"]
- del win.text["schedule_date_setting"]
- del win.text["schedule_time_setting"]
- except:
- pass
- UI_elements.roundrect(layer, win,
- 0,
- win.scroll["schedule"] + current_Y,
- width,
- 75,
- 10,
- button=do,
- tip=entry[1]+" : "+fullurl+thing[0][4][-1],
- offset=[x,y],
- fill=False)
- layer.stroke()
-
- ############# GRABBING FOR RE-SCHEDULING ##############
-
-
-
- # Grab
- if win.current["LMB"]\
- and int(win.current["LMB"][0]) in range(int(x), int(x+width))\
- and int(win.current["LMB"][1]) in range(int(y+win.scroll["schedule"] + current_Y), int(y+win.scroll["schedule"] + current_Y+75))\
- and win.current["tool"] == "selection"\
- and int(win.current["LMB"][0]) not in range(int(win.current["mx"]-2), int(win.current["mx"]+2))\
- and int(win.current["LMB"][1]) not in range(int(win.current["my"]-2), int(win.current["my"]+2)):
-
- try:
-
- pop = win.analytics["dates"][entry[0]][itemtype]\
- [entry[1]].pop(thing[1])
-
- dev = ""
- if itemtype == "assets":
- dev = "/dev"
- if itemtype == "scenes":
- dev = "/rnd"
-
- win.current["tool"] = "schedule"
- win.current["grab_data"] = [dev+entry[1]+thing[0][2], win.url, entry[1], pop[4], pop[-1]]
- win.url = "analytics"
- except:
- pass
-
- # If you leave it here.
- if win.current["tool"] == "schedule" and not win.current["LMB"]:
-
- path, back, cur, schedulepath, username = win.current["grab_data"].copy()
- path = path.replace(win.project, "")
- path = path[path.find(cur)+len(cur):]
- tname = cur[cur.rfind("/")+1:]
- tacur = cur.replace(name, "").replace("/", "")
-
- if tacur in ["chr", "veh", "loc","obj"]:
- itemtype = "assets"
- elif not tacur:
- itemtype = "files"
- else:
- itemtype = "scenes"
-
- theday = win.current["date"]
-
- if theday not in win.analytics["dates"]:
- win.analytics["dates"][theday] = {}
-
- if itemtype not in win.analytics["dates"][theday]:
- win.analytics["dates"][theday][itemtype] = {}
-
- if cur not in win.analytics["dates"][theday][itemtype]:
- win.analytics["dates"][theday][itemtype][cur] = []
-
- win.analytics["dates"][theday][itemtype][cur].append(
- ["00:00:00",
- "schedule",
- path,
- "[Un-Checked]",
- schedulepath,
- username]
- )
-
-
- # RETURNING BACK TO NORMAL
-
- win.url = back
- win.current["tool"] = "selection"
- analytics.save(win.project, win.analytics)
- win.analytics = analytics.load(win.project)
- win.checklists = {}
-
- # Multiuser sycning
- win.multiuser["request"] = "analytics"
-
-
-
- #########################################################
-
-
-
- # ICON
- UI_elements.image(layer, win,
- "settings/themes/"+win.settings["Theme"]+"/icons/schedule.png",
- 5, win.scroll["schedule"] + current_Y+5, 40, 40)
-
- # MAIN TASK
- UI_color.set(layer, win, "text_normal")
- layer.set_font_size(20)
- layer.move_to(
- 50,
- win.scroll["schedule"] + current_Y+25,
- )
- layer.show_text(thing[0][4][-1])
-
- # TASK URL INSIDE THE CHECKLIST
-
- if fullurl:
- layer.set_font_size(10)
- layer.move_to(
- 60+len(thing[0][4][-1])*12,
- win.scroll["schedule"] + current_Y+25,
- )
- layer.show_text(fullurl)
-
- # NAME OF THE ASSET / SHOT
- if acur in ["chr", "veh", "loc", "obj"]:
- assetname = talk.text(acur)+": "+name
- else:
- assetname = entry[1].replace("/set", "")
-
- layer.set_font_size(15)
- layer.move_to(
- 50,
- win.scroll["schedule"] + current_Y+45,
- )
- layer.show_text(assetname)
-
- # DATE
- if entry[0] != "1997/07/30" and entry[0] != today:
- layer.set_font_size(15)
- layer.move_to(
- width-130,
- win.scroll["schedule"] + current_Y+45,
- )
- layer.show_text(entry[0])
-
- # TIME
-
- layer.set_font_size(15)
- layer.move_to(
- width-130,
- win.scroll["schedule"] + current_Y+65,
- )
- layer.show_text(thing[0][0])
-
- # USERNAME
- layer.set_font_size(15)
- layer.move_to(
- 20,
- win.scroll["schedule"] + current_Y+65,
- )
- layer.show_text(talk.text("user_schedules")+" "+thing[0][-1])
-
- # IF SELECTED THERE WILL BE MORE STUFF
- if win.current["schedule_task_selected"] == [ thing, entry[1] ]:
- UI_color.set(layer, win, "text_normal")
- UI_elements.roundrect(layer, win,
- 1,
- win.scroll["schedule"] + current_Y,
- width-2,
- 75,
- 10,
- fill=False)
- layer.stroke()
-
- current_Y = current_Y + 85
-
- # If it's a task from an asset or a scene. There should be a link
- # to it. But first let's check that's it's infect an asset.
- # because...
-
- if entry[1] and entry[1] != "/set":
-
- goto = "script"
- itemtype = "scenes"
-
- # If asset:
- if acur in ["chr", "veh", "loc","obj"]:
- # ICON
- UI_elements.image(layer, win,
- "settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png",
- 25, win.scroll["schedule"] + current_Y+5, 40, 40)
-
- goto = "assets"
- itemtype = "assets"
-
- elif not acur:
- itemtype = "files"
- else:
- goto = "script"
- itemtype = "scenes"
-
- if goto == "script":
- # ICON
- UI_elements.image(layer, win,
- "settings/themes/"+win.settings["Theme"]+"/icons/scene.png",
- 25, win.scroll["schedule"] + current_Y+5, 40, 40)
-
- # Here comes the link button
-
- def do():
- win.url = goto
- win.cur = entry[1]
- win.current["asset_left_panel"] = "schedule"
- UI_elements.roundrect(layer, win,
- 20,
- win.scroll["schedule"] + current_Y+5,
- width-20,
- 40,
- 10,
- button=do,
- tip=entry[1]+" : "+fullurl+thing[0][4][-1],
- offset=[x,y],
- fill=False)
- layer.stroke()
-
- #Title
- UI_color.set(layer, win, "text_normal")
- layer.set_font_size(20)
- layer.move_to(
- 80,
- win.scroll["schedule"] + current_Y+30,
- )
- layer.show_text(assetname)
-
- current_Y = current_Y + 50
-
- # Next thing! Let's show the most editable values. I think the first
- # one. For the director will be important. Is to edit the USER.
- # or in other words. Who is doing the task.
-
- # In the end It will be a drop down menu. Like all of it. But for this
- # I need to implement MULTIUSER first. And it's not a priority right
- # now. So a simple text editor could be okay.
-
- # ICON
- UI_elements.image(layer, win,
- "settings/themes/"+win.settings["Theme"]+"/icons/user.png",
- 25, win.scroll["schedule"] + current_Y+5, 40, 40)
-
- UI_elements.text(layer, win, "schedule_username_setting",
- 80,
- win.scroll["schedule"] + current_Y+5,
- width-80,
- 40,
- set_text=thing[0][-1],
- tip=talk.text("username"),
- offset=[x,y])
-
- if win.text["schedule_username_setting"]["text"] != thing[0][-1]:
- def do():
- thing[0][-1] = win.text["schedule_username_setting"]["text"]
- analytics.save(win.project, win.analytics)
-
- # Multiuser sycning
- win.multiuser["request"] = "analytics"
-
- UI_elements.roundrect(layer, win,
- width-40,
- win.scroll["schedule"] + current_Y+5,
- 40,
- 40,
- 10,
- button=do,
- icon="ok",
- tip=talk.text("checked"),
- offset=[x,y])
-
- current_Y = current_Y + 50
-
- # Multiuser now gave a way to give who ever does the assingments
- # a tool to select the name from a drop down menu. Rather then
- # type it by hand. I will still have the ability to type. What
- # if that someone is not logged in currently.
-
- if win.textactive == "schedule_username_setting":
-
- # So when you clicked to edit a drop down menu will appear.
-
- for user in win.multiuser["users"]:
-
- # It's going to be simple buttons with user icons and
- # the username.
- def do():
- thing[0][-1] = win.multiuser["users"][user]["username"]
- analytics.save(win.project, win.analytics)
- win.text["schedule_username_setting"]["text"] = thing[0][-1]
- win.textactive = ""
-
-
- # Multiuser sycning
- win.multiuser["request"] = "analytics"
-
- UI_elements.roundrect(layer, win,
- 80,
- win.scroll["schedule"] + current_Y+5,
- width-80,
- 40,
- 10,
- button=do,
- icon="user",
- tip=win.multiuser["users"][user]["username"],
- offset=[x,y])
-
- UI_color.set(layer, win, "text_normal")
- layer.set_font_size(20)
- layer.move_to(
- 130,
- win.scroll["schedule"] + current_Y+30,
- )
- layer.show_text(win.multiuser["users"][user]["username"])
-
- current_Y = current_Y + 50
-
- # DATE : TIME
-
- UI_elements.image(layer, win,
- "settings/themes/"+win.settings["Theme"]+"/icons/schedule.png",
- 25, win.scroll["schedule"] + current_Y+5, 40, 40)
-
- UI_elements.text(layer, win, "schedule_date_setting",
- 80,
- win.scroll["schedule"] + current_Y+5,
- (width-80)/2-20,
- 40,
- set_text=entry[0],
- tip=talk.text("username"),
- offset=[x,y])
-
- ### DELETE KEY ###
-
- if acur in ["chr", "veh", "loc","obj"]:
- itemtype = "assets"
- elif not acur:
- itemtype = "files"
- else:
- itemtype = "scenes"
-
- if 65535 in win.current["keys"]:
- pop = win.analytics["dates"][entry[0]][itemtype]\
- [entry[1]].pop(thing[1])
- win.current["keys"] = []
-
- analytics.save(win.project, win.analytics)
- win.analytics = analytics.load(win.project)
-
- if win.text["schedule_date_setting"]["text"] != entry[0]\
- and analytics.ifdate(win.text["schedule_date_setting"]["text"]):
- def do():
-
-
-
- pop = win.analytics["dates"][entry[0]][itemtype]\
- [entry[1]].pop(thing[1])
-
- if win.text["schedule_date_setting"]["text"] not in win.analytics["dates"]:
- win.analytics["dates"][win.text["schedule_date_setting"]["text"]] = {}
- if itemtype not in win.analytics["dates"][win.text["schedule_date_setting"]["text"]]:
- win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype] = {}
- if entry[1] not in win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype]:
- win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype][entry[1]] = []
-
- win.analytics["dates"][win.text["schedule_date_setting"]["text"]][itemtype]\
- [entry[1]].append(pop)
-
- analytics.save(win.project, win.analytics)
- win.analytics = analytics.load(win.project)
-
- # Multiuser sycning
- win.multiuser["request"] = "analytics"
-
- UI_elements.roundrect(layer, win,
- (width-80)/2+20,
- win.scroll["schedule"] + current_Y+5,
- 40,
- 40,
- 10,
- button=do,
- icon="ok",
- tip=talk.text("checked"),
- offset=[x,y])
-
- # TIME
-
- UI_elements.text(layer, win, "schedule_time_setting",
- 80+(width-80)/2,
- win.scroll["schedule"] + current_Y+5,
- (width-80)/2,
- 40,
- set_text=thing[0][0],
- tip=talk.text("username"),
- offset=[x,y])
-
- if win.text["schedule_time_setting"]["text"] != thing[0][0]\
- and analytics.iftime(win.text["schedule_time_setting"]["text"]):
- def do():
- thing[0][0] = win.text["schedule_time_setting"]["text"]
-
- analytics.save(win.project, win.analytics)
- win.analytics = analytics.load(win.project)
-
- # Multiuser sycning
- win.multiuser["request"] = "analytics"
-
- UI_elements.roundrect(layer, win,
- width-40,
- win.scroll["schedule"] + current_Y+5,
- 40,
- 40,
- 10,
- button=do,
- icon="ok",
- tip=talk.text("checked"),
- offset=[x,y])
-
-
-
- current_Y = current_Y + 70
-
-
- else:
- current_Y = current_Y + 85
-
-
-
- # Outputting the layer
- outlayer.set_source_surface(surface, x, y)
- outlayer.paint()
-
- # Scroll
- UI_elements.scroll_area(outlayer, win, "schedule",
- x+0,
- y+50,
- width,
- height-50,
- current_Y,
- bar=True,
- mmb=True)
|