Remove .gitignore do nothing is ignored.
[synfig.git] / synfig-core / trunk / src / synfig / loadcanvas.cpp
index cf01a8c..3da37e9 100644 (file)
@@ -7,6 +7,7 @@
 **     \legal
 **     Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley
 **     Copyright (c) 2007, 2008 Chris Moore
+**     Copyright (c) 2009 Carlos A. Sosa Navarro
 **
 **     This package is free software; you can redistribute it and/or
 **     modify it under the terms of the GNU General Public License as
@@ -39,6 +40,7 @@
 #include <stdexcept>
 #include <iostream>
 
+#include "layer_pastecanvas.h"
 #include "loadcanvas.h"
 #include "valuenode.h"
 #include "valuenode_subtract.h"
@@ -92,6 +94,8 @@ test_class test_class_instance;
 
 inline bool is_whitespace(char x) { return ((x)=='\n' || (x)=='\t' || (x)==' '); }
 
+std::set<String> CanvasParser::loading_;
+
 /* === P R O C E D U R E S ================================================= */
 
 static std::map<String, Canvas::LooseHandle>* open_canvas_map_(0);
@@ -121,19 +125,44 @@ static void _canvas_file_name_changed(Canvas *x)
 }
 
 Canvas::Handle
-synfig::open_canvas(const String &filename,String &errors)
+synfig::open_canvas(const String &filename,String &errors,String &warnings)
 {
-       return open_canvas_as(filename, filename, errors);
+       return open_canvas_as(filename, filename, errors, warnings);
 }
 
 Canvas::Handle
