diff options
author | Juan Linietsky <reduzio@gmail.com> | 2015-08-23 20:15:56 -0300 |
---|---|---|
committer | Juan Linietsky <reduzio@gmail.com> | 2015-08-23 20:15:56 -0300 |
commit | 07e97414250827c3b930befa123a4bbd48d24861 (patch) | |
tree | 8ec9872421ad333d3a1150ee64db1d0d27bd4269 | |
parent | 9d185ccc30ad5fe7eb716390ca2e7f5c06574ce0 (diff) |
**WARNING BEFORE PULLING**
This push changes the binary and XML formats and bumps the major version to 2.0. As such, files saved in this version WILL NO LONGER WORK IN PREVIOUS VERSIONS. This compatibility breakage with older versions was required in order to properly provide project refactoring tools.
If I were you, unless you are brave, I would wait a week or two before pulling, in case of bugs :)
Summary of Changes
-New Filesystem dock, with filesystem & tree view modes.
-New refactoring tools, to change or fix dependencies.
-Quick search dialog, to quickly search any file
59 files changed, 2688 insertions, 396 deletions
diff --git a/core/error_list.h b/core/error_list.h index 124027172e..92c417154c 100644 --- a/core/error_list.h +++ b/core/error_list.h @@ -54,6 +54,7 @@ enum Error { ERR_FILE_CANT_READ, ERR_FILE_UNRECOGNIZED, // (15) ERR_FILE_CORRUPT, + ERR_FILE_MISSING_DEPENDENCIES, ERR_FILE_EOF, ERR_CANT_OPEN, ///< Can't open a resource/socket/file ERR_CANT_CREATE, diff --git a/core/global_constants.cpp b/core/global_constants.cpp index b8d113f67c..9fb45c672a 100644 --- a/core/global_constants.cpp +++ b/core/global_constants.cpp @@ -422,6 +422,7 @@ static _GlobalConstant _global_constants[]={ BIND_GLOBAL_CONSTANT( ERR_FILE_CANT_READ ), BIND_GLOBAL_CONSTANT( ERR_FILE_UNRECOGNIZED ), BIND_GLOBAL_CONSTANT( ERR_FILE_CORRUPT ), + BIND_GLOBAL_CONSTANT( ERR_FILE_MISSING_DEPENDENCIES), BIND_GLOBAL_CONSTANT( ERR_FILE_EOF ), BIND_GLOBAL_CONSTANT( ERR_CANT_OPEN ), ///< Can't open a resource/socket/file BIND_GLOBAL_CONSTANT( ERR_CANT_CREATE ), diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp index c6cf631de6..60bb8b658e 100644 --- a/core/io/resource_format_binary.cpp +++ b/core/io/resource_format_binary.cpp @@ -31,6 +31,7 @@ #include "globals.h" #include "io/file_access_compressed.h" #include "io/marshalls.h" +#include "os/dir_access.h" //#define print_bl(m_what) print_line(m_what) #define print_bl(m_what) @@ -99,7 +100,9 @@ enum { OBJECT_EMPTY=0, OBJECT_EXTERNAL_RESOURCE=1, OBJECT_INTERNAL_RESOURCE=2, - FORMAT_VERSION=0 + OBJECT_EXTERNAL_RESOURCE_INDEX=3, + FORMAT_VERSION=1, + FORMAT_VERSION_CAN_RENAME_DEPS=1 }; @@ -375,7 +378,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } break; case OBJECT_INTERNAL_RESOURCE: { uint32_t index=f->get_32(); - String path = res_path+"::"+itos(index); + String path = res_path+"::"+itos(index); RES res = ResourceLoader::load(path); if (res.is_null()) { WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); @@ -384,6 +387,7 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } break; case OBJECT_EXTERNAL_RESOURCE: { + //old file format, still around for compatibility String type = get_unicode_string(); String path = get_unicode_string(); @@ -394,6 +398,10 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { } + if (remaps.find(path)) { + path=remaps[path]; + } + RES res=ResourceLoader::load(path,type); if (res.is_null()) { @@ -402,6 +410,34 @@ Error ResourceInteractiveLoaderBinary::parse_variant(Variant& r_v) { r_v=res; } break; + case OBJECT_EXTERNAL_RESOURCE_INDEX: { + //new file format, just refers to an index in the external list + uint32_t erindex = f->get_32(); + + if (erindex>=external_resources.size()) { + WARN_PRINT("Broken external resource! (index out of size"); + r_v=Variant(); + } else { + + String type = external_resources[erindex].type; + String path = external_resources[erindex].path; + + if (path.find("://")==-1 && path.is_rel_path()) { + // path is relative to file being loaded, so convert to a resource path + path=Globals::get_singleton()->localize_path(res_path.get_base_dir().plus_file(path)); + + } + + RES res=ResourceLoader::load(path,type); + + if (res.is_null()) { + WARN_PRINT(String("Couldn't load resource: "+path).utf8().get_data()); + } + r_v=res; + } + + + } break; default: { ERR_FAIL_V(ERR_FILE_CORRUPT); @@ -628,17 +664,20 @@ Error ResourceInteractiveLoaderBinary::poll(){ if (s<external_resources.size()) { - RES res = ResourceLoader::load(external_resources[s].path,external_resources[s].type); + String path = external_resources[s].path; + if (remaps.has(path)) { + path=remaps[path]; + } + RES res = ResourceLoader::load(path,external_resources[s].type); if (res.is_null()) { if (!ResourceLoader::get_abort_on_missing_resources()) { - ResourceLoader::notify_load_error("Resource Not Found: "+external_resources[s].path); + ResourceLoader::notify_dependency_error(local_path,path,external_resources[s].type); } else { - - error=ERR_FILE_CORRUPT; - ERR_EXPLAIN("Can't load dependency: "+external_resources[s].path); + error=ERR_FILE_MISSING_DEPENDENCIES; + ERR_EXPLAIN("Can't load dependency: "+path); ERR_FAIL_V(error); } @@ -787,6 +826,27 @@ int ResourceInteractiveLoaderBinary::get_stage_count() const { return external_resources.size()+internal_resources.size(); } + +static void save_ustring(FileAccess* f,const String& p_string) { + + + CharString utf8 = p_string.utf8(); + f->store_32(utf8.length()+1); + f->store_buffer((const uint8_t*)utf8.get_data(),utf8.length()+1); +} + + +static String get_ustring(FileAccess *f) { + + int len = f->get_32(); + Vector<char> str_buf; + str_buf.resize(len); + f->get_buffer((uint8_t*)&str_buf[0],len); + String s; + s.parse_utf8(&str_buf[0]); + return s; +} + String ResourceInteractiveLoaderBinary::get_unicode_string() { int len = f->get_32(); @@ -801,7 +861,7 @@ String ResourceInteractiveLoaderBinary::get_unicode_string() { -void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies) { +void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<String> *p_dependencies,bool p_add_types) { open(p_f); if (error) @@ -814,6 +874,10 @@ void ResourceInteractiveLoaderBinary::get_dependencies(FileAccess *p_f,List<Stri dep=ResourceLoader::guess_full_filename(dep,external_resources[i].type); } + if (p_add_types && external_resources[i].type!=String()) { + dep+="::"+external_resources[i].type; + } + p_dependencies->push_back(dep); } @@ -866,7 +930,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { print_bl("minor: "+itos(ver_minor)); print_bl("format: "+itos(ver_format)); - if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR) { + if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) { f->close(); ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path); @@ -903,6 +967,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { } //see if the exporter has different set of external resources for more efficient loading + /* String preload_depts = "deps/"+res_path.md5_text(); if (Globals::get_singleton()->has(preload_depts)) { external_resources.clear(); @@ -913,7 +978,7 @@ void ResourceInteractiveLoaderBinary::open(FileAccess *p_f) { external_resources[i].path=depts.get_name(i); } print_line(res_path+" - EXTERNAL RESOURCES: "+itos(external_resources.size())); - } + }*/ print_bl("ext resources: "+itos(ext_resources_size)); uint32_t int_resources_size=f->get_32(); @@ -973,7 +1038,7 @@ String ResourceInteractiveLoaderBinary::recognize(FileAccess *p_f) { uint32_t ver_minor=f->get_32(); uint32_t ver_format=f->get_32(); - if (ver_format<FORMAT_VERSION || ver_major>VERSION_MAJOR) { + if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) { f->close(); return ""; @@ -1000,8 +1065,10 @@ ResourceInteractiveLoaderBinary::~ResourceInteractiveLoaderBinary() { } -Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path) { +Ref<ResourceInteractiveLoader> ResourceFormatLoaderBinary::load_interactive(const String &p_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -1114,7 +1181,7 @@ Error ResourceFormatLoaderBinary::load_import_metadata(const String &p_path, Ref } -void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) { FileAccess *f = FileAccess::open(p_path,FileAccess::READ); ERR_FAIL_COND(!f); @@ -1123,7 +1190,217 @@ void ResourceFormatLoaderBinary::get_dependencies(const String& p_path,List<Stri ria->local_path=Globals::get_singleton()->localize_path(p_path); ria->res_path=ria->local_path; // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); - ria->get_dependencies(f,p_dependencies); + ria->get_dependencies(f,p_dependencies,p_add_types); +} + +Error ResourceFormatLoaderBinary::rename_dependencies(const String &p_path,const Map<String,String>& p_map) { + + +// Error error=OK; + + + FileAccess *f=FileAccess::open(p_path,FileAccess::READ); + ERR_FAIL_COND_V(!f,ERR_CANT_OPEN); + + FileAccess* fw=NULL;//=FileAccess::open(p_path+".depren"); + + String local_path=p_path.get_base_dir(); + + uint8_t header[4]; + f->get_buffer(header,4); + if (header[0]=='R' && header[1]=='S' && header[2]=='C' && header[3]=='C') { + //compressed + FileAccessCompressed *fac = memnew( FileAccessCompressed ); + fac->open_after_magic(f); + f=fac; + + FileAccessCompressed *facw = memnew( FileAccessCompressed ); + facw->configure("RSCC"); + Error err = facw->_open(p_path+".depren",FileAccess::WRITE); + if (err) { + memdelete(fac); + memdelete(facw); + ERR_FAIL_COND_V(err,ERR_FILE_CORRUPT); + } + + fw=facw; + + + } else if (header[0]!='R' || header[1]!='S' || header[2]!='R' || header[3]!='C') { + //not normal + + //error=ERR_FILE_UNRECOGNIZED; + memdelete(f); + ERR_EXPLAIN("Unrecognized binary resource file: "+local_path); + ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + } else { + fw = FileAccess::open(p_path+".depren",FileAccess::WRITE); + if (!fw) { + memdelete(f); + } + ERR_FAIL_COND_V(!fw,ERR_CANT_CREATE); + } + + bool big_endian = f->get_32(); +#ifdef BIG_ENDIAN_ENABLED + endian_swap = !big_endian; +#else + bool endian_swap = big_endian; +#endif + + bool use_real64 = f->get_32(); + + f->set_endian_swap(big_endian!=0); //read big endian if saved as big endian + fw->store_32(endian_swap); + fw->set_endian_swap(big_endian!=0); + fw->store_32(use_real64); //use real64 + + uint32_t ver_major=f->get_32(); + uint32_t ver_minor=f->get_32(); + uint32_t ver_format=f->get_32(); + + if (ver_format<FORMAT_VERSION_CAN_RENAME_DEPS) { + + memdelete(f); + memdelete(fw); + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + da->remove(p_path+".depren"); + memdelete(da); + //fuck it, use the old approach; + + WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data()); + + Error err; + f = FileAccess::open(p_path,FileAccess::READ,&err); + if (err!=OK) { + ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderBinary> ria = memnew( ResourceInteractiveLoaderBinary ); + ria->local_path=Globals::get_singleton()->localize_path(p_path); + ria->res_path=ria->local_path; + ria->remaps=p_map; + // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); + ria->open(f); + + err = ria->poll(); + + while(err==OK) { + err=ria->poll(); + } + + ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT); + RES res = ria->get_resource(); + ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT); + + return ResourceFormatSaverBinary::singleton->save(p_path,res); + } + + if (ver_format>FORMAT_VERSION || ver_major>VERSION_MAJOR) { + + memdelete(f); + memdelete(fw); + ERR_EXPLAIN("File Format '"+itos(FORMAT_VERSION)+"."+itos(ver_major)+"."+itos(ver_minor)+"' is too new! Please upgrade to a a new engine version: "+local_path); + ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + + } + + fw->store_32( VERSION_MAJOR ); //current version + fw->store_32( VERSION_MINOR ); + fw->store_32( FORMAT_VERSION ); + + save_ustring(fw,get_ustring(f)); //type + + + size_t md_ofs = f->get_pos(); + size_t importmd_ofs = f->get_64(); + fw->store_64(0); //metadata offset + + for(int i=0;i<14;i++) { + fw->store_32(0); + f->get_32(); + } + + //string table + uint32_t string_table_size=f->get_32(); + + fw->store_32(string_table_size); + + for(uint32_t i=0;i<string_table_size;i++) { + + String s = get_ustring(f); + save_ustring(fw,s); + } + + //external resources + uint32_t ext_resources_size=f->get_32(); + fw->store_32(ext_resources_size); + for(uint32_t i=0;i<ext_resources_size;i++) { + + String type = get_ustring(f); + String path = get_ustring(f); + + bool relative=false; + if (!path.begins_with("res://")) { + path=local_path.plus_file(path).simplify_path(); + relative=true; + } + + + if (p_map.has(path)) { + String np=p_map[path]; + path=np; + } + + if (relative) { + //restore relative + path=local_path.path_to_file(path); + } + + save_ustring(fw,type); + save_ustring(fw,path); + } + + int64_t size_diff = (int64_t)fw->get_pos() - (int64_t)f->get_pos(); + + //internal resources + uint32_t int_resources_size=f->get_32(); + fw->store_32(int_resources_size); + + for(uint32_t i=0;i<int_resources_size;i++) { + + + String path=get_ustring(f); + uint64_t offset=f->get_64(); + save_ustring(fw,path); + fw->store_64(offset+size_diff); + } + + //rest of file + uint8_t b = f->get_8(); + while(!f->eof_reached()) { + fw->store_8(b); + b = f->get_8(); + } + + bool all_ok = fw->get_error()==OK; + + fw->seek(md_ofs); + fw->store_64(importmd_ofs+size_diff); + + + memdelete(f); + memdelete(fw); + + if (!all_ok) { + return ERR_CANT_CREATE; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + da->remove(p_path); + da->rename(p_path+".depren",p_path); + memdelete(da); + return OK; } @@ -1433,10 +1710,8 @@ void ResourceFormatSaverBinaryInstance::write_variant(const Variant& p_property, } if (res->get_path().length() && res->get_path().find("::")==-1) { - f->store_32(OBJECT_EXTERNAL_RESOURCE); - save_unicode_string(res->get_save_type()); - String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); - save_unicode_string(path); + f->store_32(OBJECT_EXTERNAL_RESOURCE_INDEX); + f->store_32(external_resources[res]); } else { if (!resource_set.has(res)) { @@ -1594,11 +1869,12 @@ void ResourceFormatSaverBinaryInstance::_find_resources(const Variant& p_variant RES res = p_variant.operator RefPtr(); - if (res.is_null()) + if (res.is_null() || external_resources.has(res)) return; if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { - external_resources.insert(res); + int idx = external_resources.size(); + external_resources[res]=idx; return; } @@ -1842,10 +2118,18 @@ Error ResourceFormatSaverBinaryInstance::save(const String &p_path,const RES& p_ // save external resource table f->store_32(external_resources.size()); //amount of external resources - for(Set<RES>::Element *E=external_resources.front();E;E=E->next()) { + Vector<RES> save_order; + save_order.resize(external_resources.size()); + + for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) { + save_order[E->get()]=E->key(); + } - save_unicode_string(E->get()->get_save_type()); - String path = E->get()->get_path(); + for(int i=0;i<save_order.size();i++) { + + save_unicode_string(save_order[i]->get_save_type()); + String path = save_order[i]->get_path(); + path=relative_paths?local_path.path_to_file(path):path; save_unicode_string(path); } // save internal resource table @@ -1995,3 +2279,9 @@ void ResourceFormatSaverBinary::get_recognized_extensions(const RES& p_resource, } +ResourceFormatSaverBinary* ResourceFormatSaverBinary::singleton=NULL; + +ResourceFormatSaverBinary::ResourceFormatSaverBinary() { + + singleton=this; +} diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h index da415d97a5..8bf20bc574 100644 --- a/core/io/resource_format_binary.h +++ b/core/io/resource_format_binary.h @@ -71,6 +71,7 @@ class ResourceInteractiveLoaderBinary : public ResourceInteractiveLoader { String get_unicode_string(); void _advance_padding(uint32_t p_len); + Map<String,String> remaps; Error error; int stage; @@ -88,9 +89,10 @@ public: virtual int get_stage() const; virtual int get_stage_count() const; + void set_remaps(const Map<String,String>& p_remaps) { remaps=p_remaps; } void open(FileAccess *p_f); String recognize(FileAccess *p_f); - void get_dependencies(FileAccess *p_f,List<String> *p_dependencies); + void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); ResourceInteractiveLoaderBinary(); @@ -101,13 +103,14 @@ public: class ResourceFormatLoaderBinary : public ResourceFormatLoader { public: - virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path); + virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL); virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; - virtual void get_dependencies(const String& p_path,List<String> *p_dependencies); + virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false); virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const; + virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map); @@ -134,7 +137,7 @@ class ResourceFormatSaverBinaryInstance { Vector<StringName> strings; - Set<RES> external_resources; + Map<RES,int> external_resources; List<RES> saved_resources; @@ -174,11 +177,12 @@ class ResourceFormatSaverBinary : public ResourceFormatSaver { public: + static ResourceFormatSaverBinary* singleton; virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0); virtual bool recognize(const RES& p_resource) const; virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const; - + ResourceFormatSaverBinary(); }; diff --git a/core/io/resource_format_xml.cpp b/core/io/resource_format_xml.cpp index b744cbf967..9019b4e3c0 100644 --- a/core/io/resource_format_xml.cpp +++ b/core/io/resource_format_xml.cpp @@ -29,10 +29,10 @@ #include "resource_format_xml.h" #include "globals.h" #include "version.h" +#include "os/dir_access.h" - -ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit,bool p_printerr) { +ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool *r_exit, bool p_printerr, List<String> *r_order) { while(get_char()!='<' && !f->eof_reached()) {} @@ -107,7 +107,11 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool if (r_value.size()) { r_value.push_back(0); - tag.args[name].parse_utf8(r_value.get_data()); + String str; + str.parse_utf8(r_value.get_data()); + tag.args[name]=str; + if (r_order) + r_order->push_back(name); } break; @@ -119,7 +123,11 @@ ResourceInteractiveLoaderXML::Tag* ResourceInteractiveLoaderXML::parse_tag(bool } else if (reading_value && r_value.size()) { r_value.push_back(0); - tag.args[name].parse_utf8(r_value.get_data()); + String str; + str.parse_utf8(r_value.get_data()); + tag.args[name]=str; + if (r_order) + r_order->push_back(name); name=""; r_value.clear(); reading_value=false; @@ -463,6 +471,10 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) } + if (remaps.has(path)) { + path=remaps[path]; + } + //take advantage of the resource loader cache. The resource is cached on it, even if RES res=ResourceLoader::load(path,hint); @@ -473,10 +485,31 @@ Error ResourceInteractiveLoaderXML::parse_property(Variant& r_v, String &r_name) } r_v=res.get_ref_ptr(); + } else if (tag->args.has("external")) { + + int index = tag->args["external"].to_int(); + if (ext_resources.has(index)) { + String path=ext_resources[index].path; + String type=ext_resources[index].type; + + //take advantage of the resource loader cache. The resource is cached on it, even if + RES res=ResourceLoader::load(path,type); + + if (res.is_null()) { + + WARN_PRINT(String("Couldn't load externalresource: "+path).ascii().get_data()); + } + + r_v=res.get_ref_ptr(); + } else { + WARN_PRINT(String("Invalid external resource index: "+itos(index)).ascii().get_data()); + + } } + Error err=goto_end_of_tag(); if (err) { ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": Error closing <resource> tag."); @@ -1364,32 +1397,6 @@ Error ResourceInteractiveLoaderXML::poll() { if (error!=OK) return error; - if (ext_resources.size()) { - - error=ERR_FILE_CORRUPT; - String path=ext_resources.front()->get(); - - RES res = ResourceLoader::load(path); - - if (res.is_null()) { - - if (ResourceLoader::get_abort_on_missing_resources()) { - ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": editor exported nonexistent resource at: "+path); - ERR_FAIL_V(error); - } else { - ResourceLoader::notify_load_error("Resource Not Found: "+path); - } - } else { - - resource_cache.push_back(res); - } - - error=OK; - ext_resources.pop_front(); - resource_current++; - return error; - } - bool exit; Tag *tag = parse_tag(&exit); @@ -1413,12 +1420,13 @@ Error ResourceInteractiveLoaderXML::poll() { ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> missing 'path' field."); ERR_FAIL_COND_V(!tag->args.has("path"),ERR_FILE_CORRUPT); - String type; + String type="Resource"; if (tag->args.has("type")) type=tag->args["type"]; String path = tag->args["path"]; + ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> can't use a local path, this is a bug?."); ERR_FAIL_COND_V(path.begins_with("local://"),ERR_FILE_CORRUPT); @@ -1427,6 +1435,9 @@ Error ResourceInteractiveLoaderXML::poll() { path=Globals::get_singleton()->localize_path(local_path.get_base_dir().plus_file(path)); } + if (remaps.has(path)) { + path=remaps[path]; + } RES res = ResourceLoader::load(path,type); @@ -1436,13 +1447,21 @@ Error ResourceInteractiveLoaderXML::poll() { ERR_EXPLAIN(local_path+":"+itos(get_current_line())+": <ext_resource> referenced nonexistent resource at: "+path); ERR_FAIL_V(error); } else { - ResourceLoader::notify_load_error("Resource Not Found: "+path); + ResourceLoader::notify_dependency_error(local_path,path,type); } } else { resource_cache.push_back(res); } + if (tag->args.has("index")) { + ExtResource er; + er.path=path; + er.type=type; + ext_resources[tag->args["index"].to_int()]=er; + } + + Error err = close_tag("ext_resource"); if (err) return error; @@ -1566,7 +1585,7 @@ int ResourceInteractiveLoaderXML::get_stage() const { } int ResourceInteractiveLoaderXML::get_stage_count() const { - return resources_total+ext_resources.size(); + return resources_total;//+ext_resources; } ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() { @@ -1574,7 +1593,7 @@ ResourceInteractiveLoaderXML::~ResourceInteractiveLoaderXML() { memdelete(f); } -void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies) { +void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> *p_dependencies,bool p_add_types) { open(f); @@ -1617,6 +1636,10 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> * path = ResourceLoader::guess_full_filename(path,type); } + if (p_add_types && tag->args.has("type")) { + path+="::"+tag->args["type"]; + } + p_dependencies->push_back(path); Error err = close_tag("ext_resource"); @@ -1628,6 +1651,167 @@ void ResourceInteractiveLoaderXML::get_dependencies(FileAccess *f,List<String> * } +Error ResourceInteractiveLoaderXML::rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map) { + + open(p_f); + ERR_FAIL_COND_V(error!=OK,error); + + //FileAccess + + bool old_format=false; + + FileAccess *fw = NULL; + + String base_path=local_path.get_base_dir(); + + while(true) { + bool exit; + List<String> order; + + Tag *tag = parse_tag(&exit,true,&order); + + bool done=false; + + if (!tag) { + if (fw) { + memdelete(fw); + } + error=ERR_FILE_CORRUPT; + ERR_FAIL_COND_V(!exit,error); + error=ERR_FILE_EOF; + + return error; + } + + if (tag->name=="ext_resource") { + + if (!tag->args.has("index") || !tag->args.has("path") || !tag->args.has("type")) { + old_format=true; + break; + } + + if (!fw) { + + fw=FileAccess::open(p_path+".depren",FileAccess::WRITE); + fw->store_line("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); //no escape + fw->store_line("<resource_file type=\""+resource_type+"\" subresource_count=\""+itos(resources_total)+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\">"); + + } + + String path = tag->args["path"]; + String index = tag->args["index"]; + String type = tag->args["type"]; + + + bool relative=false; + if (!path.begins_with("res://")) { + path=base_path.plus_file(path).simplify_path(); + relative=true; + } + + + if (p_map.has(path)) { + String np=p_map[path]; + path=np; + } + + if (relative) { + //restore relative + path=base_path.path_to_file(path); + } + + tag->args["path"]=path; + tag->args["index"]=index; + tag->args["type"]=type; + + } else { + + done=true; + } + + String tagt="\t<"; + if (exit) + tagt+="/"; + tagt+=tag->name; + + for(List<String>::Element *E=order.front();E;E=E->next()) { + tagt+=" "+E->get()+"=\""+tag->args[E->get()]+"\""; + } + tagt+=">"; + fw->store_line(tagt); + if (done) + break; + close_tag("ext_resource"); + fw->store_line("\t</ext_resource>"); + + } + + + if (old_format) { + if (fw) + memdelete(fw); + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + da->remove(p_path+".depren"); + memdelete(da); + //fuck it, use the old approach; + + WARN_PRINT(("This file is old, so it can't refactor dependencies, opening and resaving: "+p_path).utf8().get_data()); + + Error err; + FileAccess *f2 = FileAccess::open(p_path,FileAccess::READ,&err); + if (err!=OK) { + ERR_FAIL_COND_V(err!=OK,ERR_FILE_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML ); + ria->local_path=Globals::get_singleton()->localize_path(p_path); + ria->res_path=ria->local_path; + ria->remaps=p_map; + // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); + ria->open(f2); + + err = ria->poll(); + + while(err==OK) { + err=ria->poll(); + } + + ERR_FAIL_COND_V(err!=ERR_FILE_EOF,ERR_FILE_CORRUPT); + RES res = ria->get_resource(); + ERR_FAIL_COND_V(!res.is_valid(),ERR_FILE_CORRUPT); + + return ResourceFormatSaverXML::singleton->save(p_path,res); + } + + if (!fw) { + + return OK; //nothing to rename, do nothing + } + + uint8_t c=f->get_8(); + while(!f->eof_reached()) { + fw->store_8(c); + c=f->get_8(); + } + + bool all_ok = fw->get_error()==OK; + + memdelete(fw); + + if (!all_ok) { + return ERR_CANT_CREATE; + } + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + da->remove(p_path); + da->rename(p_path+".depren",p_path); + memdelete(da); + + return OK; + +} + void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { @@ -1686,6 +1870,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { } + /* String preload_depts = "deps/"+local_path.md5_text(); if (Globals::get_singleton()->has(preload_depts)) { ext_resources.clear(); @@ -1697,7 +1882,7 @@ void ResourceInteractiveLoaderXML::open(FileAccess *p_f) { } print_line(local_path+" - EXTERNAL RESOURCES: "+itos(ext_resources.size())); } - +*/ } @@ -1730,7 +1915,10 @@ String ResourceInteractiveLoaderXML::recognize(FileAccess *p_f) { ///////////////////// -Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path) { +Ref<ResourceInteractiveLoader> ResourceFormatLoaderXML::load_interactive(const String &p_path, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -1816,7 +2004,7 @@ String ResourceFormatLoaderXML::get_resource_type(const String &p_path) const{ } -void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types) { FileAccess *f = FileAccess::open(p_path,FileAccess::READ); if (!f) { @@ -1828,11 +2016,27 @@ void ResourceFormatLoaderXML::get_dependencies(const String& p_path,List<String> ria->local_path=Globals::get_singleton()->localize_path(p_path); ria->res_path=ria->local_path; // ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); - ria->get_dependencies(f,p_dependencies); + ria->get_dependencies(f,p_dependencies,p_add_types); + +} + +Error ResourceFormatLoaderXML::rename_dependencies(const String &p_path,const Map<String,String>& p_map) { + + FileAccess *f = FileAccess::open(p_path,FileAccess::READ); + if (!f) { + ERR_FAIL_V(ERR_CANT_OPEN); + } + + Ref<ResourceInteractiveLoaderXML> ria = memnew( ResourceInteractiveLoaderXML ); + ria->local_path=Globals::get_singleton()->localize_path(p_path); + ria->res_path=ria->local_path; +// ria->set_local_path( Globals::get_singleton()->localize_path(p_path) ); + return ria->rename_dependencies(f,p_path,p_map); } + /****************************************************************************************/ /****************************************************************************************/ /****************************************************************************************/ @@ -2024,20 +2228,26 @@ void ResourceFormatSaverXMLInstance::write_property(const String& p_name,const V return; // don't save it } - params="resource_type=\""+res->get_save_type()+"\""; + if (external_resources.has(res)) { - if (res->get_path().length() && res->get_path().find("::")==-1) { - //external resource - String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); - escape(path); - params+=" path=\""+path+"\""; + params="external=\""+itos(external_resources[res])+"\""; } else { + params="resource_type=\""+res->get_save_type()+"\""; - //internal resource - ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); - ERR_FAIL_COND(!resource_set.has(res)); - params+=" path=\"local://"+itos(res->get_subindex())+"\""; + if (res->get_path().length() && res->get_path().find("::")==-1) { + //external resource + String path=relative_paths?local_path.path_to_file(res->get_path()):res->get_path(); + escape(path); + params+=" path=\""+path+"\""; + } else { + + //internal resource + ERR_EXPLAIN("Resource was not pre cached for the resource section, bug?"); + ERR_FAIL_COND(!resource_set.has(res)); + + params+=" path=\"local://"+itos(res->get_subindex())+"\""; + } } } break; @@ -2441,11 +2651,12 @@ void ResourceFormatSaverXMLInstance::_find_resources(const Variant& p_variant,bo RES res = p_variant.operator RefPtr(); - if (res.is_null()) + if (res.is_null() || external_resources.has(res)) return; if (!p_main && (!bundle_resources ) && res->get_path().length() && res->get_path().find("::") == -1 ) { - external_resources.push_back(res); + int index = external_resources.size(); + external_resources[res]=index; return; } @@ -2533,12 +2744,12 @@ Error ResourceFormatSaverXMLInstance::save(const String &p_path,const RES& p_res enter_tag("resource_file","type=\""+p_resource->get_type()+"\" subresource_count=\""+itos(saved_resources.size()+external_resources.size())+"\" version=\""+itos(VERSION_MAJOR)+"."+itos(VERSION_MINOR)+"\" version_name=\""+VERSION_FULL_NAME+"\""); write_string("\n",false); - for(List<RES>::Element *E=external_resources.front();E;E=E->next()) { + for(Map<RES,int>::Element *E=external_resources.front();E;E=E->next()) { write_tabs(); - String p = E->get()->get_path(); + String p = E->key()->get_path(); - enter_tag("ext_resource","path=\""+p+"\" type=\""+E->get()->get_save_type()+"\""); //bundled + enter_tag("ext_resource","path=\""+p+"\" type=\""+E->key()->get_save_type()+"\" index=\""+itos(E->get())+"\""); //bundled exit_tag("ext_resource"); //bundled write_string("\n",false); } @@ -2667,3 +2878,8 @@ void ResourceFormatSaverXML::get_recognized_extensions(const RES& p_resource,Lis } } + +ResourceFormatSaverXML* ResourceFormatSaverXML::singleton=NULL; +ResourceFormatSaverXML::ResourceFormatSaverXML() { + singleton=this; +} diff --git a/core/io/resource_format_xml.h b/core/io/resource_format_xml.h index d5ba9eb800..77987c6a5b 100644 --- a/core/io/resource_format_xml.h +++ b/core/io/resource_format_xml.h @@ -46,13 +46,21 @@ class ResourceInteractiveLoaderXML : public ResourceInteractiveLoader { String name; HashMap<String,String> args; + }; _FORCE_INLINE_ Error _parse_array_element(Vector<char> &buff,bool p_number_only,FileAccess *f,bool *end); + struct ExtResource { + String path; + String type; + }; + - List<StringName> ext_resources; + Map<String,String> remaps; + + Map<int,ExtResource> ext_resources; int resources_total; int resource_current; @@ -66,7 +74,7 @@ friend class ResourceFormatLoaderXML; List<Tag> tag_stack; List<RES> resource_cache; - Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true); + Tag* parse_tag(bool* r_exit=NULL,bool p_printerr=true,List<String> *r_order=NULL); Error close_tag(const String& p_name); _FORCE_INLINE_ void unquote(String& p_str); Error goto_end_of_tag(); @@ -87,7 +95,8 @@ public: void open(FileAccess *p_f); String recognize(FileAccess *p_f); - void get_dependencies(FileAccess *p_f,List<String> *p_dependencies); + void get_dependencies(FileAccess *p_f, List<String> *p_dependencies, bool p_add_types); + Error rename_dependencies(FileAccess *p_f, const String &p_path,const Map<String,String>& p_map); ~ResourceInteractiveLoaderXML(); @@ -97,12 +106,13 @@ public: class ResourceFormatLoaderXML : public ResourceFormatLoader { public: - virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path); + virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL); virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const; virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; - virtual void get_dependencies(const String& p_path,List<String> *p_dependencies); + virtual void get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types=false); + virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map); }; @@ -125,7 +135,7 @@ class ResourceFormatSaverXMLInstance { int depth; Set<RES> resource_set; List<RES> saved_resources; - List<RES> external_resources; + Map<RES,int> external_resources; void enter_tag(const char* p_tag,const String& p_args=String()); void exit_tag(const char* p_tag); @@ -148,11 +158,12 @@ public: class ResourceFormatSaverXML : public ResourceFormatSaver { public: + static ResourceFormatSaverXML* singleton; virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0); virtual bool recognize(const RES& p_resource) const; virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const; - + ResourceFormatSaverXML(); }; diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp index 22d89840ae..1e014480f4 100644 --- a/core/io/resource_loader.cpp +++ b/core/io/resource_loader.cpp @@ -103,10 +103,10 @@ public: -Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path) { +Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const String &p_path, Error *r_error) { //either this - Ref<Resource> res = load(p_path); + Ref<Resource> res = load(p_path,p_path,r_error); if (res.is_null()) return Ref<ResourceInteractiveLoader>(); @@ -115,12 +115,13 @@ Ref<ResourceInteractiveLoader> ResourceFormatLoader::load_interactive(const Stri return ril; } -RES ResourceFormatLoader::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoader::load(const String &p_path, const String& p_original_path, Error *r_error) { + String path=p_path; //or this must be implemented - Ref<ResourceInteractiveLoader> ril = load_interactive(p_path); + Ref<ResourceInteractiveLoader> ril = load_interactive(p_path,r_error); if (!ril.is_valid()) return RES(); ril->set_local_path(p_original_path); @@ -130,9 +131,14 @@ RES ResourceFormatLoader::load(const String &p_path,const String& p_original_pat Error err = ril->poll(); if (err==ERR_FILE_EOF) { + if (r_error) + *r_error=OK; return ril->get_resource(); } + if (r_error) + *r_error=err; + ERR_FAIL_COND_V(err!=OK,RES()); } @@ -140,7 +146,7 @@ RES ResourceFormatLoader::load(const String &p_path,const String& p_original_pat } -void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceFormatLoader::get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types) { //do nothing by default } @@ -149,7 +155,10 @@ void ResourceFormatLoader::get_dependencies(const String& p_path,List<String> *p /////////////////////////////////// -RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_no_cache) { +RES ResourceLoader::load(const String &p_path, const String& p_type_hint, bool p_no_cache, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) @@ -183,7 +192,7 @@ RES ResourceLoader::load(const String &p_path,const String& p_type_hint,bool p_n if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) continue; found=true; - RES res = loader[i]->load(remapped_path,local_path); + RES res = loader[i]->load(remapped_path,local_path,r_error); if (res.is_null()) continue; if (!p_no_cache) @@ -289,9 +298,11 @@ String ResourceLoader::find_complete_path(const String& p_path,const String& p_t return local_path; } -Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache) { +Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_path,const String& p_type_hint,bool p_no_cache,Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; String local_path; if (p_path.is_rel_path()) @@ -327,7 +338,7 @@ Ref<ResourceInteractiveLoader> ResourceLoader::load_interactive(const String &p_ if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) continue; found=true; - Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path); + Ref<ResourceInteractiveLoader> ril = loader[i]->load_interactive(remapped_path,r_error); if (ril.is_null()) continue; if (!p_no_cache) @@ -352,7 +363,32 @@ void ResourceLoader::add_resource_format_loader(ResourceFormatLoader *p_format_l loader[loader_count++]=p_format_loader; } -void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_dependencies) { +void ResourceLoader::get_dependencies(const String& p_path, List<String> *p_dependencies, bool p_add_types) { + + + String local_path; + if (p_path.is_rel_path()) + local_path="res://"+p_path; + else + local_path = Globals::get_singleton()->localize_path(p_path); + + String remapped_path = PathRemap::get_singleton()->get_remap(local_path); + + String extension=remapped_path.extension(); + + for (int i=0;i<loader_count;i++) { + + if (!loader[i]->recognize(extension)) + continue; + //if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) + // continue; + + loader[i]->get_dependencies(remapped_path,p_dependencies,p_add_types); + + } +} + +Error ResourceLoader::rename_dependencies(const String &p_path,const Map<String,String>& p_map) { String local_path; @@ -372,11 +408,15 @@ void ResourceLoader::get_dependencies(const String& p_path,List<String> *p_depen //if (p_type_hint!="" && !loader[i]->handles_type(p_type_hint)) // continue; - loader[i]->get_dependencies(remapped_path,p_dependencies); + return loader[i]->rename_dependencies(p_path,p_map); } + + return OK; // ?? + } + String ResourceLoader::guess_full_filename(const String &p_path,const String& p_type) { String local_path; @@ -414,6 +454,9 @@ String ResourceLoader::get_resource_type(const String &p_path) { ResourceLoadErrorNotify ResourceLoader::err_notify=NULL; void *ResourceLoader::err_notify_ud=NULL; +DependencyErrorNotify ResourceLoader::dep_err_notify=NULL; +void *ResourceLoader::dep_err_notify_ud=NULL; + bool ResourceLoader::abort_on_missing_resource=true; bool ResourceLoader::timestamp_on_load=false; diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h index d25727f19f..00a05dcb43 100644 --- a/core/io/resource_loader.h +++ b/core/io/resource_loader.h @@ -57,21 +57,23 @@ public: class ResourceFormatLoader { public: - virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path); - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,Error *r_error=NULL); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const=0; virtual void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions) const; bool recognize(const String& p_extension) const; virtual bool handles_type(const String& p_type) const=0; virtual String get_resource_type(const String &p_path) const=0; - virtual void get_dependencies(const String& p_path,List<String> *p_dependencies); + virtual void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false); virtual Error load_import_metadata(const String &p_path, Ref<ResourceImportMetadata>& r_var) const { return ERR_UNAVAILABLE; } + virtual Error rename_dependencies(const String &p_path,const Map<String,String>& p_map) { return OK; } virtual ~ResourceFormatLoader() {} }; typedef void (*ResourceLoadErrorNotify)(void *p_ud,const String& p_text); +typedef void (*DependencyErrorNotify)(void *p_ud,const String& p_loading,const String& p_which,const String& p_type); class ResourceLoader { @@ -86,6 +88,8 @@ class ResourceLoader { static void* err_notify_ud; static ResourceLoadErrorNotify err_notify; + static void* dep_err_notify_ud; + static DependencyErrorNotify dep_err_notify; static bool abort_on_missing_resource; static String find_complete_path(const String& p_path,const String& p_type); @@ -93,14 +97,15 @@ public: - static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false); - static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false); + static Ref<ResourceInteractiveLoader> load_interactive(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL); + static RES load(const String &p_path,const String& p_type_hint="",bool p_no_cache=false,Error *r_error=NULL); static Ref<ResourceImportMetadata> load_import_metadata(const String &p_path); static void get_recognized_extensions_for_type(const String& p_type,List<String> *p_extensions); static void add_resource_format_loader(ResourceFormatLoader *p_format_loader); static String get_resource_type(const String &p_path); - static void get_dependencies(const String& p_path,List<String> *p_dependencies); + static void get_dependencies(const String& p_path,List<String> *p_dependencies,bool p_add_types=false); + static Error rename_dependencies(const String &p_path,const Map<String,String>& p_map); static String guess_full_filename(const String &p_path,const String& p_type); @@ -108,6 +113,11 @@ public: static void notify_load_error(const String& p_err) { if (err_notify) err_notify(err_notify_ud,p_err); } static void set_error_notify_func(void* p_ud,ResourceLoadErrorNotify p_err_notify) { err_notify=p_err_notify; err_notify_ud=p_ud;} + + static void notify_dependency_error(const String& p_path,const String& p_dependency,const String& p_type) { if (dep_err_notify) dep_err_notify(dep_err_notify_ud,p_path,p_dependency,p_type); } + static void set_dependency_error_notify_func(void* p_ud,DependencyErrorNotify p_err_notify) { dep_err_notify=p_err_notify; dep_err_notify_ud=p_ud;} + + static void set_abort_on_missing_resources(bool p_abort) { abort_on_missing_resource=p_abort; } static bool get_abort_on_missing_resources() { return abort_on_missing_resource; } }; diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h index 05cbe7f98e..8382b65290 100644 --- a/core/io/resource_saver.h +++ b/core/io/resource_saver.h @@ -46,7 +46,7 @@ public: virtual Error save(const String &p_path,const RES& p_resource,uint32_t p_flags=0)=0; virtual bool recognize(const RES& p_resource) const=0; virtual void get_recognized_extensions(const RES& p_resource,List<String> *p_extensions) const=0; - + virtual ~ResourceFormatSaver() {} }; diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp index c32b25c407..020d168208 100644 --- a/core/io/translation_loader_po.cpp +++ b/core/io/translation_loader_po.cpp @@ -30,7 +30,10 @@ #include "os/file_access.h" #include "translation.h" -RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path) { +RES TranslationLoaderPO::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_CANT_OPEN; FileAccess *f=FileAccess::open(p_path,FileAccess::READ); ERR_FAIL_COND_V(!f,RES()); @@ -49,6 +52,8 @@ RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path String msg_id; String msg_str; String config; + if (r_error) + *r_error=ERR_FILE_CORRUPT; Ref<Translation> translation = Ref<Translation>( memnew( Translation )); int line = 1; @@ -174,6 +179,8 @@ RES TranslationLoaderPO::load(const String &p_path,const String& p_original_path } } + if (r_error) + *r_error=OK; return translation; diff --git a/core/io/translation_loader_po.h b/core/io/translation_loader_po.h index 9d8ad97a29..e07ae15e28 100644 --- a/core/io/translation_loader_po.h +++ b/core/io/translation_loader_po.h @@ -34,7 +34,7 @@ class TranslationLoaderPO : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/chibi/event_stream_chibi.cpp b/drivers/chibi/event_stream_chibi.cpp index e87e0a9aaa..ecb5c3f22b 100644 --- a/drivers/chibi/event_stream_chibi.cpp +++ b/drivers/chibi/event_stream_chibi.cpp @@ -779,8 +779,10 @@ EventStreamChibi::EventStreamChibi() { -RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderChibi::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; String el = p_path.extension().to_lower(); CPFileAccessWrapperImpl f; @@ -791,6 +793,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_IT loader(&f); CPLoader::Error err = loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; return esc; @@ -800,6 +804,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_XM loader(&f); CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; return esc; } else if (el=="s3m") { @@ -808,6 +814,9 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_S3M loader(&f); CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; + return esc; } else if (el=="mod") { @@ -816,6 +825,8 @@ RES ResourceFormatLoaderChibi::load(const String &p_path,const String& p_origina CPLoader_MOD loader(&f); CPLoader::Error err=loader.load_song(p_path.utf8().get_data(),&esc->song,false); ERR_FAIL_COND_V(err!=CPLoader::FILE_OK,RES()); + if (r_error) + *r_error=OK; return esc; } diff --git a/drivers/chibi/event_stream_chibi.h b/drivers/chibi/event_stream_chibi.h index 7b2ee4b471..b564c16018 100644 --- a/drivers/chibi/event_stream_chibi.h +++ b/drivers/chibi/event_stream_chibi.h @@ -301,7 +301,7 @@ public: class ResourceFormatLoaderChibi : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/dds/texture_loader_dds.cpp b/drivers/dds/texture_loader_dds.cpp index 8e6c3b62e6..9b2e401fd9 100644 --- a/drivers/dds/texture_loader_dds.cpp +++ b/drivers/dds/texture_loader_dds.cpp @@ -64,8 +64,10 @@ static const DDSFormatInfo dds_format_info[DDS_MAX]={ }; -RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatDDS::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -73,6 +75,8 @@ RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) return RES(); FileAccessRef fref(f); + if (r_error) + *r_error=ERR_FILE_CORRUPT; ERR_EXPLAIN("Unable to open DDS texture file: "+p_path); ERR_FAIL_COND_V(err!=OK,RES()); @@ -427,6 +431,10 @@ RES ResourceFormatDDS::load(const String &p_path,const String& p_original_path) Ref<ImageTexture> texture = memnew( ImageTexture ); texture->create_from_image(img); + if (r_error) + *r_error=OK; + + return texture; } diff --git a/drivers/dds/texture_loader_dds.h b/drivers/dds/texture_loader_dds.h index 18a1485073..c8b3610063 100644 --- a/drivers/dds/texture_loader_dds.h +++ b/drivers/dds/texture_loader_dds.h @@ -7,7 +7,7 @@ class ResourceFormatDDS : public ResourceFormatLoader{ public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/mpc/audio_stream_mpc.cpp b/drivers/mpc/audio_stream_mpc.cpp index cd8125c9af..67f21f922c 100644 --- a/drivers/mpc/audio_stream_mpc.cpp +++ b/drivers/mpc/audio_stream_mpc.cpp @@ -366,8 +366,9 @@ AudioStreamMPC::~AudioStreamMPC() { -RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path,const String& p_original_path) { - +RES ResourceFormatLoaderAudioStreamMPC::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; //streamed so it will always work.. AudioStreamMPC *mpc_stream = memnew(AudioStreamMPC); mpc_stream->set_file(p_path); return Ref<AudioStreamMPC>(mpc_stream); diff --git a/drivers/mpc/audio_stream_mpc.h b/drivers/mpc/audio_stream_mpc.h index fa949acd00..8fb0ed13de 100644 --- a/drivers/mpc/audio_stream_mpc.h +++ b/drivers/mpc/audio_stream_mpc.h @@ -88,7 +88,7 @@ public: class ResourceFormatLoaderAudioStreamMPC : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/pvr/texture_loader_pvr.cpp b/drivers/pvr/texture_loader_pvr.cpp index 5268b953f4..eb67dad8cf 100644 --- a/drivers/pvr/texture_loader_pvr.cpp +++ b/drivers/pvr/texture_loader_pvr.cpp @@ -22,8 +22,10 @@ enum PVRFLags { -RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path,Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -34,6 +36,8 @@ RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) ERR_FAIL_COND_V(err,RES()); + if (r_error) + *r_error=ERR_FILE_CORRUPT; uint32_t hsize = f->get_32(); @@ -135,6 +139,9 @@ RES ResourceFormatPVR::load(const String &p_path,const String& p_original_path) Ref<ImageTexture> texture = memnew( ImageTexture ); texture->create_from_image(image,tex_flags); + if (r_error) + *r_error=OK; + return texture; } diff --git a/drivers/pvr/texture_loader_pvr.h b/drivers/pvr/texture_loader_pvr.h index ad86660aa1..735cb2b48b 100644 --- a/drivers/pvr/texture_loader_pvr.h +++ b/drivers/pvr/texture_loader_pvr.h @@ -9,7 +9,7 @@ class ResourceFormatPVR : public ResourceFormatLoader{ public: - virtual RES load(const String &p_path,const String& p_original_path); + virtual RES load(const String &p_path,const String& p_original_path,Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/speex/audio_stream_speex.cpp b/drivers/speex/audio_stream_speex.cpp index bcf4c515f8..2cffb17049 100644 --- a/drivers/speex/audio_stream_speex.cpp +++ b/drivers/speex/audio_stream_speex.cpp @@ -530,7 +530,10 @@ AudioStreamSpeex::~AudioStreamSpeex() { unload(); } -RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=OK; AudioStreamSpeex *stream = memnew(AudioStreamSpeex); stream->set_file(p_path); diff --git a/drivers/speex/audio_stream_speex.h b/drivers/speex/audio_stream_speex.h index 9557ebe0b8..f9e0fce666 100644 --- a/drivers/speex/audio_stream_speex.h +++ b/drivers/speex/audio_stream_speex.h @@ -91,7 +91,7 @@ public: class ResourceFormatLoaderAudioStreamSpeex : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/theora/video_stream_theora.h b/drivers/theora/video_stream_theora.h index b408f9db13..12aac731fc 100644 --- a/drivers/theora/video_stream_theora.h +++ b/drivers/theora/video_stream_theora.h @@ -102,7 +102,7 @@ public: class ResourceFormatLoaderVideoStreamTheora : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/theoraplayer/video_stream_theoraplayer.cpp b/drivers/theoraplayer/video_stream_theoraplayer.cpp index ef1f5651ab..876cac3425 100644 --- a/drivers/theoraplayer/video_stream_theoraplayer.cpp +++ b/drivers/theoraplayer/video_stream_theoraplayer.cpp @@ -525,7 +525,9 @@ VideoStreamTheoraplayer::VideoStreamTheoraplayer() { }; -RES ResourceFormatLoaderVideoStreamTheoraplayer::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderVideoStreamTheoraplayer::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; VideoStreamTheoraplayer *stream = memnew(VideoStreamTheoraplayer); stream->set_file(p_path); diff --git a/drivers/theoraplayer/video_stream_theoraplayer.h b/drivers/theoraplayer/video_stream_theoraplayer.h index d43c12609f..69cae7c4a2 100644 --- a/drivers/theoraplayer/video_stream_theoraplayer.h +++ b/drivers/theoraplayer/video_stream_theoraplayer.h @@ -54,7 +54,7 @@ public: class ResourceFormatLoaderVideoStreamTheoraplayer : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.cpp b/drivers/vorbis/audio_stream_ogg_vorbis.cpp index ed292621e9..a9fefc1422 100644 --- a/drivers/vorbis/audio_stream_ogg_vorbis.cpp +++ b/drivers/vorbis/audio_stream_ogg_vorbis.cpp @@ -385,7 +385,9 @@ AudioStreamOGGVorbis::~AudioStreamOGGVorbis() { -RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderAudioStreamOGGVorbis::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=OK; AudioStreamOGGVorbis *ogg_stream = memnew(AudioStreamOGGVorbis); ogg_stream->set_file(p_path); diff --git a/drivers/vorbis/audio_stream_ogg_vorbis.h b/drivers/vorbis/audio_stream_ogg_vorbis.h index 8a35fc09cb..5e3649d980 100644 --- a/drivers/vorbis/audio_stream_ogg_vorbis.h +++ b/drivers/vorbis/audio_stream_ogg_vorbis.h @@ -111,7 +111,7 @@ public: class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/modules/gdscript/gd_script.cpp b/modules/gdscript/gd_script.cpp index 53ae0c8702..99ddc74bb4 100644 --- a/modules/gdscript/gd_script.cpp +++ b/modules/gdscript/gd_script.cpp @@ -2710,7 +2710,10 @@ GDScriptLanguage::~GDScriptLanguage() { /*************** RESOURCE ***************/ -RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderGDScript::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; GDScript *script = memnew( GDScript ); @@ -2742,6 +2745,8 @@ RES ResourceFormatLoaderGDScript::load(const String &p_path,const String& p_orig script->reload(); } + if (r_error) + *r_error=OK; return scriptres; } diff --git a/modules/gdscript/gd_script.h b/modules/gdscript/gd_script.h index fe325ff71e..37ef47af6c 100644 --- a/modules/gdscript/gd_script.h +++ b/modules/gdscript/gd_script.h @@ -557,7 +557,7 @@ public: class ResourceFormatLoaderGDScript : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp index 3ddf23fc4a..0c0f924f52 100644 --- a/scene/gui/dialogs.cpp +++ b/scene/gui/dialogs.cpp @@ -274,7 +274,7 @@ Button* AcceptDialog::add_button(const String& p_text,bool p_right,const String& } if (p_action!="") { - button->connect("pressed",this,"_custom_action",make_binds(p_action)); + button->connect("pressed",this,"_custom_action",varray(p_action)); } return button; diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index c29f6625d3..b7b2f061ea 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -187,6 +187,7 @@ void ItemList::select(int p_idx,bool p_single){ } current=p_idx; + ensure_selected_visible=false; } else { if (items[p_idx].selectable) { @@ -195,6 +196,7 @@ void ItemList::select(int p_idx,bool p_single){ } update(); + } void ItemList::unselect(int p_idx){ @@ -246,12 +248,14 @@ void ItemList::remove_item(int p_idx){ update(); shape_changed=true; + } void ItemList::clear(){ items.clear(); current=-1; + ensure_selected_visible=false; update(); } @@ -602,18 +606,8 @@ void ItemList::_input_event(const InputEvent& p_event) { void ItemList::ensure_current_is_visible() { - if (current>=0 && current <=items.size()) { - - Rect2 r = items[current].rect_cache; - int from = scroll_bar->get_val(); - int to = from + scroll_bar->get_page(); - - if (r.pos.y < from) { - scroll_bar->set_val(r.pos.y); - } else if (r.pos.y+r.size.y > to) { - scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); - } - } + ensure_selected_visible=true; + update(); } void ItemList::_notification(int p_what) { @@ -928,6 +922,24 @@ void ItemList::_notification(int p_what) { draw_line(Vector2(bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),Vector2(size.width-bg->get_margin(MARGIN_LEFT),base_ofs.y+separators[i]),guide_color); } + + if (ensure_selected_visible && current>=0 && current <=items.size()) { + + Rect2 r = items[current].rect_cache; + int from = scroll_bar->get_val(); + int to = from + scroll_bar->get_page(); + + if (r.pos.y < from) { + scroll_bar->set_val(r.pos.y); + } else if (r.pos.y+r.size.y > to) { + scroll_bar->set_val(r.pos.y+r.size.y - (to-from)); + } + + + } + + ensure_selected_visible=false; + } } @@ -1095,6 +1107,7 @@ ItemList::ItemList() { set_focus_mode(FOCUS_ALL); current_columns=1; search_time_msec=0; + ensure_selected_visible=false; } diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h index 237079c428..7cf58a6426 100644 --- a/scene/gui/item_list.h +++ b/scene/gui/item_list.h @@ -41,6 +41,8 @@ private: bool shape_changed; + bool ensure_selected_visible; + Vector<Item> items; Vector<int> separators; diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp index 6c15f1cae4..4feb03feef 100644 --- a/scene/gui/tree.cpp +++ b/scene/gui/tree.cpp @@ -2360,6 +2360,11 @@ void Tree::_notification(int p_what) { } } + if (p_what==NOTIFICATION_VISIBILITY_CHANGED) { + + drag_touching=false; + } + if (p_what==NOTIFICATION_ENTER_TREE) { update_cache();; diff --git a/scene/io/resource_format_image.cpp b/scene/io/resource_format_image.cpp index 8527498fc2..f67d50b56c 100644 --- a/scene/io/resource_format_image.cpp +++ b/scene/io/resource_format_image.cpp @@ -31,9 +31,11 @@ #include "io/image_loader.h" #include "globals.h" #include "os/os.h" -RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_original_path) { - +RES ResourceFormatLoaderImage::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; + if (p_path.extension()=="cube") { // open as cubemap txture @@ -83,6 +85,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina memdelete(f); cubemap->set_name(p_path.get_file()); + if (r_error) + *r_error=OK; return cubemap; @@ -112,6 +116,8 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina ERR_EXPLAIN("Failed loading image: "+p_path); ERR_FAIL_COND_V(err, RES()); + if (r_error) + *r_error=ERR_FILE_CORRUPT; #ifdef DEBUG_ENABLED #ifdef TOOLS_ENABLED @@ -199,6 +205,9 @@ RES ResourceFormatLoaderImage::load(const String &p_path,const String& p_origina print_line(" -make texture: "+rtos(total)); } + if (r_error) + *r_error=OK; + return RES( texture ); } diff --git a/scene/io/resource_format_image.h b/scene/io/resource_format_image.h index 1af65870f8..b5ec5a1200 100644 --- a/scene/io/resource_format_image.h +++ b/scene/io/resource_format_image.h @@ -40,7 +40,7 @@ class ResourceFormatLoaderImage : public ResourceFormatLoader { int max_texture_size; public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/io/resource_format_wav.cpp b/scene/io/resource_format_wav.cpp index 7c90a4b3cd..090348c933 100644 --- a/scene/io/resource_format_wav.cpp +++ b/scene/io/resource_format_wav.cpp @@ -31,13 +31,18 @@ #include "scene/resources/sample.h" -RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderWAV::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; Error err; FileAccess *file=FileAccess::open(p_path, FileAccess::READ,&err); ERR_FAIL_COND_V( err!=OK, RES() ); + if (r_error) + *r_error=ERR_FILE_CORRUPT; + /* CHECK RIFF */ char riff[5]; riff[4]=0; @@ -244,6 +249,9 @@ RES ResourceFormatLoaderWAV::load(const String &p_path,const String& p_original_ file->close(); memdelete(file); + if (r_error) + *r_error=OK; + return sample; } diff --git a/scene/io/resource_format_wav.h b/scene/io/resource_format_wav.h index 081a563d03..a74da041c1 100644 --- a/scene/io/resource_format_wav.h +++ b/scene/io/resource_format_wav.h @@ -33,7 +33,7 @@ class ResourceFormatLoaderWAV : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/resources/bit_mask.cpp b/scene/resources/bit_mask.cpp index ef056a6230..9a6452797a 100644 --- a/scene/resources/bit_mask.cpp +++ b/scene/resources/bit_mask.cpp @@ -205,7 +205,10 @@ BitMap::BitMap() { ////////////////////////////////////// -RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderBitMap::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; BitMap* ptr = memnew(BitMap); Ref<BitMap> bitmap( ptr ); @@ -219,6 +222,8 @@ RES ResourceFormatLoaderBitMap::load(const String &p_path,const String& p_origin ERR_FAIL_COND_V(err, RES()); bitmap->create_from_image_alpha(image); + if (r_error) + *r_error=OK; return bitmap; diff --git a/scene/resources/bit_mask.h b/scene/resources/bit_mask.h index 29b7bc66f4..a6b29bb919 100644 --- a/scene/resources/bit_mask.h +++ b/scene/resources/bit_mask.h @@ -66,7 +66,7 @@ class ResourceFormatLoaderBitMap : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/resources/shader.cpp b/scene/resources/shader.cpp index 90598ee789..a9376faf62 100644 --- a/scene/resources/shader.cpp +++ b/scene/resources/shader.cpp @@ -219,7 +219,10 @@ Shader::~Shader() { -RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderShader::load(const String &p_path, const String& p_original_path, Error *r_error) { + + if (r_error) + *r_error=ERR_FILE_CANT_OPEN; String fragment_code; String vertex_code; @@ -235,6 +238,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin ERR_FAIL_COND_V(err,RES()); String base_path = p_path.get_base_dir(); + if (r_error) + *r_error=ERR_FILE_CORRUPT; Ref<Shader> shader;//( memnew( Shader ) ); @@ -435,6 +440,8 @@ RES ResourceFormatLoaderShader::load(const String &p_path,const String& p_origin f->close(); memdelete(f); + if (r_error) + *r_error=OK; return shader; } diff --git a/scene/resources/shader.h b/scene/resources/shader.h index b805cbec96..61a369c408 100644 --- a/scene/resources/shader.h +++ b/scene/resources/shader.h @@ -126,7 +126,7 @@ public: class ResourceFormatLoaderShader : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp index 3060fe41b4..651e234b49 100644 --- a/scene/resources/theme.cpp +++ b/scene/resources/theme.cpp @@ -601,7 +601,9 @@ Theme::~Theme() -RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_original_path) { +RES ResourceFormatLoaderTheme::load(const String &p_path, const String& p_original_path, Error *r_error) { + if (r_error) + *r_error=ERR_CANT_OPEN; Error err; FileAccess *f = FileAccess::open(p_path,FileAccess::READ,&err); @@ -611,6 +613,8 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina String base_path = p_path.get_base_dir(); Ref<Theme> theme( memnew( Theme ) ); Map<StringName,Variant> library; + if (r_error) + *r_error=ERR_FILE_CORRUPT; bool reading_library=false; int line=0; @@ -1003,6 +1007,9 @@ RES ResourceFormatLoaderTheme::load(const String &p_path,const String& p_origina f->close(); memdelete(f); + if (r_error) + *r_error=OK; + return theme; } diff --git a/scene/resources/theme.h b/scene/resources/theme.h index 802dcb099c..cfa0762595 100644 --- a/scene/resources/theme.h +++ b/scene/resources/theme.h @@ -124,7 +124,7 @@ public: class ResourceFormatLoaderTheme : public ResourceFormatLoader { public: - virtual RES load(const String &p_path,const String& p_original_path=""); + virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual void get_recognized_extensions(List<String> *p_extensions) const; virtual bool handles_type(const String& p_type) const; virtual String get_resource_type(const String &p_path) const; diff --git a/tools/editor/dependency_editor.cpp b/tools/editor/dependency_editor.cpp new file mode 100644 index 0000000000..c04e82a08a --- /dev/null +++ b/tools/editor/dependency_editor.cpp @@ -0,0 +1,512 @@ +#include "dependency_editor.h" +#include "os/file_access.h" +#include "scene/gui/margin_container.h" +#include "io/resource_loader.h" +#include "editor_node.h" + +void DependencyEditor::_notification(int p_what){ + + +} + +void DependencyEditor::_searched(const String& p_path) { + + Map<String,String> dep_rename; + dep_rename[replacing]=p_path; + + + ResourceLoader::rename_dependencies(editing,dep_rename); + + _update_list(); + _update_file(); +} + +void DependencyEditor::_load_pressed(Object* p_item,int p_cell,int p_button){ + + TreeItem *ti=p_item->cast_to<TreeItem>(); + String fname = ti->get_text(0); + replacing = ti->get_text(1); + + search->set_title("Search Replacement For: "+replacing.get_file()); + + search->clear_filters(); + List<String> ext; + ResourceLoader::get_recognized_extensions_for_type(ti->get_metadata(0),&ext); + for (List<String>::Element *E=ext.front();E;E=E->next()) { + search->add_filter("*"+E->get()); + } + search->popup_centered_ratio(); + +} + +void DependencyEditor::_fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates){ + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fix_and_find(efsd->get_subdir(i),candidates); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + String file = efsd->get_file(i); + if (!candidates.has(file)) + continue; + + String path = efsd->get_file_path(i); + Map<String,String> &ss = candidates[file]; + + + for(Map<String,String>::Element *E=candidates[file].front();E;E=E->next()) { + + if (E->get()==String()) { + E->get()=path; + continue; + } + + //must match the best, using subdirs + String existing=E->get().replace_first("res://",""); + String current=path.replace_first("res://",""); + String lost=E->key().replace_first("res://",""); + + Vector<String> existingv=existing.split("/"); + existingv.invert(); + Vector<String> currentv=current.split("/"); + currentv.invert(); + Vector<String> lostv=lost.split("/"); + lostv.invert(); + + int existing_score=0; + int current_score=0; + + for(int j=0;j<lostv.size();j++) { + + if (j<existingv.size() && lostv[j]==existingv[j]) { + existing_score++; + } + if (j<currentv.size() && lostv[j]==currentv[j]) { + current_score++; + } + } + + if (current_score > existing_score) { + + //if it was the same, could track distance to new path but.. + + E->get()=path; //replace by more accurate + } + + } + + } + +} + + +void DependencyEditor::_fix_all(){ + + if (!EditorFileSystem::get_singleton()->get_filesystem()) + return; + + Map<String,Map<String,String> > candidates; + + for (List<String>::Element *E=missing.front();E;E=E->next()) { + + String base = E->get().get_file(); + if (!candidates.has(base)) { + candidates[base]=Map<String,String>(); + } + + candidates[base][E->get()]=""; + } + + _fix_and_find(EditorFileSystem::get_singleton()->get_filesystem(),candidates); + + Map<String,String> remaps; + + for (Map<String,Map<String,String> >::Element *E=candidates.front();E;E=E->next()) { + + for (Map<String,String>::Element *F=E->get().front();F;F=F->next()) { + + if (F->get()!=String()) { + remaps[F->key()]=F->get(); + } + } + + } + + if (remaps.size()) { + + ResourceLoader::rename_dependencies(editing,remaps); + + _update_list(); + _update_file(); + } +} + +void DependencyEditor::_update_file() { + + EditorFileSystem::get_singleton()->update_file(editing); + +} + +void DependencyEditor::_update_list() { + + List<String> deps; + ResourceLoader::get_dependencies(editing,&deps,true); + + tree->clear(); + missing.clear(); + + TreeItem *root = tree->create_item(); + + Ref<Texture> folder = get_icon("folder","FileDialog"); + + bool broken=false; + + for(List<String>::Element *E=deps.front();E;E=E->next()) { + + TreeItem *item = tree->create_item(root); + + String n = E->get(); + String path; + String type; + + if (n.find("::")!=-1) { + path = n.get_slice("::",0); + type = n.get_slice("::",1); + } else { + path=n; + type="Resource"; + } + String name = path.get_file(); + + Ref<Texture> icon; + if (has_icon(type,"EditorIcons")) { + icon=get_icon(type,"EditorIcons"); + } else { + icon=get_icon("Object","EditorIcons"); + } + item->set_text(0,name); + item->set_icon(0,icon); + item->set_metadata(0,type); + item->set_text(1,path); + + if (!FileAccess::exists(path)) { + item->set_custom_color(1,Color(1,0.4,0.3)); + missing.push_back(path); + broken=true; + } + + item->add_button(1,folder,0); + } + + fixdeps->set_disabled(!broken); + +} + + + +void DependencyEditor::edit(const String& p_path) { + + + editing=p_path; + set_title("Dependencies For: "+p_path.get_file()); + + _update_list(); + popup_centered_ratio(); + + if (EditorNode::get_singleton()->is_scene_open(p_path)) { + EditorNode::get_singleton()->show_warning("Scene '"+p_path.get_file()+"' is currently being edited.\nChanges will not take effect unless reloaded."); + } else if (ResourceCache::has(p_path)) { + EditorNode::get_singleton()->show_warning("Resource '"+p_path.get_file()+"' is in use.\nChanges will take effect when reloaded."); + } +} + + +void DependencyEditor::_bind_methods() { + + ObjectTypeDB::bind_method(_MD("_searched"),&DependencyEditor::_searched); + ObjectTypeDB::bind_method(_MD("_load_pressed"),&DependencyEditor::_load_pressed); + ObjectTypeDB::bind_method(_MD("_fix_all"),&DependencyEditor::_fix_all); + +} + +DependencyEditor::DependencyEditor() { + + VBoxContainer *vb = memnew( VBoxContainer ); + vb->set_name("Dependencies"); + add_child(vb); + set_child_rect(vb); + + tree = memnew( Tree ); + tree->set_columns(2); + tree->set_column_titles_visible(true); + tree->set_column_title(0,"Resource"); + tree->set_column_title(1,"Path"); + tree->set_hide_root(true); + tree->connect("button_pressed",this,"_load_pressed"); + + HBoxContainer *hbc = memnew( HBoxContainer ); + Label *label = memnew( Label("Dependencies:")); + hbc->add_child(label); + hbc->add_spacer(); + fixdeps = memnew( Button("Fix Broken")); + hbc->add_child(fixdeps); + fixdeps->connect("pressed",this,"_fix_all"); + + vb->add_child(hbc); + + MarginContainer *mc = memnew( MarginContainer ); + mc->set_v_size_flags(SIZE_EXPAND_FILL); + + mc->add_child(tree); + vb->add_child(mc); + + set_title("Dependency Editor"); + search = memnew( EditorFileDialog ); + search->connect("file_selected",this,"_searched"); + search->set_mode(EditorFileDialog::MODE_OPEN_FILE); + search->set_title("Search Replacement Resource:"); + add_child(search); + +} + +///////////////////////////////////// + + + +void DependencyEditorOwners::_fill_owners(EditorFileSystemDirectory *efsd) { + + if (!efsd) + return; + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fill_owners(efsd->get_subdir(i)); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + Vector<String> deps = efsd->get_file_deps(i); + //print_line(":::"+efsd->get_file_path(i)); + bool found=false; + for(int j=0;j<deps.size();j++) { + //print_line("\t"+deps[j]+" vs "+editing); + if (deps[j]==editing) { + //print_line("found"); + found=true; + break; + } + } + if (!found) + continue; + + Ref<Texture> icon; + String type=efsd->get_file_type(i); + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + owners->add_item(efsd->get_file_path(i),icon); + } + +} + +void DependencyEditorOwners::show(const String& p_path) { + + editing=p_path; + owners->clear(); + _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + popup_centered_ratio(); + + set_title("Owners Of: "+p_path.get_file()); + +} + +DependencyEditorOwners::DependencyEditorOwners() { + + + owners = memnew( ItemList ); + add_child(owners); + set_child_rect(owners); + + +} + +/////////////////////// + + +void DependencyRemoveDialog::_fill_owners(EditorFileSystemDirectory *efsd) { + + if (!efsd) + return; + + for(int i=0;i<efsd->get_subdir_count();i++) { + _fill_owners(efsd->get_subdir(i)); + } + + for(int i=0;i<efsd->get_file_count();i++) { + + Vector<String> deps = efsd->get_file_deps(i); + //print_line(":::"+efsd->get_file_path(i)); + Set<String> met; + for(int j=0;j<deps.size();j++) { + if (files.has(deps[j])) { + met.insert(deps[j]); + } + } + if (!met.size()) + continue; + + exist=true; + + Ref<Texture> icon; + String type=efsd->get_file_type(i); + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + + for(Set<String>::Element *E=met.front();E;E=E->next()) { + + String which = E->get(); + if (!files[which]) { + TreeItem *ti=owners->create_item(owners->get_root()); + ti->set_text(0,which.get_file()); + files[which]=ti; + + } + TreeItem *ti=owners->create_item(files[which]); + ti->set_text(0,efsd->get_file_path(i)); + ti->set_icon(0,icon); + } + + } + +} + +void DependencyRemoveDialog::show(const Vector<String> &to_erase) { + + exist=false; + owners->clear(); + files.clear(); + TreeItem *root=owners->create_item(); + for(int i=0;i<to_erase.size();i++) { + files[to_erase[i]]=NULL; + } + + _fill_owners(EditorFileSystem::get_singleton()->get_filesystem()); + + if (exist) { + owners->show(); + text->set_text("The files being removed are required by other resources in order for them to work.\nRemove them anyway? (no undo)"); + popup_centered_minsize(Size2(500,220)); + } else { + owners->hide(); + text->set_text("Remove selected files from the project? (no undo)"); + popup_centered_minsize(Size2(400,100)); + } + +} + +void DependencyRemoveDialog::ok_pressed() { + + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + for (Map<String,TreeItem*>::Element *E=files.front();E;E=E->next()) { + + da->remove(E->key()); + EditorFileSystem::get_singleton()->update_file(E->key()); + } + memdelete(da); + +} + +DependencyRemoveDialog::DependencyRemoveDialog() { + + VBoxContainer *vb = memnew( VBoxContainer ); + add_child(vb); + set_child_rect(vb); + + text = memnew( Label ); + vb->add_child(text); + + owners = memnew( Tree ); + owners->set_hide_root(true); + vb->add_child(owners); + owners->set_v_size_flags(SIZE_EXPAND_FILL); + get_ok()->set_text("Remove"); +} + + +////////////// + + +void DependencyErrorDialog::show(const String& p_for_file,const Vector<String> &report) { + + + for_file=p_for_file; + set_title("Error loading: "+p_for_file.get_file()); + files->clear(); + + TreeItem *root = files->create_item(NULL); + for(int i=0;i<report.size();i++) { + + String dep; + String type="Object"; + dep=report[i].get_slice("::",0); + if (report[i].get_slice_count("::")>0) + type=report[i].get_slice("::",1); + + Ref<Texture> icon; + if (!has_icon(type,"EditorIcons")) { + icon=get_icon("Object","EditorIcons"); + } else { + icon=get_icon(type,"EditorIcons"); + } + + TreeItem *ti=files->create_item(root); + ti->set_text(0,dep); + ti->set_icon(0,icon); + + } + + popup_centered_minsize(Size2(500,220)); + +} + +void DependencyErrorDialog::ok_pressed() { + + EditorNode::get_singleton()->load_scene(for_file,true); +} + +void DependencyErrorDialog::custom_action(const String&) { + + EditorNode::get_singleton()->fix_dependencies(for_file); +} + +DependencyErrorDialog::DependencyErrorDialog() { + + VBoxContainer *vb = memnew( VBoxContainer ); + add_child(vb); + set_child_rect(vb); + + + files = memnew( Tree ); + files->set_hide_root(true); + vb->add_margin_child("Scene failed to load due to missing dependencies:",files,true); + files->set_v_size_flags(SIZE_EXPAND_FILL); + get_ok()->set_text("Open Anyway"); + + text = memnew( Label ); + vb->add_child(text); + text->set_text("Which action should be taken?"); + + + fdep=add_button("Fix Dependencies",true,"fixdeps"); + + set_title("Errors loading!"); + +} diff --git a/tools/editor/dependency_editor.h b/tools/editor/dependency_editor.h new file mode 100644 index 0000000000..1c328e7a93 --- /dev/null +++ b/tools/editor/dependency_editor.h @@ -0,0 +1,94 @@ +#ifndef DEPENDENCY_EDITOR_H +#define DEPENDENCY_EDITOR_H + +#include "scene/gui/dialogs.h" +#include "scene/gui/tree.h" +#include "scene/gui/tab_container.h" +#include "editor_file_dialog.h" + +class EditorFileSystemDirectory; + +class DependencyEditor : public AcceptDialog { + OBJ_TYPE(DependencyEditor,AcceptDialog); + + + Tree *tree; + Button *fixdeps; + + EditorFileDialog *search; + + String replacing; + String editing; + List<String> missing; + + + void _fix_and_find(EditorFileSystemDirectory *efsd, Map<String,Map<String,String> >& candidates); + + void _searched(const String& p_path); + void _load_pressed(Object* p_item,int p_cell,int p_button); + void _fix_all(); + void _update_list(); + + void _update_file(); + +protected: + + static void _bind_methods(); + void _notification(int p_what); +public: + + + void edit(const String& p_path); + DependencyEditor(); +}; + +class DependencyEditorOwners : public AcceptDialog { + OBJ_TYPE(DependencyEditorOwners,AcceptDialog); + + ItemList *owners; + String editing; + void _fill_owners(EditorFileSystemDirectory *efsd); + +public: + + void show(const String& p_path); + DependencyEditorOwners(); +}; + +class DependencyRemoveDialog : public ConfirmationDialog { + OBJ_TYPE(DependencyRemoveDialog,ConfirmationDialog); + + + Label *text; + Tree *owners; + bool exist; + Map<String,TreeItem*> files; + void _fill_owners(EditorFileSystemDirectory *efsd); + + void ok_pressed(); + +public: + + void show(const Vector<String> &to_erase); + DependencyRemoveDialog(); +}; + + +class DependencyErrorDialog : public ConfirmationDialog { + OBJ_TYPE(DependencyErrorDialog,ConfirmationDialog); + + + String for_file; + Button *fdep; + Label *text; + Tree *files; + void ok_pressed(); + void custom_action(const String&); + +public: + + void show(const String& p_for,const Vector<String> &report); + DependencyErrorDialog(); +}; + +#endif // DEPENDENCY_EDITOR_H diff --git a/tools/editor/editor_file_dialog.cpp b/tools/editor/editor_file_dialog.cpp index b1bbd71f7b..c62347d129 100644 --- a/tools/editor/editor_file_dialog.cpp +++ b/tools/editor/editor_file_dialog.cpp @@ -190,7 +190,7 @@ void EditorFileDialog::_thumbnail_done(const String& p_path,const Ref<Texture>& void EditorFileDialog::_request_single_thumbnail(const String& p_path) { EditorResourcePreview::get_singleton()->queue_resource_preview(p_path,this,"_thumbnail_done",p_path); - print_line("want file "+p_path); + //print_line("want file "+p_path); set_process(true); preview_waiting=true; preview_wheel_timeout=0; @@ -359,7 +359,7 @@ void EditorFileDialog::_item_dc_selected(int p_item) { if (d["dir"]) { - print_line("change dir: "+String(d["name"])); + //print_line("change dir: "+String(d["name"])); dir_access->change_dir(d["name"]); if (mode==MODE_OPEN_FILE || mode==MODE_OPEN_FILES || mode==MODE_OPEN_DIR) file->set_text(""); @@ -536,6 +536,7 @@ void EditorFileDialog::update_file_list() { if (get_icon_func) { + Ref<Texture> icon = get_icon_func(base_dir.plus_file(files.front()->get())); //ti->set_icon(0,icon); if (display_mode==DISPLAY_THUMBNAILS) { diff --git a/tools/editor/editor_file_system.cpp b/tools/editor/editor_file_system.cpp index d741087a9f..33e4a15c85 100644 --- a/tools/editor/editor_file_system.cpp +++ b/tools/editor/editor_file_system.cpp @@ -94,6 +94,12 @@ bool EditorFileSystemDirectory::get_file_meta(int p_idx) const { return files[p_idx].meta.enabled; } +Vector<String> EditorFileSystemDirectory::get_file_deps(int p_idx) const { + + ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); + return files[p_idx].meta.deps; + +} Vector<String> EditorFileSystemDirectory::get_missing_sources(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),Vector<String>()); @@ -118,7 +124,7 @@ bool EditorFileSystemDirectory::is_missing_sources(int p_idx) const { return false; } -String EditorFileSystemDirectory::get_file_type(int p_idx) const { +StringName EditorFileSystemDirectory::get_file_type(int p_idx) const { ERR_FAIL_INDEX_V(p_idx,files.size(),""); return files[p_idx].type; @@ -198,6 +204,13 @@ EditorFileSystemDirectory::ImportMeta EditorFileSystem::_get_meta(const String& } m.import_editor=imd->get_editor(); } + + List<String> deps; + ResourceLoader::get_dependencies(p_path,&deps); + for(List<String>::Element *E=deps.front();E;E=E->next()) { + m.deps.push_back(E->get()); + } + return m; } @@ -358,7 +371,7 @@ void EditorFileSystem::_scan_scenes() { String project=Globals::get_singleton()->get_resource_path(); - String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("file_cache"); + String fscache = EditorSettings::get_singleton()->get_project_settings_path().plus_file("filesystem_cache"); FileAccess *f =FileAccess::open(fscache,FileAccess::READ); if (f) { @@ -397,7 +410,7 @@ void EditorFileSystem::_scan_scenes() { } else { Vector<String> split = l.split("::"); - ERR_CONTINUE( split.size() != 4); + ERR_CONTINUE( split.size() != 5); String name = split[0]; String file; @@ -429,6 +442,15 @@ void EditorFileSystem::_scan_scenes() { } } + String deps = split[4].strip_edges(); + if (deps.length()) { + Vector<String> dp = deps.split("<>"); + for(int i=0;i<dp.size();i++) { + String path=dp[i]; + fc.meta.deps.push_back(path); + } + } + file_cache[name]=fc; ERR_CONTINUE(!dc); @@ -530,6 +552,7 @@ void EditorFileSystem::scan() { thread = Thread::create(_thread_func,this,s); //tree->hide(); //progress->show(); + } @@ -798,6 +821,14 @@ void EditorFileSystem::_save_type_cache_fs(DirItem *p_dir,FileAccess *p_file) { } } + s+="::"; + for(int j=0;j<p_dir->files[i]->meta.deps.size();j++) { + + if (j>0) + s+="<>"; + s+=p_dir->files[i]->meta.deps[j]; + } + p_file->store_line(s); } @@ -1037,6 +1068,13 @@ void EditorFileSystem::update_file(const String& p_file) { return; } + if (!FileAccess::exists(p_file)) { + //was removed + fs->files.remove(cpos); + call_deferred("emit_signal","filesystem_changed"); //update later + return; + + } String type = ResourceLoader::get_resource_type(p_file); diff --git a/tools/editor/editor_file_system.h b/tools/editor/editor_file_system.h index 3f413292fe..f79dd209ef 100644 --- a/tools/editor/editor_file_system.h +++ b/tools/editor/editor_file_system.h @@ -59,13 +59,14 @@ class EditorFileSystemDirectory : public Object { Vector<Source> sources; String import_editor; + Vector<String> deps; bool enabled; }; struct FileInfo { String file; - String type; + StringName type; uint64_t modified_time; ImportMeta meta; @@ -87,10 +88,11 @@ public: int get_file_count() const; String get_file(int p_idx) const; String get_file_path(int p_idx) const; - String get_file_type(int p_idx) const; + StringName get_file_type(int p_idx) const; bool get_file_meta(int p_idx) const; bool is_missing_sources(int p_idx) const; Vector<String> get_missing_sources(int p_idx) const; + Vector<String> get_file_deps(int p_idx) const; EditorFileSystemDirectory *get_parent(); @@ -120,7 +122,7 @@ class EditorFileSystem : public Node { String path; String name; Vector<DirItem*> dirs; - Vector<SceneItem*> files; + Vector<SceneItem*> files; ~DirItem(); }; @@ -149,6 +151,7 @@ class EditorFileSystem : public Node { String type; uint64_t modification_time; EditorFileSystemDirectory::ImportMeta meta; + Vector<String> deps; }; struct DirCache { diff --git a/tools/editor/editor_node.cpp b/tools/editor/editor_node.cpp index 605335f7cf..9808026b63 100644 --- a/tools/editor/editor_node.cpp +++ b/tools/editor/editor_node.cpp @@ -1801,6 +1801,13 @@ void EditorNode::_menu_option_confirm(int p_option,bool p_confirmed) { quick_open->set_title("Quick Open Script.."); } break; + case FILE_QUICK_OPEN_FILE: { + + + quick_open->popup("Resource",false,true); + quick_open->set_title("Quick Search File.."); + + } break; case FILE_RUN_SCRIPT: { file_script->popup_centered_ratio(); @@ -3047,7 +3054,21 @@ void EditorNode::set_current_scene(int p_idx) { } -Error EditorNode::load_scene(const String& p_scene) { +bool EditorNode::is_scene_open(const String& p_path) { + + for(int i=0;i<editor_data.get_edited_scene_count();i++) { + if (editor_data.get_scene_path(i)==p_path) + return true; + } + + return false; +} + +void EditorNode::fix_dependencies(const String& p_for_file) { + dependency_fixer->edit(p_for_file); +} + +Error EditorNode::load_scene(const String& p_scene, bool p_ignore_broken_deps) { if (!is_inside_tree()) { defer_load_scene = p_scene; @@ -3093,6 +3114,8 @@ Error EditorNode::load_scene(const String& p_scene) { //_cleanup_scene(); // i'm sorry but this MUST happen to avoid modified resources to not be reloaded. + dependency_errors.clear(); + Ref<PackedScene> sdata = ResourceLoader::load(lpath,"",true); if (!sdata.is_valid()) { @@ -3110,6 +3133,35 @@ Error EditorNode::load_scene(const String& p_scene) { return ERR_FILE_NOT_FOUND; } + if (!p_ignore_broken_deps && dependency_errors.has(lpath)) { + + current_option=-1; + Vector<String> errors; + for(Set<String>::Element *E=dependency_errors[lpath].front();E;E=E->next()) { + + errors.push_back(E->get()); + } + dependency_error->show(lpath,errors); + opening_prev=false; + + if (prev!=-1) { + set_current_scene(prev); + editor_data.remove_scene(idx); + } + return ERR_FILE_MISSING_DEPENDENCIES; + } + + dependency_errors.erase(lpath); //at least not self path + + for (Map<String,Set<String> >::Element *E=dependency_errors.front();E;E=E->next()) { + + String txt="Scene '"+E->key()+"' has broken dependencies:\n"; + for(Set<String>::Element *F=E->get().front();F;F=F->next()) { + txt+="\t"+F->get()+"\n"; + } + add_io_error(txt); + } + sdata->set_path(lpath,true); //take over path Node*new_scene=sdata->instance(true); @@ -3405,9 +3457,12 @@ void EditorNode::hide_animation_player_editors() { void EditorNode::_quick_opened(const String& p_resource) { - print_line("quick_opened"); - if (quick_open->get_base_type()=="PackedScene") { + if (current_option==FILE_QUICK_OPEN_FILE) { + scenes_dock->open(p_resource); + return; + } + if (quick_open->get_base_type()=="PackedScene") { open_request(p_resource); } else { load_resource(p_resource); @@ -4117,6 +4172,7 @@ EditorNode::EditorNode() { ResourceLoader::set_abort_on_missing_resources(false); FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("file_dialog/show_hidden_files")); ResourceLoader::set_error_notify_func(this,_load_error_notify); + ResourceLoader::set_dependency_error_notify_func(this,_dependency_error_report); ResourceLoader::set_timestamp_on_load(true); ResourceSaver::set_timestamp_on_save(true); @@ -4490,6 +4546,7 @@ EditorNode::EditorNode() { p->add_separator(); p->add_item("Quick Open Scene..",FILE_QUICK_OPEN_SCENE,KEY_MASK_SHIFT+KEY_MASK_CMD+KEY_O); p->add_item("Quick Open Script..",FILE_QUICK_OPEN_SCRIPT,KEY_MASK_ALT+KEY_MASK_CMD+KEY_O); + p->add_item("Quick Search File..",FILE_QUICK_OPEN_FILE,KEY_MASK_ALT+KEY_MASK_CMD+KEY_P); p->add_separator(); PopupMenu *pm_export = memnew(PopupMenu ); @@ -4926,7 +4983,11 @@ EditorNode::EditorNode() { + dependency_error = memnew( DependencyErrorDialog ); + gui_base->add_child(dependency_error); + dependency_fixer = memnew( DependencyEditor ); + gui_base->add_child( dependency_fixer ); settings_config_dialog = memnew( EditorSettingsDialog ); gui_base->add_child(settings_config_dialog); diff --git a/tools/editor/editor_node.h b/tools/editor/editor_node.h index d40658a056..ee45a49e4e 100644 --- a/tools/editor/editor_node.h +++ b/tools/editor/editor_node.h @@ -123,6 +123,7 @@ class EditorNode : public Node { FILE_OPEN_OLD_SCENE, FILE_QUICK_OPEN_SCENE, FILE_QUICK_OPEN_SCRIPT, + FILE_QUICK_OPEN_FILE, FILE_RUN_SCRIPT, FILE_OPEN_PREV, FILE_CLOSE, @@ -312,6 +313,9 @@ class EditorNode : public Node { ProgressDialog *progress_dialog; BackgroundProgress *progress_hb; + DependencyErrorDialog *dependency_error; + DependencyEditor *dependency_fixer; + TabContainer *dock_slot[DOCK_SLOT_MAX]; Rect2 dock_select_rect[DOCK_SLOT_MAX]; int dock_select_rect_over; @@ -451,6 +455,16 @@ class EditorNode : public Node { void _save_scene_with_preview(String p_file); + Map<String,Set<String> > dependency_errors; + + static void _dependency_error_report(void *ud,const String& p_path,const String& p_dep,const String& p_type) { + EditorNode*en=(EditorNode*)ud; + if (!en->dependency_errors.has(p_path)) + en->dependency_errors[p_path]=Set<String>(); + en->dependency_errors[p_path].insert(p_dep+"::"+p_type); + + } + struct ExportDefer { String platform; String path; @@ -534,10 +548,13 @@ public: Viewport *get_scene_root() { return scene_root; } //root of the scene being edited Error save_optimized_copy(const String& p_scene,const String& p_preset); + void fix_dependencies(const String& p_for_file); void clear_scene() { _cleanup_scene(); } - Error load_scene(const String& p_scene); + Error load_scene(const String& p_scene,bool p_ignore_broken_deps=false); Error load_resource(const String& p_scene); + bool is_scene_open(const String& p_path); + void set_current_version(uint64_t p_version); void set_current_scene(int p_idx); diff --git a/tools/editor/icons/icon_file_list.png b/tools/editor/icons/icon_file_list.png Binary files differindex e5e9213e61..ab790a85a5 100644 --- a/tools/editor/icons/icon_file_list.png +++ b/tools/editor/icons/icon_file_list.png diff --git a/tools/editor/icons/icon_filesystem.png b/tools/editor/icons/icon_filesystem.png Binary files differnew file mode 100644 index 0000000000..6841f9a792 --- /dev/null +++ b/tools/editor/icons/icon_filesystem.png diff --git a/tools/editor/icons/icon_non_favorite.png b/tools/editor/icons/icon_non_favorite.png Binary files differnew file mode 100644 index 0000000000..edd806fbe8 --- /dev/null +++ b/tools/editor/icons/icon_non_favorite.png diff --git a/tools/editor/project_export.cpp b/tools/editor/project_export.cpp index a087f23c25..626fc6e6df 100644 --- a/tools/editor/project_export.cpp +++ b/tools/editor/project_export.cpp @@ -80,7 +80,7 @@ bool ProjectExportDialog::_create_tree(TreeItem *p_parent,EditorFileSystemDirect String path = p_dir->get_file_path(i); fitem->set_tooltip(0,path); fitem->set_metadata(0,path); - Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),"EditorIcons")?p_dir->get_file_type(i):String("Object")),"EditorIcons"); + Ref<Texture> icon = get_icon( (has_icon(p_dir->get_file_type(i),ei)?p_dir->get_file_type(i):ot),ei); fitem->set_icon(0,icon); fitem->set_cell_mode(1,TreeItem::CELL_MODE_RANGE); @@ -1372,6 +1372,8 @@ ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) { button_export = add_button("Export..",!OS::get_singleton()->get_swap_ok_cancel(),"export_pck"); updating_script=false; + ei="EditorIcons"; + ot="Object"; } diff --git a/tools/editor/project_export.h b/tools/editor/project_export.h index c88233ae01..d85e688e58 100644 --- a/tools/editor/project_export.h +++ b/tools/editor/project_export.h @@ -78,6 +78,9 @@ private: HBoxContainer *plat_errors; Label *platform_error_string; + StringName ei; + StringName ot; + Tree * tree; EditorFileDialog *pck_export; diff --git a/tools/editor/quick_open.cpp b/tools/editor/quick_open.cpp index 749318386c..6135a4ab64 100644 --- a/tools/editor/quick_open.cpp +++ b/tools/editor/quick_open.cpp @@ -30,8 +30,9 @@ #include "os/keyboard.h" -void EditorQuickOpen::popup(const String& p_base, bool p_dontclear) { +void EditorQuickOpen::popup(const StringName &p_base, bool p_dontclear, bool p_add_dirs) { + add_directories=p_add_dirs; popup_centered_ratio(0.6); if (p_dontclear) search_box->select_all(); @@ -66,27 +67,53 @@ void EditorQuickOpen::_sbox_input(const InputEvent& p_ie) { void EditorQuickOpen::_parse_fs(EditorFileSystemDirectory *efsd) { - for(int i=0;i<efsd->get_subdir_count();i++) { + if (!add_directories) { + for(int i=0;i<efsd->get_subdir_count();i++) { - _parse_fs(efsd->get_subdir(i)); + _parse_fs(efsd->get_subdir(i)); + } } + TreeItem *root = search_options->get_root(); + + if (add_directories) { + String path = efsd->get_path(); + if (!path.ends_with("/")) + path+="/"; + if (path!="res://") { + path=path.substr(6,path.length()); + if (path.findn(search_box->get_text())!=-1) { + TreeItem *ti = search_options->create_item(root); + ti->set_text(0,path); + Ref<Texture> icon = get_icon("folder","FileDialog"); + ti->set_icon(0,icon); + } + } + } for(int i=0;i<efsd->get_file_count();i++) { String file = efsd->get_file_path(i); file=file.substr(6,file.length()); if (ObjectTypeDB::is_type(efsd->get_file_type(i),base_type) && (search_box->get_text()=="" || file.findn(search_box->get_text())!=-1)) { - TreeItem *root = search_options->get_root(); TreeItem *ti = search_options->create_item(root); ti->set_text(0,file); - Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),"EditorIcons")?efsd->get_file_type(i):String("Object")),"EditorIcons"); + Ref<Texture> icon = get_icon( (has_icon(efsd->get_file_type(i),ei)?efsd->get_file_type(i):ot),ei); ti->set_icon(0,icon); if (root->get_children()==ti) ti->select(0); } } + + + if (add_directories) { + for(int i=0;i<efsd->get_subdir_count();i++) { + + _parse_fs(efsd->get_subdir(i)); + } + } + } void EditorQuickOpen::_update_search() { @@ -118,7 +145,7 @@ void EditorQuickOpen::_notification(int p_what) { } -String EditorQuickOpen::get_base_type() const { +StringName EditorQuickOpen::get_base_type() const { return base_type; } @@ -152,4 +179,7 @@ EditorQuickOpen::EditorQuickOpen() { set_hide_on_ok(false); search_options->connect("item_activated",this,"_confirmed"); search_options->set_hide_root(true); + ei="EditorIcons"; + ot="Object"; + add_directories=false; } diff --git a/tools/editor/quick_open.h b/tools/editor/quick_open.h index 63652a442a..8b38256d39 100644 --- a/tools/editor/quick_open.h +++ b/tools/editor/quick_open.h @@ -38,7 +38,11 @@ class EditorQuickOpen : public ConfirmationDialog { LineEdit *search_box; Tree *search_options; - String base_type; + StringName base_type; + StringName ei; + StringName ot; + bool add_directories; + void _update_search(); @@ -55,9 +59,9 @@ protected: static void _bind_methods(); public: - String get_base_type() const; + StringName get_base_type() const; - void popup(const String& p_base,bool p_dontclear=false); + void popup(const StringName& p_base,bool p_dontclear=false,bool p_add_dirs=false); EditorQuickOpen(); }; diff --git a/tools/editor/scenes_dock.cpp b/tools/editor/scenes_dock.cpp index 9153616775..7d9c5b24b2 100644 --- a/tools/editor/scenes_dock.cpp +++ b/tools/editor/scenes_dock.cpp @@ -35,15 +35,30 @@ #include "os/os.h" #include "editor_node.h" +#include "editor_settings.h" + bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir) { - String search_term = tree_filter->get_search_term(); - ScenesDockFilter::FilterOption file_filter = tree_filter->get_file_filter(); TreeItem *item = tree->create_item(p_parent); - item->set_text(0,p_dir->get_name()+"/"); + String dname=p_dir->get_name(); + if (dname=="") + dname="res://"; + + item->set_text(0,dname); item->set_icon(0,get_icon("Folder","EditorIcons")); - item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); + item->set_selectable(0,true); + String lpath = p_dir->get_path(); + if (lpath!="res://" && lpath.ends_with("/")) { + lpath=lpath.substr(0,lpath.length()-1); + } + item->set_metadata(0,lpath); + if (lpath==path) { + item->select(0); + } + + + //item->set_custom_bg_color(0,get_color("prop_subsection","Editor")); bool has_items=false; @@ -52,7 +67,7 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di if (_create_tree(item,p_dir->get_subdir(i))) has_items=true; } - +#if 0 for (int i=0;i<p_dir->get_file_count();i++) { String file_name = p_dir->get_file(i); @@ -89,13 +104,13 @@ bool ScenesDock::_create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_di has_items=true; } - - if (!has_items) { +#endif + /*if (!has_items) { memdelete(item); return false; - } + }*/ return true; } @@ -105,7 +120,28 @@ void ScenesDock::_update_tree() { tree->clear(); updating_tree=true; - _create_tree(NULL,EditorFileSystem::get_singleton()->get_filesystem()); + TreeItem *root = tree->create_item(); + TreeItem *favorites = tree->create_item(root); + favorites->set_icon(0, get_icon("Favorites","EditorIcons") ); + favorites->set_text(0,"Favorites:"); + favorites->set_selectable(0,false); + Vector<String> faves = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<faves.size();i++) { + if (!faves[i].begins_with("res://")) + continue; + + TreeItem *ti = tree->create_item(favorites); + String fv = faves[i]; + if (fv=="res://") + ti->set_text(0,"/"); + else + ti->set_text(0,faves[i].get_file()); + ti->set_icon(0,get_icon("Folder","EditorIcons")); + ti->set_selectable(0,true); + ti->set_metadata(0,faves[i]); + } + + _create_tree(root,EditorFileSystem::get_singleton()->get_filesystem()); updating_tree=false; } @@ -117,68 +153,192 @@ void ScenesDock::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { + if (initialized) + return; + initialized=false; - EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_update_tree"); + EditorFileSystem::get_singleton()->connect("filesystem_changed",this,"_fs_changed"); button_reload->set_icon( get_icon("Reload","EditorIcons")); button_favorite->set_icon( get_icon("Favorites","EditorIcons")); + button_fav_up->set_icon( get_icon("MoveUp","EditorIcons")); + button_fav_down->set_icon( get_icon("MoveDown","EditorIcons")); button_instance->set_icon( get_icon("Add","EditorIcons")); button_open->set_icon( get_icon("Folder","EditorIcons")); + button_back->set_icon( get_icon("Filesystem","EditorIcons")); + display_mode->set_icon( get_icon("FileList","EditorIcons")); + display_mode->connect("pressed",this,"_change_file_display"); + file_options->set_icon( get_icon("Tools","EditorIcons")); + files->connect("item_activated",this,"_select_file"); + button_hist_next->connect("pressed",this,"_fw_history"); + button_hist_prev->connect("pressed",this,"_bw_history"); - String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg"; - FileAccess *f=FileAccess::open(path,FileAccess::READ); - if (f) { + button_hist_next->set_icon( get_icon("Forward","EditorIcons")); + button_hist_prev->set_icon( get_icon("Back","EditorIcons")); + file_options->get_popup()->connect("item_pressed",this,"_file_option"); - String l = f->get_line(); - while(l!="") { - favorites.insert(l); - l = f->get_line(); - - } + button_back->connect("pressed",this,"_go_to_tree",varray(),CONNECT_DEFERRED); + current_path->connect("text_entered",this,"_go_to_dir"); + _update_tree(); //maybe it finished already - f->close(); - memdelete(f); + if (EditorFileSystem::get_singleton()->is_scanning()) { + _set_scannig_mode(); } - - - _update_tree(); //maybe it finished already + } break; + case NOTIFICATION_PROCESS: { + if (EditorFileSystem::get_singleton()->is_scanning()) { + scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); + } } break; case NOTIFICATION_EXIT_TREE: { } break; - case NOTIFICATION_PROCESS: { - } break; } } -void ScenesDock::_favorite_toggled() { - if (updating_tree) + + +void ScenesDock::_dir_selected() { + + TreeItem *ti = tree->get_selected(); + if (!ti) return; + String dir = ti->get_metadata(0); + bool found=false; + Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<favorites.size();i++) { + + if (favorites[i]==dir) { + found=true; + break; + } + } + + + button_favorite->set_pressed(found); + if (ti->get_parent() && ti->get_parent()->get_parent()==tree->get_root() && !ti->get_parent()->get_prev()) { + + //a favorite!!! + button_fav_up->set_disabled(!ti->get_prev()); + button_fav_down->set_disabled(!ti->get_next()); + } else { + button_fav_up->set_disabled(true); + button_fav_down->set_disabled(true); + + } +} + +void ScenesDock::_fav_up_pressed() { TreeItem *sel = tree->get_selected(); if (!sel) - return; //? + return ; - bool faved = sel->is_checked(0); - String path = sel->get_metadata(0); - if (faved) - favorites.insert(path); - else - favorites.erase(path); + if (!sel->get_prev()) + return; + + String sw = sel->get_prev()->get_metadata(0); + String txt = sel->get_metadata(0); + + Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs(); + + int a_idx=favorited.find(sw); + int b_idx=favorited.find(txt); + + if (a_idx==-1 || b_idx==-1) + return; + SWAP(favorited[a_idx],favorited[b_idx]); + + EditorSettings::get_singleton()->set_favorite_dirs(favorited); + + _update_tree(); - timer->start(); + if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children()) + return; + sel = tree->get_root()->get_children()->get_children(); + while(sel) { + String t = sel->get_metadata(0); + if (t==txt) { + sel->select(0); + return; + } + sel=sel->get_next(); + } } -void ScenesDock::_favorites_toggled(bool p_toggled) { +void ScenesDock::_fav_down_pressed() { + + TreeItem *sel = tree->get_selected(); + if (!sel) + return ; + + if (!sel->get_next()) + return; + + String sw = sel->get_next()->get_metadata(0); + String txt = sel->get_metadata(0); + + Vector<String> favorited = EditorSettings::get_singleton()->get_favorite_dirs(); + + int a_idx=favorited.find(sw); + int b_idx=favorited.find(txt); + + if (a_idx==-1 || b_idx==-1) + return; + SWAP(favorited[a_idx],favorited[b_idx]); + + EditorSettings::get_singleton()->set_favorite_dirs(favorited); _update_tree(); + + if (!tree->get_root() || !tree->get_root()->get_children() || !tree->get_root()->get_children()->get_children()) + return; + sel = tree->get_root()->get_children()->get_children(); + while(sel) { + + String t = sel->get_metadata(0); + if (t==txt) { + sel->select(0); + return; + } + sel=sel->get_next(); + } +} + +void ScenesDock::_favorites_pressed() { + + TreeItem *sel = tree->get_selected(); + if (!sel) + return ; + String dir = sel->get_metadata(0); + + int idx = -1; + Vector<String> favorites = EditorSettings::get_singleton()->get_favorite_dirs(); + for(int i=0;i<favorites.size();i++) { + + if (favorites[i]==dir) { + idx=i; + break; + } + } + + if (button_favorite->is_pressed() && idx==-1) { + favorites.push_back(dir); + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(); + } else if (!button_favorite->is_pressed() && idx!=-1) { + favorites.remove(idx); + EditorSettings::get_singleton()->set_favorite_dirs(favorites); + _update_tree(); + } + } String ScenesDock::get_selected_path() const { @@ -199,65 +359,712 @@ void ScenesDock::_instance_pressed() { emit_signal("instance",path); } -void ScenesDock::_open_pressed(){ +void ScenesDock::_thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata) { - TreeItem *sel = tree->get_selected(); - if (!sel) { + if (p_preview.is_valid() && path==p_path.get_base_dir()) { + + int idx=p_udata; + if (idx>=files->get_item_count()) + return; + String fpath = files->get_item_metadata(idx); + if (fpath!=p_path) + return; + files->set_item_icon(idx,p_preview); + + } + +} + +void ScenesDock::_change_file_display() { + + if (display_mode->is_pressed()) { + display_mode->set_icon( get_icon("FileThumbnail","EditorIcons")); + + } else { + display_mode->set_icon( get_icon("FileList","EditorIcons")); + } + + _update_files(true); +} + +void ScenesDock::_update_files(bool p_keep_selection) { + + Set<String> cselection; + + if (p_keep_selection) { + + for(int i=0;i<files->get_item_count();i++) { + + if (files->is_selected(i)) + cselection.insert(files->get_item_text(i)); + } + } + + files->clear(); + + EditorFileSystemDirectory *efd = EditorFileSystem::get_singleton()->get_path(path); + if (!efd) return; + + int thumbnail_size = EditorSettings::get_singleton()->get("file_dialog/thumbnail_size"); + Ref<Texture> folder_thumbnail; + Ref<Texture> file_thumbnail; + + bool use_thumbnails=!display_mode->is_pressed(); + + if (use_thumbnails) { //thumbnails + + files->set_max_columns(0); + files->set_icon_mode(ItemList::ICON_MODE_TOP); + files->set_fixed_column_width(thumbnail_size*3/2); + files->set_max_text_lines(2); + files->set_min_icon_size(Size2(thumbnail_size,thumbnail_size)); + + if (!has_icon("ResizedFolder","EditorIcons")) { + Ref<ImageTexture> folder = get_icon("FolderBig","EditorIcons"); + Image img = folder->get_data(); + img.resize(thumbnail_size,thumbnail_size); + Ref<ImageTexture> resized_folder = Ref<ImageTexture>( memnew( ImageTexture)); + resized_folder->create_from_image(img,0); + Theme::get_default()->set_icon("ResizedFolder","EditorIcons",resized_folder); + } + + folder_thumbnail = get_icon("ResizedFolder","EditorIcons"); + + if (!has_icon("ResizedFile","EditorIcons")) { + Ref<ImageTexture> file = get_icon("FileBig","EditorIcons"); + Image img = file->get_data(); + img.resize(thumbnail_size,thumbnail_size); + Ref<ImageTexture> resized_file = Ref<ImageTexture>( memnew( ImageTexture)); + resized_file->create_from_image(img,0); + Theme::get_default()->set_icon("ResizedFile","EditorIcons",resized_file); + } + + file_thumbnail = get_icon("ResizedFile","EditorIcons"); + + } else { + + files->set_icon_mode(ItemList::ICON_MODE_LEFT); + files->set_max_columns(1); + files->set_max_text_lines(1); + files->set_fixed_column_width(0); + files->set_min_icon_size(Size2()); + } - String path = sel->get_metadata(0); - if (ResourceLoader::get_resource_type(path)=="PackedScene") { - editor->open_request(path); + if (path!="res://") { + + if (use_thumbnails) { + files->add_item("..",folder_thumbnail,true); + } else { + files->add_item("..",get_icon("folder","FileDialog"),true); + } + + String bd = path.get_base_dir(); + if (bd!="res://" && !bd.ends_with("/")) + bd+="/"; + + files->set_item_metadata(files->get_item_count()-1,bd); + } + + for(int i=0;i<efd->get_subdir_count();i++) { + + String dname=efd->get_subdir(i)->get_name(); + + + if (use_thumbnails) { + files->add_item(dname,folder_thumbnail,true); + } else { + files->add_item(dname,get_icon("folder","FileDialog"),true); + } + + files->set_item_metadata(files->get_item_count()-1,path.plus_file(dname)+"/"); + + if (cselection.has(dname)) + files->select(files->get_item_count()-1,false); + } + + for(int i=0;i<efd->get_file_count();i++) { + + String fname=efd->get_file(i); + String fp = path.plus_file(fname); + + + String type = efd->get_file_type(i); + Ref<Texture> type_icon; + + if (has_icon(type,"EditorIcons")) { + type_icon=get_icon(type,"EditorIcons"); + } else { + type_icon=get_icon("Object","EditorIcons"); + } + + if (use_thumbnails) { + files->add_item(fname,file_thumbnail,true); + files->set_item_metadata(files->get_item_count()-1,fp); + files->set_item_tag_icon(files->get_item_count()-1,type_icon); + EditorResourcePreview::get_singleton()->queue_resource_preview(fp,this,"_thumbnail_done",files->get_item_count()-1); + } else { + files->add_item(fname,type_icon,true); + files->set_item_metadata(files->get_item_count()-1,fp); + + } + + if (cselection.has(fname)) + files->select(files->get_item_count()-1,false); + + } + + +} + +void ScenesDock::_select_file(int p_idx) { + + files->select(p_idx,true); + _open_pressed(); +} + +void ScenesDock::_go_to_tree() { + + tree->show(); + files->hide(); + path_hb->hide(); + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + button_favorite->show(); + button_fav_up->show(); + button_fav_down->show(); + button_open->hide(); + button_instance->hide(); + button_open->hide(); + file_options->hide(); + tree_mode=true; +} + +void ScenesDock::_go_to_dir(const String& p_dir){ + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->change_dir(p_dir)==OK) { + path=da->get_current_dir(); + _update_files(false); + } + current_path->set_text(path); + memdelete(da); + + +} +void ScenesDock::_fs_changed() { + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + scanning_vb->hide(); + + if (tree_mode) { + + tree->show(); + button_favorite->show(); + button_fav_up->show(); + button_fav_down->show(); + _update_tree(); + } else { + files->show(); + path_hb->show(); + button_instance->show(); + button_open->show(); + file_options->show(); + _update_files(true); + } + + set_process(false); +} + +void ScenesDock::_set_scannig_mode() { + + tree->hide(); + button_favorite->hide(); + button_fav_up->hide(); + button_fav_down->hide(); + button_instance->hide(); + button_open->hide(); + file_options->hide(); + button_hist_prev->set_disabled(true); + button_hist_next->set_disabled(true); + scanning_vb->show(); + path_hb->hide(); + files->hide(); + set_process(true); + if (EditorFileSystem::get_singleton()->is_scanning()) { + scanning_progress->set_val(EditorFileSystem::get_singleton()->get_scanning_progress()*100); + } else { + scanning_progress->set_val(0); + } + +} + +void ScenesDock::_fw_history() { + + if (history_pos<history.size()-1) + history_pos++; + + path=history[history_pos]; + + if (tree_mode) { + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + } else { + _update_files(false); + current_path->set_text(path); + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + +void ScenesDock::_bw_history() { + + if (history_pos>0) + history_pos--; + + path=history[history_pos]; + + if (tree_mode) { + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); } else { + _update_files(false); + current_path->set_text(path); + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + +void ScenesDock::_push_to_history() { - /* + history.resize(history_pos+1); + if (history[history_pos]!=path) { + history.push_back(path); + history_pos++; + } + + button_hist_prev->set_disabled(history_pos==0); + button_hist_next->set_disabled(history_pos+1==history.size()); + +} + + +void ScenesDock::_find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files) { - RES res = ResourceLoader::load(path); - if (res.is_null()) { + for(int i=0;i<efsd->get_subdir_count();i++) { + _find_inside_move_files(efsd->get_subdir(i),files); + } + for(int i=0;i<efsd->get_file_count();i++) { + files.push_back(efsd->get_file_path(i)); + } + +} +void ScenesDock::_find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps) { + for(int i=0;i<efsd->get_subdir_count();i++) { + _find_remaps(efsd->get_subdir(i),renames,to_remaps); + } + for(int i=0;i<efsd->get_file_count();i++) { + Vector<String> deps=efsd->get_file_deps(i); + for(int j=0;j<deps.size();j++) { + if (renames.has(deps[j])) { + to_remaps.push_back(efsd->get_file_path(i)); + break; + } + } + } +} + + +void ScenesDock::_rename_operation(const String& p_to_path) { + + if (move_files[0]==p_to_path) { + EditorNode::get_singleton()->show_warning("Same source and destination files, doing nothing."); + return; + } + if (FileAccess::exists(p_to_path)) { + EditorNode::get_singleton()->show_warning("Target file exists, can't overwrite. Delete first."); + return; + } + + Map<String,String> renames; + renames[move_files[0]]=p_to_path; + + List<String> remap; + + _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap); + print_line("found files to remap: "+itos(remap.size())); + + //perform remaps + for(List<String>::Element *E=remap.front();E;E=E->next()) { + + Error err = ResourceLoader::rename_dependencies(E->get(),renames); + print_line("remapping: "+E->get()); + + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n"); + } + } + + //finally, perform moves + + DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES); + + Error err = da->rename(move_files[0],p_to_path); + print_line("moving file "+move_files[0]+" to "+p_to_path); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[0]+"\n"); + } + + //rescan everything + memdelete(da); + print_line("call rescan!"); + _rescan(); +} + + +void ScenesDock::_move_operation(const String& p_to_path) { + + if (p_to_path==path) { + EditorNode::get_singleton()->show_warning("Same source and destination paths, doing nothing."); + return; + } + + //find files inside dirs to be moved + + Vector<String> inside_files; + + for(int i=0;i<move_dirs.size();i++) { + if (p_to_path.begins_with(move_dirs[i])) { + EditorNode::get_singleton()->show_warning("Can't move directories to within themselves"); return; - }*/ + } - editor->load_resource(path); + EditorFileSystemDirectory *efsd=EditorFileSystem::get_singleton()->get_path(move_dirs[i]); + if (!efsd) + continue; + _find_inside_move_files(efsd,inside_files); } -// emit_signal("open",path); + //make list of remaps + Map<String,String> renames; + String repfrom=path=="res://"?path:String(path+"/"); + String repto=p_to_path=="res://"?p_to_path:String(p_to_path+"/"); + + for(int i=0;i<move_files.size();i++) { + renames[move_files[i]]=move_files[i].replace_first(repfrom,repto); + print_line("move file "+move_files[i]+" -> "+renames[move_files[i]]); + } + for(int i=0;i<inside_files.size();i++) { + renames[inside_files[i]]=inside_files[i].replace_first(repfrom,repto); + print_line("inside file "+inside_files[i]+" -> "+renames[inside_files[i]]); + } + + //make list of files that will be run the remapping + List<String> remap; + _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(),renames,remap); + print_line("found files to remap: "+itos(remap.size())); + + //perform remaps + for(List<String>::Element *E=remap.front();E;E=E->next()) { + + Error err = ResourceLoader::rename_dependencies(E->get(),renames); + print_line("remapping: "+E->get()); + + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Can't rename deps for:\n"+E->get()+"\n"); + } + } + + //finally, perform moves + + DirAccess *da=DirAccess::create(DirAccess::ACCESS_RESOURCES); + + for(int i=0;i<move_files.size();i++) { + + String to = move_files[i].replace_first(repfrom,repto); + Error err = da->rename(move_files[i],to); + print_line("moving file "+move_files[i]+" to "+to); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving file:\n"+move_files[i]+"\n"); + } + } + + for(int i=0;i<move_dirs.size();i++) { + + String to = p_to_path.plus_file(move_dirs[i].get_file()); + Error err = da->rename(move_dirs[i],to); + print_line("moving dir "+move_dirs[i]+" to "+to); + if (err!=OK) { + EditorNode::get_singleton()->add_io_error("Error moving dir:\n"+move_dirs[i]+"\n"); + } + } + + memdelete(da); + //rescan everything + print_line("call rescan!"); + _rescan(); + +} + +void ScenesDock::_file_option(int p_option) { + + switch(p_option) { + + case FILE_DEPENDENCIES: { + + int idx = files->get_current(); + if (idx<0 || idx>=files->get_item_count()) + break; + String path = files->get_item_metadata(idx); + deps_editor->edit(path); + } break; + case FILE_OWNERS: { + + int idx = files->get_current(); + if (idx<0 || idx>=files->get_item_count()) + break; + String path = files->get_item_metadata(idx); + owners_editor->show(path); + } break; + case FILE_MOVE: { + + move_dirs.clear();; + move_files.clear(); + + for(int i=0;i<files->get_item_count();i++) { + + String path = files->get_item_metadata(i); + if (!files->is_selected(i)) + continue; + + if (files->get_item_text(i)=="..") { + EditorNode::get_singleton()->show_warning("Can't operate on '..'"); + return; + } + + if (path.ends_with("/")) { + move_dirs.push_back(path.substr(0,path.length()-1)); + } else { + move_files.push_back(path); + } + } + + + if (move_dirs.empty() && move_files.size()==1) { + + rename_dialog->clear_filters(); + rename_dialog->add_filter("*."+move_files[0].extension()); + rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + rename_dialog->set_current_path(move_files[0]); + rename_dialog->popup_centered_ratio(); + rename_dialog->set_title("Pick New Name and Location For: "+move_files[0].get_file()); + + + } else { + //just move + move_dialog->popup_centered_ratio(); + } + + + } break; + case FILE_REMOVE: { + + Vector<String> torem; + + for(int i=0;i<files->get_item_count();i++) { + + String path = files->get_item_metadata(i); + if (path.ends_with("/") || !files->is_selected(i)) + continue; + torem.push_back(path); + } + + if (torem.empty()) { + EditorNode::get_singleton()->show_warning("No files selected!"); + break; + } + + remove_dialog->show(torem); + //1) find if used + //2) warn + + } break; + case FILE_INFO: { + + } break; + + } } -void ScenesDock::_save_favorites() { +void ScenesDock::_open_pressed(){ + + + if (tree_mode) { + + TreeItem *sel = tree->get_selected(); + if (!sel) { + return; + } + path = sel->get_metadata(0); + /*if (path!="res://" && path.ends_with("/")) { + path=path.substr(0,path.length()-1); + }*/ + + tree_mode=false; + + tree->hide(); + files->show(); + path_hb->show(); + button_favorite->hide(); + button_fav_up->hide(); + button_fav_down->hide(); + button_instance->show(); + button_open->show(); + file_options->show(); + + _update_files(false); - String path = Globals::get_singleton()->get_resource_path()+"/favorites.cfg"; - FileAccess *f=FileAccess::open(path,FileAccess::WRITE); - ERR_FAIL_COND(!f); - for(Set<String>::Element *E=favorites.front();E;E=E->next() ) { + current_path->set_text(path); - CharString utf8f = E->get().utf8(); - f->store_buffer((const uint8_t*)utf8f.get_data(),utf8f.length()); - f->store_8('\n'); + _push_to_history(); + + + } else { + + int idx=-1; + for(int i=0;i<files->get_item_count();i++) { + if (files->is_selected(i)) { + idx=i; + break; + } + } + + if (idx<0) + return; + + + + String path = files->get_item_metadata(idx); + + if (path.ends_with("/")) { + if (path!="res://") { + path=path.substr(0,path.length()-1); + } + this->path=path; + _update_files(false); + current_path->set_text(path); + _push_to_history(); + } else { + + if (ResourceLoader::get_resource_type(path)=="PackedScene") { + + editor->open_request(path); + } else { + + editor->load_resource(path); + } + } } - f->close(); - memdelete(f); +// emit_signal("open",path); + } + void ScenesDock::_rescan() { + _set_scannig_mode(); EditorFileSystem::get_singleton()->scan(); + +} + +void ScenesDock::fix_dependencies(const String& p_for_file) { + deps_editor->edit(p_for_file); +} + +void ScenesDock::open(const String& p_path) { + + + String npath; + String nfile; + + if (p_path.ends_with("/")) { + + if (p_path!="res://") + npath=p_path.substr(0,p_path.length()-1); + else + npath="res://"; + } else { + nfile=p_path.get_file(); + npath=p_path.get_base_dir(); + } + + path=npath; + + if (tree_mode && nfile=="") { + _update_tree(); + tree->grab_focus(); + tree->call_deferred("ensure_cursor_is_visible"); + _push_to_history(); + return; + } else if (tree_mode){ + _update_tree(); + tree->grab_focus(); + tree->ensure_cursor_is_visible(); + _open_pressed(); + current_path->set_text(path); + } else { + _update_files(false); + _push_to_history(); + } + + for(int i=0;i<files->get_item_count();i++) { + + String md = files->get_item_metadata(i); + if (md==p_path) { + files->select(i,true); + files->ensure_current_is_visible(); + break; + } + } + } void ScenesDock::_bind_methods() { ObjectTypeDB::bind_method(_MD("_update_tree"),&ScenesDock::_update_tree); ObjectTypeDB::bind_method(_MD("_rescan"),&ScenesDock::_rescan); - ObjectTypeDB::bind_method(_MD("_favorites_toggled"),&ScenesDock::_favorites_toggled); - ObjectTypeDB::bind_method(_MD("_favorite_toggled"),&ScenesDock::_favorite_toggled); + ObjectTypeDB::bind_method(_MD("_favorites_pressed"),&ScenesDock::_favorites_pressed); ObjectTypeDB::bind_method(_MD("_instance_pressed"),&ScenesDock::_instance_pressed); ObjectTypeDB::bind_method(_MD("_open_pressed"),&ScenesDock::_open_pressed); - ObjectTypeDB::bind_method(_MD("_save_favorites"),&ScenesDock::_save_favorites); + + ObjectTypeDB::bind_method(_MD("_thumbnail_done"),&ScenesDock::_thumbnail_done); + ObjectTypeDB::bind_method(_MD("_select_file"), &ScenesDock::_select_file); + ObjectTypeDB::bind_method(_MD("_go_to_tree"), &ScenesDock::_go_to_tree); + ObjectTypeDB::bind_method(_MD("_go_to_dir"), &ScenesDock::_go_to_dir); + ObjectTypeDB::bind_method(_MD("_change_file_display"), &ScenesDock::_change_file_display); + ObjectTypeDB::bind_method(_MD("_fw_history"), &ScenesDock::_fw_history); + ObjectTypeDB::bind_method(_MD("_bw_history"), &ScenesDock::_bw_history); + ObjectTypeDB::bind_method(_MD("_fs_changed"), &ScenesDock::_fs_changed); + ObjectTypeDB::bind_method(_MD("_dir_selected"), &ScenesDock::_dir_selected); + ObjectTypeDB::bind_method(_MD("_fav_up_pressed"), &ScenesDock::_fav_up_pressed); + ObjectTypeDB::bind_method(_MD("_fav_down_pressed"), &ScenesDock::_fav_down_pressed); + ObjectTypeDB::bind_method(_MD("_file_option"), &ScenesDock::_file_option); + ObjectTypeDB::bind_method(_MD("_move_operation"), &ScenesDock::_move_operation); + ObjectTypeDB::bind_method(_MD("_rename_operation"), &ScenesDock::_rename_operation); ADD_SIGNAL(MethodInfo("instance")); ADD_SIGNAL(MethodInfo("open")); @@ -271,153 +1078,156 @@ ScenesDock::ScenesDock(EditorNode *p_editor) { HBoxContainer *toolbar_hbc = memnew( HBoxContainer ); add_child(toolbar_hbc); + button_hist_prev = memnew( ToolButton ); + toolbar_hbc->add_child(button_hist_prev); + button_hist_prev->set_disabled(true); + button_hist_prev->set_tooltip("Previous Directory"); + + button_hist_next = memnew( ToolButton ); + toolbar_hbc->add_child(button_hist_next); + button_hist_next->set_disabled(true); + button_hist_prev->set_focus_mode(FOCUS_NONE); + button_hist_next->set_focus_mode(FOCUS_NONE); + button_hist_next->set_tooltip("Next Directory"); + button_reload = memnew( Button ); button_reload->set_flat(true); button_reload->connect("pressed",this,"_rescan"); toolbar_hbc->add_child(button_reload); + button_reload->set_focus_mode(FOCUS_NONE); + button_reload->set_tooltip("Re-Scan Filesystem"); + + toolbar_hbc->add_spacer(); + + button_fav_up = memnew( ToolButton ); + button_fav_up->set_flat(true); + toolbar_hbc->add_child(button_fav_up); + button_fav_up->set_disabled(true); + button_fav_up->connect("pressed",this,"_fav_up_pressed"); + button_fav_up->set_tooltip("Move Favorite Up"); + + button_fav_down = memnew( ToolButton ); + button_fav_down->set_flat(true); + toolbar_hbc->add_child(button_fav_down); + button_fav_down->set_disabled(true); + button_fav_down->connect("pressed",this,"_fav_down_pressed"); + button_fav_down->set_tooltip("Move Favorite Down"); button_favorite = memnew( Button ); button_favorite->set_flat(true); button_favorite->set_toggle_mode(true); - button_favorite->connect("toggled",this,"_favorites_toggled"); + button_favorite->connect("pressed",this,"_favorites_pressed"); toolbar_hbc->add_child(button_favorite); + button_favorite->set_tooltip("Toggle folder status as Favorite"); + + button_favorite->set_focus_mode(FOCUS_NONE); + button_fav_up->set_focus_mode(FOCUS_NONE); + button_fav_down->set_focus_mode(FOCUS_NONE); - toolbar_hbc->add_spacer(); button_open = memnew( Button ); button_open->set_flat(true); button_open->connect("pressed",this,"_open_pressed"); toolbar_hbc->add_child(button_open); + button_open->hide(); + button_open->set_focus_mode(FOCUS_NONE); + button_open->set_tooltip("Open the selected file.\nOpen as scene if a scene, or as resource otherwise."); + button_instance = memnew( Button ); button_instance->set_flat(true); button_instance->connect("pressed",this,"_instance_pressed"); toolbar_hbc->add_child(button_instance); + button_instance->hide(); + button_instance->set_focus_mode(FOCUS_NONE); + button_instance->set_tooltip("Instance the selected scene(s) as child of the selected node."); + + + file_options = memnew( MenuButton ); + toolbar_hbc->add_child(file_options); + file_options->get_popup()->add_item("Rename or Move",FILE_MOVE); + file_options->get_popup()->add_item("Delete",FILE_REMOVE); + file_options->get_popup()->add_separator(); + file_options->get_popup()->add_item("Edit Dependencies",FILE_DEPENDENCIES); + file_options->get_popup()->add_item("View Owners",FILE_OWNERS); + //file_options->get_popup()->add_item("Info",FILE_INFO); + file_options->hide(); + file_options->set_focus_mode(FOCUS_NONE); + file_options->set_tooltip("Miscenaneous options related to resources on disk."); tree = memnew( Tree ); - tree_filter=memnew( ScenesDockFilter() ); - tree_filter->connect("filter_changed", this, "_update_tree"); - add_child(tree_filter); + + tree->set_hide_root(true); add_child(tree); + tree->set_v_size_flags(SIZE_EXPAND_FILL); tree->connect("item_edited",this,"_favorite_toggled"); tree->connect("item_activated",this,"_open_pressed"); - - timer = memnew( Timer ); - timer->set_one_shot(true); - timer->set_wait_time(2); - timer->connect("timeout",this,"_save_favorites"); - add_child(timer); - + tree->connect("cell_selected",this,"_dir_selected"); + + files = memnew( ItemList ); + files->set_v_size_flags(SIZE_EXPAND_FILL); + files->set_select_mode(ItemList::SELECT_MULTI); + + path_hb = memnew( HBoxContainer ); + button_back = memnew( ToolButton ); + path_hb->add_child(button_back); + current_path=memnew( LineEdit ); + current_path->set_h_size_flags(SIZE_EXPAND_FILL); + path_hb->add_child(current_path); + display_mode = memnew( ToolButton ); + path_hb->add_child(display_mode); + display_mode->set_toggle_mode(true); + add_child(path_hb); + path_hb->hide(); + + + add_child(files); + files->hide(); + + scanning_vb = memnew( VBoxContainer ); + Label *slabel = memnew( Label ); + slabel->set_text("Scanning Files,\nPlease Wait.."); + slabel->set_align(Label::ALIGN_CENTER); + scanning_vb->add_child(slabel); + scanning_progress = memnew( ProgressBar ); + scanning_vb->add_child(scanning_progress); + add_child(scanning_vb); + scanning_vb->hide(); + + + + deps_editor = memnew( DependencyEditor ); + add_child(deps_editor); + + owners_editor = memnew( DependencyEditorOwners); + add_child(owners_editor); + + remove_dialog = memnew( DependencyRemoveDialog); + add_child(remove_dialog); + + move_dialog = memnew( EditorDirDialog ); + add_child(move_dialog); + move_dialog->connect("dir_selected",this,"_move_operation"); + move_dialog->get_ok()->set_text("Move"); + + rename_dialog = memnew( EditorFileDialog ); + rename_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + rename_dialog->connect("file_selected",this,"_rename_operation"); + add_child(rename_dialog); updating_tree=false; + initialized=false; -} - -ScenesDock::~ScenesDock() { - -} - -void ScenesDockFilter::_setup_filters() { - - filter_option->clear(); - filter_option->add_item("Path"); - filter_option->add_item("Name"); - filter_option->add_item("Folder"); -#if 0 - List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type("",&extensions); - - file_filter->add_item("All Files (*)"); - filters.push_back("*"); - - List<String> filter_texts; - for(int i=0;i<extensions.size();i++) { - filter_texts.push_back("*."+extensions[i]+" ; "+extensions[i].to_upper()); - filters.push_back(extensions[i]); - } - for(int i=0;i<filter_texts.size();i++) { - - String flt=filter_texts[i].get_slice(";",0).strip_edges(); - String desc=filter_texts[i].get_slice(";",1).strip_edges(); - if (desc.length()) - file_filter->add_item(desc+" ( "+flt+" )"); - else - file_filter->add_item("( "+flt+" )"); - } -#endif -} - -void ScenesDockFilter::_command(int p_command) { - switch (p_command) { - - case CMD_CLEAR_FILTER: { - if (search_box->get_text()!="") { - search_box->clear(); - emit_signal("filter_changed"); - } - }break; - } -} - -void ScenesDockFilter::_search_text_changed(const String &p_newtext) { - emit_signal("filter_changed"); -} - -String ScenesDockFilter::get_search_term() { - return search_box->get_text().strip_edges(); -} - -ScenesDockFilter::FilterOption ScenesDockFilter::get_file_filter() { - return _current_filter; -} - -void ScenesDockFilter::_file_filter_selected(int p_idx) { - FilterOption selected = (FilterOption)(filter_option->get_selected()); - if (_current_filter != selected ) { - _current_filter = selected; - emit_signal("filter_changed"); - } -} - -void ScenesDockFilter::_notification(int p_what) { - switch(p_what) { - case NOTIFICATION_ENTER_TREE: { - clear_search_button->set_icon(get_icon("CloseHover","EditorIcons")); - } break; - } -} - -void ScenesDockFilter::_bind_methods() { + history.push_back("res://"); + history_pos=0; + tree_mode=true; - ObjectTypeDB::bind_method(_MD("_command"),&ScenesDockFilter::_command); - ObjectTypeDB::bind_method(_MD("_search_text_changed"), &ScenesDockFilter::_search_text_changed); - ObjectTypeDB::bind_method(_MD("_file_filter_selected"), &ScenesDockFilter::_file_filter_selected); - ADD_SIGNAL( MethodInfo("filter_changed") ); } -ScenesDockFilter::ScenesDockFilter() { - - _current_filter = FILTER_PATH; - - filter_option = memnew( OptionButton ); - filter_option->set_custom_minimum_size(Size2(60,10)); - filter_option->set_clip_text(true); - filter_option->connect("item_selected", this, "_file_filter_selected"); - add_child(filter_option); - - _setup_filters(); - - search_box = memnew( LineEdit ); - search_box->connect("text_changed",this,"_search_text_changed"); - search_box->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(search_box); - - clear_search_button = memnew( ToolButton ); - clear_search_button->connect("pressed",this,"_command",make_binds(CMD_CLEAR_FILTER)); - add_child(clear_search_button); +ScenesDock::~ScenesDock() { } diff --git a/tools/editor/scenes_dock.h b/tools/editor/scenes_dock.h index de7ab51edc..d045124bf7 100644 --- a/tools/editor/scenes_dock.h +++ b/tools/editor/scenes_dock.h @@ -36,40 +36,112 @@ #include "scene/gui/tool_button.h" #include "scene/gui/option_button.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/item_list.h" +#include "scene/gui/progress_bar.h" + #include "os/dir_access.h" #include "os/thread.h" #include "editor_file_system.h" - +#include "editor_dir_dialog.h" +#include "dependency_editor.h" class EditorNode; -class ScenesDockFilter; + class ScenesDock : public VBoxContainer { OBJ_TYPE( ScenesDock, VBoxContainer ); + enum FileMenu { + FILE_DEPENDENCIES, + FILE_OWNERS, + FILE_MOVE, + FILE_REMOVE, + FILE_REIMPORT, + FILE_INFO + }; + + + VBoxContainer *scanning_vb; + ProgressBar *scanning_progress; + EditorNode *editor; Set<String> favorites; Button *button_reload; Button *button_instance; Button *button_favorite; + Button *button_fav_up; + Button *button_fav_down; Button *button_open; - Timer *timer; + Button *button_back; + Button *display_mode; + Button *button_hist_next; + Button *button_hist_prev; + LineEdit *current_path; + HBoxContainer *path_hb; + + MenuButton *file_options; + + + DependencyEditor *deps_editor; + DependencyEditorOwners *owners_editor; + DependencyRemoveDialog *remove_dialog; + + EditorDirDialog *move_dialog; + EditorFileDialog *rename_dialog; - ScenesDockFilter *tree_filter; + Vector<String> move_dirs; + Vector<String> move_files; + + + Vector<String> history; + int history_pos; + + String path; + + bool initialized; bool updating_tree; - Tree * tree; + Tree * tree; //directories + ItemList *files; + + bool tree_mode; + + void _go_to_tree(); + void _go_to_dir(const String& p_dir); + void _select_file(int p_idx); + bool _create_tree(TreeItem *p_parent,EditorFileSystemDirectory *p_dir); + void _thumbnail_done(const String& p_path,const Ref<Texture>& p_preview, const Variant& p_udata); + void _find_inside_move_files(EditorFileSystemDirectory *efsd,Vector<String>& files); + void _find_remaps(EditorFileSystemDirectory *efsd,Map<String,String> &renames,List<String>& to_remaps); + + void _rename_operation(const String& p_to_path); + void _move_operation(const String& p_to_path); + + + void _file_option(int p_option); + void _update_files(bool p_keep_selection); + void _change_file_display(); + void _fs_changed(); + void _fw_history(); + void _bw_history(); + void _push_to_history(); + + void _fav_up_pressed(); + void _fav_down_pressed(); + void _dir_selected(); void _update_tree(); void _rescan(); - void _favorites_toggled(bool); - void _favorite_toggled(); + void _set_scannig_mode(); + + void _favorites_pressed(); void _instance_pressed(); void _open_pressed(); - void _save_favorites(); + protected: void _notification(int p_what); @@ -77,48 +149,14 @@ protected: public: String get_selected_path() const; + void open(const String& p_path); + + void fix_dependencies(const String& p_for_file); + ScenesDock(EditorNode *p_editor); ~ScenesDock(); }; -class ScenesDockFilter : public HBoxContainer { - - OBJ_TYPE( ScenesDockFilter, HBoxContainer ); - -private: - friend class ScenesDock; - - enum Command { - CMD_CLEAR_FILTER, - }; - - Tree *tree; - OptionButton *filter_option; - LineEdit *search_box; - ToolButton *clear_search_button; - - enum FilterOption { - FILTER_PATH, // NAME or Folder - FILTER_NAME, - FILTER_FOLDER, - }; - FilterOption _current_filter; - //Vector<String> filters; - - void _command(int p_command); - void _search_text_changed(const String& p_newtext); - void _setup_filters(); - void _file_filter_selected(int p_idx); - -protected: - void _notification(int p_what); - static void _bind_methods(); - -public: - String get_search_term(); - FilterOption get_file_filter(); - ScenesDockFilter(); -}; #endif // SCENES_DOCK_H diff --git a/version.py b/version.py index c723dd2935..284bda9520 100644 --- a/version.py +++ b/version.py @@ -1,7 +1,8 @@ short_name="godot" name="Godot Engine" -major=1 -minor=1 -status="stable" +major=2 +minor=0 +status="alpha" + |