Blender-Pipeline/studio/history.py

641 lines
29 KiB
Python
Raw Normal View History

2020-12-14 04:21:25 +01:00
# 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 hande HISTORY. Both recoring and showing. I suppose in
# future when I gonna implement Networking Multiuser support. History will be
# handling some of it too. Will see. ( I might forget about this comment and it's
# already implemented, who knows. )
################################################################################
def record(win, filename, task, checklist=[] ):
############################################################################
# This function will write the history file. Or incase connecting to multiuser
# will also notify the server of a task being done. This file probably going
# to change quite usually. Because I might start writting in more or less
# stuff. So keep an eye on it.
# Now since this will touch the multiuser and I can't guarantee that all
# users will have the same version. The multiuser part of this should insure
# stable backward compatibility with all verisons of VCStudio.
# BUT THERE IS NO WARRANTY! So who knows if exidentaly break something for
# the old versions. So keeping up to date quite advisable. Or at least keep
# the same version of VCStudio across all the computers involved in multiuser.
############################################################################
################### CHECKLIST OF IMPEMENTED DATATYPES ######################
# [V] [Openned] # WHEN BLEND FILE IS OPENNED [ settings/oscalls.py ]
2020-12-25 15:20:53 +01:00
# [V] [Linked] # AS LINKED ASSET INTO BLEND [ studio/studio_shot_linkLayer.py ]
# [V] [Edited] # WHEN EDITED STORY [ studio/studio_scriptLayer.py ]
# [V] [Updated] # WHEN CONFIGURED STUFF [ studio/studio_asset_configureLayer.py ]
2020-12-14 04:21:25 +01:00
# [V] [Added] # WHEN ADDING A BLEND FILE [ settings/oscalls.py ]
# [V] [Added Asset] # WHEN ADDING AN ASSET [ studio/studio_asset_selectLayer.py ]
# [V] [Checked] # WHEN [V] IN CHECKLIST [ studio/checklist.py ]
# [V] [Un-Checked] # WHEN [ ] IN CHECKLIST [ studio/checklist.py ]
############################################################################
############### PARSING THE URLS ##############
print("HISTORY-RAW: ", filename, task, checklist)
# Fisrt of all let's remove the project's url
filename = filename.replace(win.project, "").replace("//", "/")
# Now let's find a type
t = "files"
item = filename
if filename.startswith("/rnd"):
t = "scenes"
item = filename.replace("/rnd", "")
filename = filename[filename.rfind("/"):]
2020-12-15 21:38:04 +01:00
item = item[:item.rfind(filename)]
2020-12-14 04:21:25 +01:00
elif filename.startswith("/ast") or filename.startswith("/dev"):
t = "assets"
if filename.startswith("/ast"):
filename = "[asset_blend]"
item = item.replace(".blend", "").replace("/ast", "")
elif filename.startswith("/dev"):
f = filename[filename.rfind("/"):]
item = filename.replace(f, "").replace("/dev", "")
filename = f
else:
filename = filename[filename.rfind("/"):]
item = item.replace("//", "/")
filename = filename.replace("//", "/")
2020-12-25 15:20:53 +01:00
# Somebody please look at this. Maybe there is more clever way to record
# editing of scenes. I don't know.
if task == "[Edited]":
item = filename
2020-12-14 04:21:25 +01:00
print("HISTORY: ", t, item, filename, task, checklist)
########### WRITING TO THE ANANLYTICS ###########
new_date_format = "%Y/%m/%d"
date = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
seconds_format = "%H:%M:%S"
time = datetime.datetime.strftime(datetime.datetime.now(), seconds_format)
username = win.settings["Username"]
# Now since we have our DATE and TIME we can start writing.
if date not in win.analytics["dates"]:
win.analytics["dates"][date] = {}
if t not in win.analytics["dates"][date]:
win.analytics["dates"][date][t] = {}
if item not in win.analytics["dates"][date][t]:
win.analytics["dates"][date][t][item] = []
# APPENDNING
if not checklist:
win.analytics["dates"][date][t][item].append(
[
time,
"history",
filename,
task,
username
]
)
else:
win.analytics["dates"][date][t][item].append(
[
time,
"history",
filename,
task,
checklist,
username
]
)
# REFRASHING
analytics.save(win.project, win.analytics)
win.analytics = analytics.load(win.project)
def draw(outlayer, win):
x = 10
y = 70
width = win.current["w"] / 4 - 20
height = win.current["h"] - 80
# 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()
# Background
#UI_color.set(layer, win, "dark_overdrop")
#layer.rectangle(0,0,width, height)
#layer.fill()
new_date_format = "%Y/%m/%d"
today = datetime.datetime.strftime(datetime.datetime.today(), new_date_format)
if not win.cur:
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"))
if "history" not in win.scroll:
win.scroll["history"] = 0
current_Y = 0
# OKAY I GUESS SINCE HISTORY IS RELATIVELLY SIMPLE (LOL) I WILL PARSE IT
# STRAIGHT. Without making a whole lot of parsing. Because with schedules
# it resulted in some rather hilarious stuff.
if "history_selection" not in win.current:
win.current["history_selection"] = {
"date":win.current["date"],
"item":False,
"user":False
}
dates = win.analytics["dates"]
for date in dates:
if not win.cur and date != win.current["date"]:
continue
theday = date
date = dates[date]
# Now let's parse throught it. I guess.
for i in ["files", "assets", "scenes"]:
if i in date:
for item in date[i]:
# This is our individual items. I want to create a folder
# with USERS inside it. So you could see who done what.
2020-12-15 21:38:04 +01:00
if win.cur.count("/") > 1:
tmp = win.cur.replace("/","",1).split("/")
acur, name = tmp[0], tmp[1]
else:
name = win.cur[win.cur.rfind("/")+1:]
acur = ""
if win.cur not in item and win.cur:
continue
name = item[item.rfind("/")+1:]
acur = item.replace(name, "").replace("/", "")
2020-12-14 04:21:25 +01:00
found = {}
for stuff in date[i][item]:
if stuff[1] == "history":
if stuff[-1] not in found:
found[stuff[-1]] = []
if stuff[3] in ["[Checked]", "[Un-Checked]"]:
found[stuff[-1]].append([stuff[0],stuff[2],stuff[3],stuff[4]])
else:
found[stuff[-1]].append([stuff[0],stuff[2],stuff[3],[]])
if found:
# Now let's output our findings
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
0,
win.scroll["history"] + current_Y,
width,
50,
10)
# ICON
if i == "scenes" and not win.cur:
2020-12-25 15:20:53 +01:00
if item.count("/") > 1:
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/shot.png",
5, win.scroll["history"] + current_Y+5, 40, 40)
else:
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/scene.png",
5, win.scroll["history"] + current_Y+5, 40, 40)
2020-12-14 04:21:25 +01:00
elif i == "assets" and not win.cur:
if os.path.exists(os.getcwd()+"/settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png"):
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/"+acur+".png",
5, win.scroll["history"] + current_Y+5, 40, 40)
else:
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/"+name+".png",
5, win.scroll["history"] + current_Y+5, 40, 40)
name = talk.text(name.replace("/", ""))
else:
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/history.png",
5, win.scroll["history"] + 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["history"] + current_Y+30,
)
if not win.cur:
2020-12-25 15:20:53 +01:00
if "chr" not in item and "veh" not in item and "loc" not in item and "obj" not in item and "set" not in item:
layer.show_text(item.replace("/","",1).replace("/", " | "))
else:
layer.show_text(name.replace("project.progress", win.analytics["name"]))
2020-12-14 04:21:25 +01:00
else:
layer.show_text(theday)
# Selection button
def do():
win.current["history_selection"]["item"] = item
win.current["history_selection"]["date"] = theday
win.current["history_selection"]["user"] = False
UI_elements.roundrect(layer, win,
0,
win.scroll["history"] + current_Y,
width,
50,
10,
button=do,
fill=False,
offset=[x,y])
layer.stroke()
if win.current["history_selection"]["item"] == item\
and win.current["history_selection"]["date"] == theday:
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
0,
win.scroll["history"] + current_Y,
width,
50,
10,
fill=False)
layer.stroke()
current_Y = current_Y + 60
# It a history is selected you could open up the list
# of users that worked on a given task.
for user in found:
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
20,
win.scroll["history"] + current_Y,
width-20,
50,
10)
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/user.png",
25, win.scroll["history"] + current_Y+5, 40, 40)
# NAME OF THE USER
UI_color.set(layer, win, "text_normal")
layer.set_font_size(20)
layer.move_to(
70,
win.scroll["history"] + current_Y+30,
)
layer.show_text(user)
# SELECTION BOX
def do():
win.current["history_selection"]["user"] = user
UI_elements.roundrect(layer, win,
20,
win.scroll["history"] + current_Y,
width-20,
50,
10,
button=do,
fill=False,
offset=[x,y])
layer.stroke()
# IF THE USER IS SELECTED
if win.current["history_selection"]["user"] == user:
UI_color.set(layer, win, "progress_background")
UI_elements.roundrect(layer, win,
20,
win.scroll["history"] + current_Y,
width-20,
50,
10,
fill=False)
layer.stroke()
current_Y = current_Y + 60
for stuff in found[user]:
UI_color.set(layer, win, "node_background")
UI_elements.roundrect(layer, win,
40,
win.scroll["history"] + current_Y,
width-40,
50,
10)
# Here if both category and the user are
# selected I need to parse the data of
# the history to present it to you.
operation_icons = {
"[Openned]":"blender",
"[Linked]":"file_link",
2020-12-25 15:20:53 +01:00
"[Edited]":"scene",
2020-12-14 04:21:25 +01:00
"[Updated]":"update",
"[Added]":"new",
"[Added Asset]":"asset_new",
"[Checked]":"checked",
"[Un-Checked]":"unchecked"
}
try:
icon = operation_icons[stuff[2]]
except:
icon = "history"
UI_elements.image(layer, win,
"settings/themes/"+win.settings["Theme"]+"/icons/"+icon+".png",
45, win.scroll["history"] + current_Y+5, 40, 40)
# Next will be to add some text about
# what exactly was done here. And I know
# that we are already super inside. I
# mean indentation. If somebody want's
# to reduse a few spaces. They are
# welcome to try.
# Let's split the the history entries to
# 2 types. Checklists and everything else.
# CHECKLISTS
if "Checked" in stuff[2]:
# Let's get task and url
try:
task = stuff[-1][-1]
fullurl = ""
for e in stuff[-1][:-1]:
fullurl = fullurl+e+" > "
except:
tasl = ""
fullurl = ""
# MAIN TASK
UI_color.set(layer, win, "text_normal")
layer.set_font_size(20)
layer.move_to(
80,
win.scroll["history"] + current_Y+24,
)
layer.show_text(task)
# TASK URL INSIDE THE CHECKLIST
if fullurl:
UI_color.set(layer, win, "text_normal")
layer.set_font_size(10)
layer.move_to(
90+len(task)*12,
win.scroll["history"] + current_Y+24,
)
layer.show_text(fullurl)
else:
# If it's not a checklist. I just want
# to output what it is and what action
# happened to it.
task = stuff[1].replace("/", " ")
if task == "[asset_blend]":
task = " Asset Blend File"
# WHAT
UI_color.set(layer, win, "text_normal")
layer.set_font_size(20)
layer.move_to(
80,
win.scroll["history"] + current_Y+24,
)
layer.show_text(task)
# WHAT WAS DONE
UI_color.set(layer, win, "text_normal")
layer.set_font_size(10)
layer.move_to(
90+len(task)*12,
win.scroll["history"] + current_Y+24,
)
layer.show_text(stuff[2])
UI_color.set(layer, win, "text_normal")
layer.set_font_size(15)
layer.move_to(
92,
win.scroll["history"] + current_Y+41,
)
layer.show_text(stuff[0])
# Okay and the last thing. The button of
# when it's clicked. For example to get
# to the item. Or to find the task in
# the checklist. For what ever reason.
def do():
# Let's make the auto-selecting of
# the checklists. OMG I really have
# no space left to type. OMG. What
# is this.
if "Checked" in stuff[2]:
# AAAAAAAAAAAAAAAAAAAAAAAAAAAA
# How am I supposed to tell thi-
# ngs? OMG.
if "schedule_task_selected" not in win.current:
win.current["schedule_task_selected"] = []
win.current["schedule_task_selected"] = \
[[[stuff[0], "schedule", stuff[1], stuff[2], stuff[3]], 0], item]
# Now since we did this weird
# what ever the mack. Let's make so
# it's going to the asset.
if i == "assets":
goto = "assets"
elif i == "scenes":
goto = "script"
else:
goto = "analytics"
win.url = goto
win.cur = item
win.current["asset_left_panel"] = "history"
if stuff[2] != "[Added Asset]":
UI_elements.roundrect(layer, win,
40,
win.scroll["history"] + current_Y,
width-40,
50,
10,
button=do,
fill=False,
offset=[x,y])
layer.stroke()
current_Y = current_Y + 60
else:
current_Y = current_Y + 60
else:
current_Y = current_Y + 60
# Outputting the layer
outlayer.set_source_surface(surface, x, y)
outlayer.paint()
# Scroll
UI_elements.scroll_area(outlayer, win, "history",
x+0,
y+50,
width,
height-50,
current_Y,
bar=True,
mmb=True)