-synfig::open_canvas_as(const String &filename,const String &as,String &errors)
+synfig::open_canvas_as(const String &filename,const String &as,String &errors,String &warnings)
 {
-       CanvasParser parser;
+       if (CanvasParser::loading_.count(filename))
+       {
+               String warning(strprintf(_("cannot load '%s' recursively"), filename.c_str()));
+               synfig::warning(warning);
+               warnings = "  * " + warning + "\n";
+               Canvas::Handle canvas(Canvas::create());
+               canvas->set_file_name(filename);
+               Layer::Handle paste(Layer_PasteCanvas::create());
+               canvas->push_back(paste);
+               paste->set_description(warning);
+               return canvas;
+       }
 
+       Canvas::Handle canvas;
+       CanvasParser parser;
        parser.set_allow_errors(true);
 
-       Canvas::Handle canvas=parser.parse_from_file_as(filename,as,errors);
+       try
+       {
+               CanvasParser::loading_.insert(filename);
+               canvas=parser.parse_from_file_as(filename,as,errors);
+       }
+       catch (...)
+       {
+               CanvasParser::loading_.erase(filename);
+               throw;
+       }
+       CanvasParser::loading_.erase(filename);
+
+       warnings = parser.get_warnings_text();
 
        if(parser.error_count())
        {
@@ -161,10 +190,13 @@ CanvasParser::error_unexpected_element(xmlpp::Node *element,const String &got)
 void
 CanvasParser::warning(xmlpp::Node *element, const String &text)
 {
-       string str=strprintf("%s:<%s>:%d: warning: ",filename.c_str(),element->get_name().c_str(),element->get_line())+text;
-       //synfig::warning(str);
-       cerr<<str<<endl;
+       string str=strprintf("%s:<%s>:%d: ",filename.c_str(),element->get_name().c_str(),element->get_line())+text;
+
+       synfig::warning(str);
+       // cerr<<str<<endl;
+
        total_warnings_++;
+       warnings_text += "  * " + str + "\n";
        if(total_warnings_>=max_warnings_)
                fatal_error(element, _("Too many warnings"));
 }
@@ -908,7 +940,11 @@ CanvasParser::parse_animated(xmlpp::Element *element,Canvas::Handle canvas)
                                //        <waypoint time="0s" use="mycanvas"/>
                                //      </animated>
                                if (type==ValueBase::TYPE_CANVAS)
-                                       waypoint_value_node=ValueNode_Const::create(canvas->surefind_canvas(child->get_attribute("use")->get_value()));
+                               {
+                                       String warnings;
+                                       waypoint_value_node=ValueNode_Const::create(canvas->surefind_canvas(child->get_attribute("use")->get_value(), warnings));
+                                       warnings_text += warnings;
+                               }
                                else
                                        waypoint_value_node=canvas->surefind_value_node(child->get_attribute("use")->get_value());
                        }
@@ -1040,7 +1076,7 @@ CanvasParser::parse_animated(xmlpp::Element *element,Canvas::Handle canvas)
        // when loading a version 0.1 canvas, modify constant angle
        // waypoints to that they are within 180 degrees of the previous
        // waypoint's value
-       if (type == ValueBase::TYPE_ANGLE) 
+       if (type == ValueBase::TYPE_ANGLE)
        {
                if (canvas->get_version() == "0.1")
                {
@@ -1284,6 +1320,12 @@ CanvasParser::parse_linkable_value_node(xmlpp::Element *element,Canvas::Handle c
                                value_node->link_name(i) == "loop")
                                continue;
 
+                       // 'loop' was added while canvas version 0.6 was in use; the 'random' node was added back when 0.1 was in use
+                       if ((version == "0.1" || version == "0.2" || version == "0.3" || version == "0.4" || version == "0.5" || version == "0.6") &&
+                               element->get_name() == "random" &&
+                               value_node->link_name(i) == "loop")
+                               continue;
+
                        error(element, strprintf(_("<%s> is missing link %d (%s)"),
                                                                         element->get_name().c_str(),
                                                                         i,
@@ -1718,7 +1760,11 @@ CanvasParser::parse_layer(xmlpp::Element *element,Canvas::Handle canvas)
                                        error(child,_("Empty use=\"\" value in <param>"));
                                else if(layer->get_param(param_name).get_type()==ValueBase::TYPE_CANVAS)
                                {
-                                       if(!layer->set_param(param_name,canvas->surefind_canvas(str)))
+                                       String warnings;
+                                       Canvas::Handle c(canvas->surefind_canvas(str, warnings));
+                                       warnings_text += warnings;
+                                       if(!c) error((*iter),strprintf(_("Failed to load subcanvas '%s'"), str.c_str()));
+                                       if(!layer->set_param(param_name,c))
                                                error((*iter),_("Layer rejected canvas link"));
                                }
                                else
@@ -1830,7 +1876,9 @@ CanvasParser::parse_canvas(xmlpp::Element *element,Canvas::Handle parent,bool in
                {
                        try
                        {
-                               canvas=parent->find_canvas(element->get_attribute("id")->get_value());
+                               String warnings;
+                               canvas=parent->find_canvas(element->get_attribute("id")->get_value(), warnings);
+                               warnings_text += warnings;
                        }
                        catch(...)
                        {
@@ -2079,6 +2127,32 @@ CanvasParser::parse_canvas(xmlpp::Element *element,Canvas::Handle parent,bool in
        return canvas;
 }
 
+void
+CanvasParser::register_canvas_in_map(Canvas::Handle canvas, String as)
+{
+       get_open_canvas_map()[etl::absolute_path(as)]=canvas;
+       canvas->signal_deleted().connect(sigc::bind(sigc::ptr_fun(_remove_from_open_canvas_map),canvas.get()));
+       canvas->signal_file_name_changed().connect(sigc::bind(sigc::ptr_fun(_canvas_file_name_changed),canvas.get()));
+}
+
+#ifdef _DEBUG
+void
+CanvasParser::show_canvas_map(String file, int line, String text)
+{
+       return;
+       printf("  .-----\n  |  %s:%d %s\n", file.c_str(), line, text.c_str());
+       std::map<synfig::String, etl::loose_handle<Canvas> > canvas_map(synfig::get_open_canvas_map());
+       std::map<synfig::String, etl::loose_handle<Canvas> >::iterator iter;
+       for (iter = canvas_map.begin(); iter != canvas_map.end(); iter++)
+       {
+               synfig::String first(iter->first);
+               etl::loose_handle<Canvas> second(iter->second);
+               printf("  |    %40s : %lx (%d)\n", first.c_str(), ulong(&*second), second->count());
+       }
+       printf("  `-----\n\n");
+}
+#endif // _DEBUG
+
 Canvas::Handle
 CanvasParser::parse_from_file_as(const String &file_,const String &as_,String &errors)
 {
@@ -2098,9 +2172,7 @@ CanvasParser::parse_from_file_as(const String &file_,const String &as_,String &e
                {
                        Canvas::Handle canvas(parse_canvas(parser.get_document()->get_root_node(),0,false,as));
                        if (!canvas) return canvas;
-                       get_open_canvas_map()[etl::absolute_path(as)]=canvas;
-                       canvas->signal_deleted().connect(sigc::bind(sigc::ptr_fun(_remove_from_open_canvas_map),canvas.get()));
-                       canvas->signal_file_name_changed().connect(sigc::bind(sigc::ptr_fun(_canvas_file_name_changed),canvas.get()));
+                       register_canvas_in_map(canvas, as);
 
                        const ValueNodeList& value_node_list(canvas->value_node_list());
 
@@ -2126,7 +2198,6 @@ CanvasParser::parse_from_file_as(const String &file_,const String &as_,String &e
        catch(Exception::IDAlreadyExists) { synfig::error("IDAlreadyExists Thrown"); }
        catch(xmlpp::internal_error x)
        {
-               printf("caught internal error\n");
                if (!strcmp(x.what(), "Couldn't create parsing context"))
                        throw runtime_error(String("  * ") + _("Can't open file") + " \"" + file + "\"");
                throw;
@@ -2146,3 +2217,85 @@ CanvasParser::parse_from_file_as(const String &file_,const String &as_,String &e
        }
        return Canvas::Handle();
 }
+
+Canvas::Handle
+CanvasParser::parse_as(xmlpp::Element* node,String &errors)
+{
+       ChangeLocale change_locale(LC_NUMERIC, "C");
+       try
+       {
+               total_warnings_=0;
+               if(node)
+               {
+                       Canvas::Handle canvas(parse_canvas(node,0,false,""));
+                       if (!canvas) return canvas;
+
+                       const ValueNodeList& value_node_list(canvas->value_node_list());
+
+                       again:
+                       ValueNodeList::const_iterator iter;
+                       for(iter=value_node_list.begin();iter!=value_node_list.end();++iter)
+                       {
+                               ValueNode::Handle value_node(*iter);
+                               if(value_node->is_exported() && value_node->get_id().find("Unnamed")==0)
+                               {
+                                       canvas->remove_value_node(value_node);
+                                       goto again;
+                               }
+                       }
+
+                       return canvas;
+               }
+       }
+       catch(Exception::BadLinkName) { synfig::error("BadLinkName Thrown"); }
+       catch(Exception::BadType) { synfig::error("BadType Thrown"); }
+       catch(Exception::FileNotFound) { synfig::error("FileNotFound Thrown"); }
+       catch(Exception::IDNotFound) { synfig::error("IDNotFound Thrown"); }
+       catch(Exception::IDAlreadyExists) { synfig::error("IDAlreadyExists Thrown"); }
+       catch(xmlpp::internal_error x)
+       {
+               if (!strcmp(x.what(), "Couldn't create parsing context"))
+                       throw runtime_error(String("  * ") + _("Can't open file") + " \"" + "\"");
+               throw;
+       }
+       catch(const std::exception& ex)
+       {
+               synfig::error("Standard Exception: "+String(ex.what()));
+               errors = ex.what();
+               return Canvas::Handle();
+       }
+       catch(const String& str)
+       {
+               cerr<<str<<endl;
+               errors = str;
+               return Canvas::Handle();
+       }
+       return Canvas::Handle();
+}
+//extern
+Canvas::Handle
+synfig::open_canvas(xmlpp::Element* node,String &errors,String &warnings){
+       Canvas::Handle canvas;
+       CanvasParser parser;
+       parser.set_allow_errors(true);
+       try
+       {
+               canvas=parser.parse_as(node,errors);
+       }
+       catch (...)
+       {
+               synfig::error("open canvas of a node");
+               throw;
+       }
+
+       warnings = parser.get_warnings_text();
+
+       if(parser.error_count())
+       {
+               errors = parser.get_errors_text();
+               return Canvas::Handle();
+       }
+       return canvas;
+}
+
+