Blender-Pipeline/studio/schedule.py

766 lines
28 KiB
Python

# 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:
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 = {}
#########################################################
# 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]
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]:
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)
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
# 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)
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)
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)