-
-
Save Andrej730/ffe91117fea88c84f28df000463447a5 to your computer and use it in GitHub Desktop.
# ***** BEGIN GPL LICENSE BLOCK ***** | |
# | |
# | |
# This program is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License | |
# as published by the Free Software Foundation; either version 2 | |
# of the License, or (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, write to the Free Software Foundation, | |
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |
# | |
# ***** END GPL LICENCE BLOCK ***** | |
bl_info = { | |
"name": "Reload if Modified", | |
"author": "Dany Lebel (Axon_D), updated by @Andrej730", | |
"version": (1,0), | |
"blender": (2, 80, 0), | |
"location": "Text Editor -> Header Bar -> Reload if Modified", | |
"description": "Determine if a text datablock must be reloaded from file in the case that it has changed", | |
"warning": "", | |
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.5/Py/Scripts/Text_Editor/Reload_if_Modified", | |
"tracker_url": "http://projects.blender.org/tracker/index.php?func=detail&aid=25277&group_id=153&atid=467", | |
"category": "Text Editor" | |
} | |
# https://archive.blender.org/wiki/index.php/Extensions:2.5/Py/Scripts/Text_Editor/Reload_if_Modified/ | |
""" | |
This addon will automatically reload a text datablock if its source file | |
does not corresponds to the last blendfile version. This must be checked | |
for each file wanted to be updated automatically. It has no effect on internal datablock. | |
""" | |
import bpy | |
def check_texts_every_second(): | |
for text in bpy.data.texts: | |
if text.is_in_memory: | |
continue | |
if text.is_modified and text.reload_if_modified: | |
# using reloading operators causes crashes, therefore we reload the text manually | |
# saving text to file afterwards as it's the only way to flip `.is_modified` | |
# since reload doesn't work - https://projects.blender.org/blender/blender/issues/113644 | |
with open(text.filepath, 'r') as fi: | |
new_text = fi.read() | |
text.from_string(new_text) | |
def get_area(): | |
for screen in bpy.data.screens: | |
for area in screen.areas: | |
if area.type == "TEXT_EDITOR": | |
return area | |
context_override = {} | |
context_override["edit_text"] = text | |
space = next(space for space in get_area().spaces if space.type == "TEXT_EDITOR") | |
context_override["space_data"] = space | |
with bpy.context.temp_override(**context_override): | |
bpy.ops.text.save() | |
return 1 # every second | |
def draw_header(self, context): | |
text = context.space_data.text | |
if not text: | |
return | |
if text.is_in_memory: | |
return | |
layout = self.layout | |
row = layout.row() | |
row.prop(text, "reload_if_modified") | |
def register(): | |
bpy.types.Text.reload_if_modified = bpy.props.BoolProperty( | |
name='Reload if Modified', | |
description= | |
'Automatically reload text file if it has changed', | |
default=False, | |
) | |
# tried `bpy.msgbus.subscribe_rna(key=bpy.data.texts.path_resolve("is_modified", False))` | |
# and didn't worked, therefore going to timer approach as depsgraph update won't be often enough | |
# maybe there is more clever way to do this | |
bpy.types.TEXT_HT_header.append(draw_header) | |
bpy.app.timers.register(check_texts_every_second) | |
def unregister(): | |
del bpy.types.Text.reload_if_modified | |
bpy.types.TEXT_HT_header.remove(draw_header) | |
bpy.app.timers.register(check_texts_every_second) | |
if __name__ == '__main__': | |
register() |
@Richardn2002 check out console errors, maybe it has some clues.
I did not see any error messages on blender --debug-all
, so I turned to good ol' print debugging. I injected:
import bpy
import logging
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.addHandler(logging.StreamHandler())
def check_texts_every_second():
logger.debug("reload_if_modified heartbeat")
...
and restarted blender with blender --debug-python
. I found out that, on blender restart, the heartbeat is there, meaning the scheduled event is running every second. but the moment any project file is loaded, the heartbeat disappeared, with no error messages.
Then if I proceed to disable the add-on, messages come:
addon_utils.disable text_editor_reload_if_modified
reload_if_modified heartbeat
Traceback (most recent call last):
File "/home/richardn/.config/blender/4.3/scripts/addons/text_editor_reload_if_modified.py", line 54, in check_texts_every_second
if text.is_modified and text.reload_if_modified:
^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Text' object has no attribute 'reload_if_modified'
(Update: There is a typo on line 104, register
should be unregister
xd. But if I made the change, error message on disabling will change into "function not registered", which indicates a same problem: Python context is reset (update update: see below, all timers are cancelled) and register()
is not called on project load.)
Then finally I re-enable the add-on,
addon_utils.enable text_editor_reload_if_modified
reload_if_modified heartbeat
Info: Saved text "<path-to-my-open-script-file-in-my-project>"
reload_if_modified heartbeat
reload_if_modified heartbeat
...
root cause seems like this (back from 2014 lol)
Alright I made it. Change everything below draw_header()
into:
@bpy.app.handlers.persistent
def load_handler(dummy):
bpy.app.timers.register(check_texts_every_second)
def register():
# build UI once per plugin load
bpy.types.Text.reload_if_modified = bpy.props.BoolProperty(
name='Reload if Modified',
description=
'Automatically reload text file if it has changed',
default=False,
)
# tried `bpy.msgbus.subscribe_rna(key=bpy.data.texts.path_resolve("is_modified", False))`
# and didn't worked, therefore going to timer approach as depsgraph update won't be often enough
# maybe there is more clever way to do this
bpy.types.TEXT_HT_header.append(draw_header)
# register timer once per plugin load
bpy.app.timers.register(check_texts_every_second)
# loading a file cancels all timers, register timer once more per file load
bpy.app.handlers.load_post.append(load_handler)
def unregister():
del bpy.types.Text.reload_if_modified
bpy.types.TEXT_HT_header.remove(draw_header)
bpy.app.timers.unregister(check_texts_every_second)
This is very helpful, thank you!
I am new to Blender so I am not sure what is going on: This plugin has a minor minor problem of, it does not function (the "reload if modified" checkbox is present on the top right of the script area, but script never reloads.) after a Blender restart. I have to tick and re-tick the "enable" box in the add-ons list after a restart to restore the function. Other than this the plugin is working perfectly.