X-Git-Url: https://de.git.xonotic.org/?p=xonotic%2Fnetradiant.git;a=blobdiff_plain;f=radiant%2Fbuild.cpp;h=4e5ca1863a75fa86136835ac37b444be2c26b941;hp=e437f678a86cb974a0fde028bd0833ab7d857f5d;hb=a333eaee1c5b8b20ec59411f4878f8fc5bdfa584;hpb=12b372f89ce109a4db9d510884fbe7d05af79870 diff --git a/radiant/build.cpp b/radiant/build.cpp index e437f678..4e5ca186 100644 --- a/radiant/build.cpp +++ b/radiant/build.cpp @@ -1,27 +1,28 @@ /* -Copyright (C) 2001-2006, William Joseph. -All Rights Reserved. + Copyright (C) 2001-2006, William Joseph. + All Rights Reserved. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ #include "build.h" #include "debugging/debugging.h" +#include #include #include #include "stream/stringstream.h" @@ -32,25 +33,21 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA typedef std::map Variables; Variables g_build_variables; -void build_clear_variables() -{ - g_build_variables.clear(); +void build_clear_variables(){ + g_build_variables.clear(); } -void build_set_variable(const char* name, const char* value) -{ - g_build_variables[name] = value; +void build_set_variable( const char* name, const char* value ){ + g_build_variables[name] = value; } -const char* build_get_variable(const char* name) -{ - Variables::iterator i = g_build_variables.find(name); - if(i != g_build_variables.end()) - { - return (*i).second.c_str(); - } - globalErrorStream() << "undefined build variable: " << makeQuoted(name) << "\n"; - return ""; +const char* build_get_variable( const std::string& name ){ + Variables::iterator i = g_build_variables.find( name.c_str() ); + if ( i != g_build_variables.end() ) { + return ( *i ).second.c_str(); + } + globalErrorStream() << "undefined build variable: " << makeQuoted( name.c_str() ) << "\n"; + return ""; } #include "xml/ixml.h" @@ -59,131 +56,143 @@ const char* build_get_variable(const char* name) class Evaluatable { public: - virtual void evaluate(StringBuffer& output) = 0; - virtual void exportXML(XMLImporter& importer) = 0; +virtual ~Evaluatable() = default; +virtual std::string evaluate() = 0; +virtual void exportXML( XMLImporter& importer ) = 0; }; class VariableString : public Evaluatable { - CopiedString m_string; +std::string m_string; public: - VariableString() : m_string() - { - } - VariableString(const char* string) : m_string(string) - { - } - const char* c_str() const - { - return m_string.c_str(); - } - void setString(const char* string) - { - m_string = string; - } - void evaluate(StringBuffer& output) - { - StringBuffer variable; - bool in_variable = false; - for(const char* i = m_string.c_str(); *i != '\0'; ++i) - { - if(!in_variable) - { - switch(*i) - { - case '[': - in_variable = true; - break; - default: - output.push_back(*i); - break; - } - } - else - { - switch(*i) - { - case ']': - in_variable = false; - output.push_string(build_get_variable(variable.c_str())); - variable.clear(); - break; - default: - variable.push_back(*i); - break; - } - } - } - } - void exportXML(XMLImporter& importer) - { - importer << c_str(); - } +VariableString() : m_string(){ +} +VariableString( std::string string ) : m_string( std::move(string) ){ +} +const char* c_str() const { + return m_string.c_str(); +} +void setString( const std::string& string ){ + m_string = string; +} +std::string evaluate(){ + // replace ".[ExecutableType]" with "[ExecutableExt]" + { + size_t pos; + const std::string pattern = ".[ExecutableType]"; + while ( ( pos = m_string.find(pattern) ) != std::string::npos ) { + m_string.replace(pos, pattern.length(), "[ExecutableExt]"); + } + } + + // add missing [ExtraQ3map2Args] if "[RadiantPath]q3map2[ExecutableExt]" + { + size_t pos; + const std::string pattern = "\"[RadiantPath]q3map2[ExecutableExt]\""; + const std::string extra = "[ExtraQ3map2Args]"; + if ( ( pos = m_string.find(pattern) ) != std::string::npos + && m_string.find(extra) == std::string::npos ) + { + m_string.insert(pos + pattern.size(), " "); + m_string.insert(pos + pattern.size() + 1, extra); + } + } + + std::string output; + std::string variable_name; + bool in_variable = false; + for ( const char c : m_string ) + { + if ( !in_variable ) { + switch ( c ) + { + case '[': + in_variable = true; + break; + default: + output += c; + break; + } + } + else + { + switch ( c ) + { + case ']': + in_variable = false; + output += build_get_variable( variable_name ); + variable_name.clear(); + break; + default: + variable_name += c; + break; + } + } + } + + return output; +} +void exportXML( XMLImporter& importer ){ + importer << c_str(); +} }; class Conditional : public Evaluatable { - VariableString* m_test; +VariableString* m_test; public: - Evaluatable* m_result; - Conditional(VariableString* test) : m_test(test) - { - } - ~Conditional() - { - delete m_test; - delete m_result; - } - void evaluate(StringBuffer& output) - { - StringBuffer buffer; - m_test->evaluate(buffer); - if(!string_empty(buffer.c_str())) - { - m_result->evaluate(output); - } - } - void exportXML(XMLImporter& importer) - { - StaticElement conditionElement("cond"); - conditionElement.insertAttribute("value", m_test->c_str()); - importer.pushElement(conditionElement); - m_result->exportXML(importer); - importer.popElement(conditionElement.name()); - } +Evaluatable* m_result; +Conditional( VariableString* test ) : m_test( test ){ +} +~Conditional(){ + delete m_test; + delete m_result; +} +std::string evaluate(){ + std::string result = m_test->evaluate(); + if ( result.empty() ) { + return result; + } + return m_result->evaluate(); +} +void exportXML( XMLImporter& importer ){ + StaticElement conditionElement( "cond" ); + conditionElement.insertAttribute( "value", m_test->c_str() ); + importer.pushElement( conditionElement ); + m_result->exportXML( importer ); + importer.popElement( conditionElement.name() ); +} }; typedef std::vector Evaluatables; class Tool : public Evaluatable { - Evaluatables m_evaluatables; +Evaluatables m_evaluatables; public: - ~Tool() - { - for(Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i) - { - delete (*i); - } - } - void push_back(Evaluatable* evaluatable) - { - m_evaluatables.push_back(evaluatable); - } - void evaluate(StringBuffer& output) - { - for(Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i) - { - (*i)->evaluate(output); - } - } - void exportXML(XMLImporter& importer) - { - for(Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i) - { - (*i)->exportXML(importer); - } - } +~Tool(){ + for ( Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i ) + { + delete ( *i ); + } +} +void push_back( Evaluatable* evaluatable ){ + m_evaluatables.push_back( evaluatable ); +} +std::string evaluate(){ + std::string result; + for ( Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i ) + { + result += ( *i )->evaluate(); + } + return result; +} +void exportXML( XMLImporter& importer ){ + for ( Evaluatables::iterator i = m_evaluatables.begin(); i != m_evaluatables.end(); ++i ) + { + ( *i )->exportXML( importer ); + } +} }; #include "xml/ixml.h" @@ -191,114 +200,96 @@ public: class XMLElementParser : public TextOutputStream { public: - virtual XMLElementParser& pushElement(const XMLElement& element) = 0; - virtual void popElement(const char* name) = 0; +virtual ~XMLElementParser() = default; +virtual XMLElementParser& pushElement( const XMLElement& element ) = 0; +virtual void popElement( const char* name ) = 0; }; class VariableStringXMLConstructor : public XMLElementParser { - StringBuffer m_buffer; - VariableString& m_variableString; +std::string m_buffer; +VariableString& m_variableString; public: - VariableStringXMLConstructor(VariableString& variableString) : m_variableString(variableString) - { - } - ~VariableStringXMLConstructor() - { - m_variableString.setString(m_buffer.c_str()); - } - std::size_t write(const char* buffer, std::size_t length) - { - m_buffer.push_range(buffer, buffer + length); - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - ERROR_MESSAGE("parse error: invalid element \"" << element.name() << "\""); - return *this; - } - void popElement(const char* name) - { - } +VariableStringXMLConstructor( VariableString& variableString ) : m_variableString( variableString ){ +} +~VariableStringXMLConstructor(){ + m_variableString.setString( std::move(m_buffer) ); +} +std::size_t write( const char* buffer, std::size_t length ){ + m_buffer.append( buffer, length ); + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + ERROR_MESSAGE( "parse error: invalid element \"" << element.name() << "\"" ); + return *this; +} +void popElement( const char* name ){ +} }; class ConditionalXMLConstructor : public XMLElementParser { - StringBuffer m_buffer; - Conditional& m_conditional; +std::string m_buffer; +Conditional& m_conditional; public: - ConditionalXMLConstructor(Conditional& conditional) : m_conditional(conditional) - { - } - ~ConditionalXMLConstructor() - { - m_conditional.m_result = new VariableString(m_buffer.c_str()); - } - std::size_t write(const char* buffer, std::size_t length) - { - m_buffer.push_range(buffer, buffer + length); - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - ERROR_MESSAGE("parse error: invalid element \"" << element.name() << "\""); - return *this; - } - void popElement(const char* name) - { - } +ConditionalXMLConstructor( Conditional& conditional ) : m_conditional( conditional ){ +} +~ConditionalXMLConstructor(){ + m_conditional.m_result = new VariableString( std::move( m_buffer ) ); +} +std::size_t write( const char* buffer, std::size_t length ){ + m_buffer.append( buffer, length ); + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + ERROR_MESSAGE( "parse error: invalid element \"" << element.name() << "\"" ); + return *this; +} +void popElement( const char* name ){ +} }; class ToolXMLConstructor : public XMLElementParser { - StringBuffer m_buffer; - Tool& m_tool; - ConditionalXMLConstructor* m_conditional; +std::string m_buffer; +Tool& m_tool; +ConditionalXMLConstructor* m_conditional; public: - ToolXMLConstructor(Tool& tool) : m_tool(tool) - { - } - ~ToolXMLConstructor() - { - flush(); - } - std::size_t write(const char* buffer, std::size_t length) - { - m_buffer.push_range(buffer, buffer + length); - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - if(string_equal(element.name(), "cond")) - { - flush(); - Conditional* conditional = new Conditional(new VariableString(element.attribute("value"))); - m_tool.push_back(conditional); - m_conditional = new ConditionalXMLConstructor(*conditional); - return *m_conditional; - } - else - { - ERROR_MESSAGE("parse error: invalid element \"" << element.name() << "\""); - return *this; - } - } - void popElement(const char* name) - { - if(string_equal(name, "cond")) - { - delete m_conditional; - } - } - - void flush() - { - if(!m_buffer.empty()) - { - m_tool.push_back(new VariableString(m_buffer.c_str())); - m_buffer.clear(); - } - } +ToolXMLConstructor( Tool& tool ) : m_tool( tool ){ +} +~ToolXMLConstructor(){ + flush(); +} +std::size_t write( const char* buffer, std::size_t length ){ + m_buffer.append( buffer, length ); + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + if ( string_equal( element.name(), "cond" ) ) { + flush(); + Conditional* conditional = new Conditional( new VariableString( element.attribute( "value" ) ) ); + m_tool.push_back( conditional ); + m_conditional = new ConditionalXMLConstructor( *conditional ); + return *m_conditional; + } + else + { + ERROR_MESSAGE( "parse error: invalid element \"" << element.name() << "\"" ); + return *this; + } +} +void popElement( const char* name ){ + if ( string_equal( name, "cond" ) ) { + delete m_conditional; + } +} + +void flush(){ + if ( !m_buffer.empty() ) { + m_tool.push_back( new VariableString( std::move( m_buffer ) ) ); + m_buffer.clear(); + } +} }; typedef VariableString BuildCommand; @@ -306,256 +297,229 @@ typedef std::list Build; class BuildXMLConstructor : public XMLElementParser { - VariableStringXMLConstructor* m_variableString; - Build& m_build; +VariableStringXMLConstructor* m_variableString; +Build& m_build; public: - BuildXMLConstructor(Build& build) : m_build(build) - { - } - std::size_t write(const char* buffer, std::size_t length) - { - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - if(string_equal(element.name(), "command")) - { - m_build.push_back(BuildCommand()); - m_variableString = new VariableStringXMLConstructor(m_build.back()); - return *m_variableString; - } - else - { - ERROR_MESSAGE("parse error: invalid element"); - return *this; - } - } - void popElement(const char* name) - { - delete m_variableString; - } +BuildXMLConstructor( Build& build ) : m_build( build ){ +} +std::size_t write( const char* buffer, std::size_t length ){ + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + if ( string_equal( element.name(), "command" ) ) { + m_build.push_back( BuildCommand() ); + m_variableString = new VariableStringXMLConstructor( m_build.back() ); + return *m_variableString; + } + else + { + ERROR_MESSAGE( "parse error: invalid element" ); + return *this; + } +} +void popElement( const char* name ){ + delete m_variableString; +} }; typedef std::pair BuildPair; +const char *SEPARATOR_STRING = "-"; +static bool is_separator( const BuildPair &p ){ + if ( !string_equal( p.first.c_str(), SEPARATOR_STRING ) ) { + return false; + } + for ( Build::const_iterator j = p.second.begin(); j != p.second.end(); ++j ) + { + if ( !string_equal( ( *j ).c_str(), "" ) ) { + return false; + } + } + return true; +} -class BuildPairEqual -{ - const char* m_name; -public: - BuildPairEqual(const char* name) : m_name(name) - { - } - bool operator()(const BuildPair& self) const - { - return string_equal(self.first.c_str(), m_name); - } -}; typedef std::list Project; -Project::iterator Project_find(Project& project, const char* name) -{ - return std::find_if(project.begin(), project.end(), BuildPairEqual(name)); +Project::iterator Project_find( Project& project, const char* name ){ + return std::find_if(project.begin(), project.end(), [&](const BuildPair &self) { + return string_equal(self.first.c_str(), name); + }); } -Project::iterator Project_find(Project& project, std::size_t index) -{ - Project::iterator i = project.begin(); - while(index-- != 0 && i != project.end()) - { - ++i; - } - return i; +Project::iterator Project_find( Project& project, std::size_t index ){ + Project::iterator i = project.begin(); + while ( index-- != 0 && i != project.end() ) + { + ++i; + } + return i; } -Build& project_find(Project& project, const char* build) -{ - Project::iterator i = Project_find(project, build); - ASSERT_MESSAGE(i != project.end(), "error finding build command"); - return (*i).second; +Build& project_find( Project& project, const char* build ){ + Project::iterator i = Project_find( project, build ); + ASSERT_MESSAGE( i != project.end(), "error finding build command" ); + return ( *i ).second; } -Build::iterator Build_find(Build& build, std::size_t index) -{ - Build::iterator i = build.begin(); - while(index-- != 0 && i != build.end()) - { - ++i; - } - return i; +Build::iterator Build_find( Build& build, std::size_t index ){ + Build::iterator i = build.begin(); + while ( index-- != 0 && i != build.end() ) + { + ++i; + } + return i; } typedef std::map Tools; class ProjectXMLConstructor : public XMLElementParser { - ToolXMLConstructor* m_tool; - BuildXMLConstructor* m_build; - Project& m_project; - Tools& m_tools; +ToolXMLConstructor* m_tool; +BuildXMLConstructor* m_build; +Project& m_project; +Tools& m_tools; public: - ProjectXMLConstructor(Project& project, Tools& tools) : m_project(project), m_tools(tools) - { - } - std::size_t write(const char* buffer, std::size_t length) - { - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - if(string_equal(element.name(), "var")) - { - Tools::iterator i = m_tools.insert(Tools::value_type(element.attribute("name"), Tool())).first; - m_tool = new ToolXMLConstructor((*i).second); - return *m_tool; - } - else if(string_equal(element.name(), "build")) - { - m_project.push_back(Project::value_type(element.attribute("name"), Build())); - m_build = new BuildXMLConstructor(m_project.back().second); - return *m_build; - } - else - { - ERROR_MESSAGE("parse error: invalid element"); - return *this; - } - } - void popElement(const char* name) - { - if(string_equal(name, "var")) - { - delete m_tool; - } - else if(string_equal(name, "build")) - { - delete m_build; - } - } +ProjectXMLConstructor( Project& project, Tools& tools ) : m_project( project ), m_tools( tools ){ +} +std::size_t write( const char* buffer, std::size_t length ){ + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + if ( string_equal( element.name(), "var" ) ) { + Tools::iterator i = m_tools.insert( Tools::value_type( element.attribute( "name" ), Tool() ) ).first; + m_tool = new ToolXMLConstructor( ( *i ).second ); + return *m_tool; + } + else if ( string_equal( element.name(), "build" ) ) { + m_project.push_back( Project::value_type( element.attribute( "name" ), Build() ) ); + m_build = new BuildXMLConstructor( m_project.back().second ); + return *m_build; + } + else if ( string_equal( element.name(), "separator" ) ) { + m_project.push_back( Project::value_type( SEPARATOR_STRING, Build() ) ); + return *this; + } + else + { + ERROR_MESSAGE( "parse error: invalid element" ); + return *this; + } +} +void popElement( const char* name ){ + if ( string_equal( name, "var" ) ) { + delete m_tool; + } + else if ( string_equal( name, "build" ) ) { + delete m_build; + } +} }; class SkipAllParser : public XMLElementParser { public: - std::size_t write(const char* buffer, std::size_t length) - { - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - return *this; - } - void popElement(const char* name) - { - } +std::size_t write( const char* buffer, std::size_t length ){ + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + return *this; +} +void popElement( const char* name ){ +} }; class RootXMLConstructor : public XMLElementParser { - CopiedString m_elementName; - XMLElementParser& m_parser; - SkipAllParser m_skip; - Version m_version; - bool m_compatible; +CopiedString m_elementName; +XMLElementParser& m_parser; +SkipAllParser m_skip; +Version m_version; +bool m_compatible; public: - RootXMLConstructor(const char* elementName, XMLElementParser& parser, const char* version) : - m_elementName(elementName), - m_parser(parser), - m_version(version_parse(version)), - m_compatible(false) - { - } - std::size_t write(const char* buffer, std::size_t length) - { - return length; - } - XMLElementParser& pushElement(const XMLElement& element) - { - if(string_equal(element.name(), m_elementName.c_str())) - { - Version dataVersion(version_parse(element.attribute("version"))); - if(version_compatible(m_version, dataVersion)) - { - m_compatible = true; - return m_parser; - } - else - { - return m_skip; - } - } - else - { - //ERROR_MESSAGE("parse error: invalid element \"" << element.name() << "\""); - return *this; - } - } - void popElement(const char* name) - { - } - - bool versionCompatible() const - { - return m_compatible; - } +RootXMLConstructor( const char* elementName, XMLElementParser& parser, const char* version ) : + m_elementName( elementName ), + m_parser( parser ), + m_version( version_parse( version ) ), + m_compatible( false ){ +} +std::size_t write( const char* buffer, std::size_t length ){ + return length; +} +XMLElementParser& pushElement( const XMLElement& element ){ + if ( string_equal( element.name(), m_elementName.c_str() ) ) { + Version dataVersion( version_parse( element.attribute( "version" ) ) ); + if ( version_compatible( m_version, dataVersion ) ) { + m_compatible = true; + return m_parser; + } + else + { + return m_skip; + } + } + else + { + //ERROR_MESSAGE("parse error: invalid element \"" << element.name() << "\""); + return *this; + } +} +void popElement( const char* name ){ +} + +bool versionCompatible() const { + return m_compatible; +} }; namespace { - Project g_build_project; - Tools g_build_tools; - bool g_build_changed = false; +Project g_build_project; +Tools g_build_tools; +bool g_build_changed = false; } -void build_error_undefined_tool(const char* build, const char* tool) -{ - globalErrorStream() << "build " << makeQuoted(build) << " refers to undefined tool " << makeQuoted(tool) << '\n'; +void build_error_undefined_tool( const char* build, const char* tool ){ + globalErrorStream() << "build " << makeQuoted( build ) << " refers to undefined tool " << makeQuoted( tool ) << '\n'; } -void project_verify(Project& project, Tools& tools) -{ +void project_verify( Project& project, Tools& tools ){ #if 0 - for(Project::iterator i = project.begin(); i != project.end(); ++i) - { - Build& build = (*i).second; - for(Build::iterator j = build.begin(); j != build.end(); ++j) - { - Tools::iterator k = tools.find((*j).first); - if(k == g_build_tools.end()) - { - build_error_undefined_tool((*i).first.c_str(), (*j).first.c_str()); - } - } - } + for ( Project::iterator i = project.begin(); i != project.end(); ++i ) + { + Build& build = ( *i ).second; + for ( Build::iterator j = build.begin(); j != build.end(); ++j ) + { + Tools::iterator k = tools.find( ( *j ).first ); + if ( k == g_build_tools.end() ) { + build_error_undefined_tool( ( *i ).first.c_str(), ( *j ).first.c_str() ); + } + } + } #endif } -void build_run(const char* name, CommandListener& listener) -{ - for(Tools::iterator i = g_build_tools.begin(); i != g_build_tools.end(); ++i) - { - StringBuffer output; - (*i).second.evaluate(output); - build_set_variable((*i).first.c_str(), output.c_str()); - } - - { - Project::iterator i = Project_find(g_build_project, name); - if(i != g_build_project.end()) - { - Build& build = (*i).second; - for(Build::iterator j = build.begin(); j != build.end(); ++j) - { - StringBuffer output; - (*j).evaluate(output); - listener.execute(output.c_str()); - } - } - else - { - globalErrorStream() << "build " << makeQuoted(name) << " not defined"; - } - } +void build_run( const char* name, CommandListener& listener ){ + for ( Tools::iterator i = g_build_tools.begin(); i != g_build_tools.end(); ++i ) + { + std::string output = ( *i ).second.evaluate(); + build_set_variable( ( *i ).first.c_str(), output.c_str() ); + } + + { + Project::iterator i = Project_find( g_build_project, name ); + if ( i != g_build_project.end() ) { + Build& build = ( *i ).second; + for ( Build::iterator j = build.begin(); j != build.end(); ++j ) + { + std::string output = ( *j ).evaluate(); + listener.execute( output.c_str() ); + } + } + else + { + globalErrorStream() << "build " << makeQuoted( name ) << " not defined"; + } + } } @@ -563,25 +527,21 @@ typedef std::vector XMLElementStack; class XMLParser : public XMLImporter { - XMLElementStack m_stack; +XMLElementStack m_stack; public: - XMLParser(XMLElementParser& parser) - { - m_stack.push_back(&parser); - } - std::size_t write(const char* buffer, std::size_t length) - { - return m_stack.back()->write(buffer, length); - } - void pushElement(const XMLElement& element) - { - m_stack.push_back(&m_stack.back()->pushElement(element)); - } - void popElement(const char* name) - { - m_stack.pop_back(); - m_stack.back()->popElement(name); - } +XMLParser( XMLElementParser& parser ){ + m_stack.push_back( &parser ); +} +std::size_t write( const char* buffer, std::size_t length ){ + return m_stack.back()->write( buffer, length ); +} +void pushElement( const XMLElement& element ){ + m_stack.push_back( &m_stack.back()->pushElement( element ) ); +} +void popElement( const char* name ){ + m_stack.pop_back(); + m_stack.back()->popElement( name ); +} }; #include "stream/textfilestream.h" @@ -589,476 +549,429 @@ public: const char* const BUILDMENU_VERSION = "2.0"; -bool build_commands_parse(const char* filename) -{ - TextFileInputStream projectFile(filename); - if(!projectFile.failed()) - { - ProjectXMLConstructor projectConstructor(g_build_project, g_build_tools); - RootXMLConstructor rootConstructor("project", projectConstructor, BUILDMENU_VERSION); - XMLParser importer(rootConstructor); - XMLStreamParser parser(projectFile); - parser.exportXML(importer); - - if(rootConstructor.versionCompatible()) - { - project_verify(g_build_project, g_build_tools); - - return true; - } - globalErrorStream() << "failed to parse build menu: " << makeQuoted(filename); - } - return false; -} - -void build_commands_clear() -{ - g_build_project.clear(); - g_build_tools.clear(); +bool build_commands_parse( const char* filename ){ + TextFileInputStream projectFile( filename ); + if ( !projectFile.failed() ) { + ProjectXMLConstructor projectConstructor( g_build_project, g_build_tools ); + RootXMLConstructor rootConstructor( "project", projectConstructor, BUILDMENU_VERSION ); + XMLParser importer( rootConstructor ); + XMLStreamParser parser( projectFile ); + parser.exportXML( importer ); + + if ( rootConstructor.versionCompatible() ) { + project_verify( g_build_project, g_build_tools ); + + return true; + } + globalErrorStream() << "failed to parse build menu: " << makeQuoted( filename ) << "\n"; + } + return false; +} + +void build_commands_clear(){ + g_build_project.clear(); + g_build_tools.clear(); } class BuildXMLExporter { - Build& m_build; +Build& m_build; public: - BuildXMLExporter(Build& build) : m_build(build) - { - } - void exportXML(XMLImporter& importer) - { - importer << "\n"; - for(Build::iterator i = m_build.begin(); i != m_build.end(); ++i) - { - StaticElement commandElement("command"); - importer.pushElement(commandElement); - (*i).exportXML(importer); - importer.popElement(commandElement.name()); - importer << "\n"; - } - } +BuildXMLExporter( Build& build ) : m_build( build ){ +} +void exportXML( XMLImporter& importer ){ + importer << "\n"; + for ( Build::iterator i = m_build.begin(); i != m_build.end(); ++i ) + { + StaticElement commandElement( "command" ); + importer.pushElement( commandElement ); + ( *i ).exportXML( importer ); + importer.popElement( commandElement.name() ); + importer << "\n"; + } +} }; class ProjectXMLExporter { - Project& m_project; - Tools& m_tools; +Project& m_project; +Tools& m_tools; public: - ProjectXMLExporter(Project& project, Tools& tools) : m_project(project), m_tools(tools) - { - } - void exportXML(XMLImporter& importer) - { - StaticElement projectElement("project"); - projectElement.insertAttribute("version", BUILDMENU_VERSION); - importer.pushElement(projectElement); - importer << "\n"; - - for(Tools::iterator i = m_tools.begin(); i != m_tools.end(); ++i) - { - StaticElement toolElement("var"); - toolElement.insertAttribute("name", (*i).first.c_str()); - importer.pushElement(toolElement); - (*i).second.exportXML(importer); - importer.popElement(toolElement.name()); - importer << "\n"; - } - for(Project::iterator i = m_project.begin(); i != m_project.end(); ++i) - { - StaticElement buildElement("build"); - buildElement.insertAttribute("name", (*i).first.c_str()); - importer.pushElement(buildElement); - BuildXMLExporter buildExporter((*i).second); - buildExporter.exportXML(importer); - importer.popElement(buildElement.name()); - importer << "\n"; - } - importer.popElement(projectElement.name()); - } +ProjectXMLExporter( Project& project, Tools& tools ) : m_project( project ), m_tools( tools ){ +} +void exportXML( XMLImporter& importer ){ + StaticElement projectElement( "project" ); + projectElement.insertAttribute( "version", BUILDMENU_VERSION ); + importer.pushElement( projectElement ); + importer << "\n"; + + for ( Tools::iterator i = m_tools.begin(); i != m_tools.end(); ++i ) + { + StaticElement toolElement( "var" ); + toolElement.insertAttribute( "name", ( *i ).first.c_str() ); + importer.pushElement( toolElement ); + ( *i ).second.exportXML( importer ); + importer.popElement( toolElement.name() ); + importer << "\n"; + } + for ( Project::iterator i = m_project.begin(); i != m_project.end(); ++i ) + { + if ( is_separator( *i ) ) { + StaticElement buildElement( "separator" ); + importer.pushElement( buildElement ); + importer.popElement( buildElement.name() ); + importer << "\n"; + } + else + { + StaticElement buildElement( "build" ); + buildElement.insertAttribute( "name", ( *i ).first.c_str() ); + importer.pushElement( buildElement ); + BuildXMLExporter buildExporter( ( *i ).second ); + buildExporter.exportXML( importer ); + importer.popElement( buildElement.name() ); + importer << "\n"; + } + } + importer.popElement( projectElement.name() ); +} }; #include "xml/xmlwriter.h" -void build_commands_write(const char* filename) -{ - TextFileOutputStream projectFile(filename); - if(!projectFile.failed()) - { - XMLStreamWriter writer(projectFile); - ProjectXMLExporter projectExporter(g_build_project, g_build_tools); - writer << "\n"; - projectExporter.exportXML(writer); - writer << "\n"; - } +void build_commands_write( const char* filename ){ + TextFileOutputStream projectFile( filename ); + if ( !projectFile.failed() ) { + XMLStreamWriter writer( projectFile ); + ProjectXMLExporter projectExporter( g_build_project, g_build_tools ); + writer << "\n"; + projectExporter.exportXML( writer ); + writer << "\n"; + } } #include -#include -#include -#include -#include -#include -#include -#include -#include #include "gtkutil/dialog.h" #include "gtkutil/closure.h" #include "gtkutil/window.h" #include "gtkdlgs.h" -void Build_refreshMenu(GtkMenu* menu); - +void Build_refreshMenu( ui::Menu menu ); -void BSPCommandList_Construct(GtkListStore* store, Project& project) -{ - gtk_list_store_clear(store); - for(Project::iterator i = project.begin(); i != project.end(); ++i) - { - const char* buildName = (*i).first.c_str(); +void BSPCommandList_Construct( ui::ListStore store, Project& project ){ + store.clear(); - GtkTreeIter buildIter; - gtk_list_store_append(store, &buildIter); - gtk_list_store_set(store, &buildIter, 0, const_cast(buildName), -1); - } + for ( Project::iterator i = project.begin(); i != project.end(); ++i ) + { + store.append(0, (*i).first.c_str()); + } - GtkTreeIter lastIter; - gtk_list_store_append(store, &lastIter); + store.append(); } class ProjectList { public: - Project& m_project; - GtkListStore* m_store; - bool m_changed; - ProjectList(Project& project) : m_project(project), m_changed(false) - { - } +Project& m_project; +ui::ListStore m_store{ui::null}; +bool m_changed; +ProjectList( Project& project ) : m_project( project ), m_changed( false ){ +} }; -gboolean project_cell_edited(GtkCellRendererText* cell, gchar* path_string, gchar* new_text, ProjectList* projectList) -{ - Project& project = projectList->m_project; - - GtkTreePath* path = gtk_tree_path_new_from_string(path_string); +gboolean project_cell_edited(ui::CellRendererText cell, gchar* path_string, gchar* new_text, ProjectList* projectList ){ + Project& project = projectList->m_project; - ASSERT_MESSAGE(gtk_tree_path_get_depth(path) == 1, "invalid path length"); + auto path = ui::TreePath( path_string ); - GtkTreeIter iter; - gtk_tree_model_get_iter(GTK_TREE_MODEL(projectList->m_store), &iter, path); + ASSERT_MESSAGE( gtk_tree_path_get_depth( path ) == 1, "invalid path length" ); - Project::iterator i = Project_find(project, gtk_tree_path_get_indices(path)[0]); - if(i != project.end()) - { - projectList->m_changed = true; - if(string_empty(new_text)) - { - project.erase(i); - Build_refreshMenu(g_bsp_menu); + GtkTreeIter iter; + gtk_tree_model_get_iter(projectList->m_store, &iter, path ); - gtk_list_store_remove(projectList->m_store, &iter); - } - else - { - (*i).first = new_text; - Build_refreshMenu(g_bsp_menu); + Project::iterator i = Project_find( project, gtk_tree_path_get_indices( path )[0] ); + if ( i != project.end() ) { + projectList->m_changed = true; + if ( string_empty( new_text ) ) { + project.erase( i ); + gtk_list_store_remove( projectList->m_store, &iter ); + } + else + { + ( *i ).first = new_text; + gtk_list_store_set( projectList->m_store, &iter, 0, new_text, -1 ); + } + } + else if ( !string_empty( new_text ) ) { + projectList->m_changed = true; + project.push_back( Project::value_type( new_text, Build() ) ); - gtk_list_store_set(projectList->m_store, &iter, 0, new_text, -1); - } - } - else if(!string_empty(new_text)) - { - projectList->m_changed = true; - project.push_back(Project::value_type(new_text, Build())); - Build_refreshMenu(g_bsp_menu); + gtk_list_store_set( projectList->m_store, &iter, 0, new_text, -1 ); + projectList->m_store.append(); + } - gtk_list_store_set(projectList->m_store, &iter, 0, new_text, -1); - GtkTreeIter lastIter; - gtk_list_store_append(projectList->m_store, &lastIter); - } + gtk_tree_path_free( path ); - gtk_tree_path_free(path); + Build_refreshMenu( g_bsp_menu ); - return FALSE; + return FALSE; } -gboolean project_key_press(GtkWidget* widget, GdkEventKey* event, GtkListStore* store, ProjectList* projectList) -{ - Project& project = projectList->m_project; +gboolean project_key_press( ui::TreeView widget, GdkEventKey* event, ProjectList* projectList ){ + Project& project = projectList->m_project; + + if ( event->keyval == GDK_KEY_Delete ) { + auto selection = ui::TreeSelection::from(gtk_tree_view_get_selection(widget)); + GtkTreeIter iter; + GtkTreeModel* model; + if ( gtk_tree_selection_get_selected( selection, &model, &iter ) ) { + auto path = gtk_tree_model_get_path( model, &iter ); + Project::iterator x = Project_find( project, gtk_tree_path_get_indices( path )[0] ); + gtk_tree_path_free( path ); + + if ( x != project.end() ) { + projectList->m_changed = true; + project.erase( x ); + Build_refreshMenu( g_bsp_menu ); + + gtk_list_store_remove( projectList->m_store, &iter ); + } + } + } + return FALSE; +} - if(event->keyval == GDK_Delete) - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - GtkTreeIter iter; - GtkTreeModel* model; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &iter); - Project::iterator x = Project_find(project, gtk_tree_path_get_indices(path)[0]); - gtk_tree_path_free(path); - if(x != project.end()) - { - projectList->m_changed = true; - project.erase(x); - Build_refreshMenu(g_bsp_menu); +Build* g_current_build = 0; - gtk_list_store_remove(projectList->m_store, &iter); - } - } - } - return FALSE; +gboolean project_selection_changed( ui::TreeSelection selection, ui::ListStore store ){ + Project& project = g_build_project; + + store.clear(); + + GtkTreeIter iter; + GtkTreeModel* model; + if ( gtk_tree_selection_get_selected( selection, &model, &iter ) ) { + auto path = gtk_tree_model_get_path( model, &iter ); + Project::iterator x = Project_find( project, gtk_tree_path_get_indices( path )[0] ); + gtk_tree_path_free( path ); + + if ( x != project.end() ) { + Build& build = ( *x ).second; + g_current_build = &build; + + for ( Build::iterator i = build.begin(); i != build.end(); ++i ) + { + store.append(0, (*i).c_str()); + } + store.append(); + } + else + { + g_current_build = 0; + } + } + else + { + g_current_build = 0; + } + + return FALSE; } +gboolean commands_cell_edited(ui::CellRendererText cell, const gchar* path_string, const gchar* new_text, ui::ListStore store ){ + if ( g_current_build == 0 ) { + return FALSE; + } + Build& build = *g_current_build; -Build* g_current_build = 0; + auto path = ui::TreePath( path_string ); -gboolean project_selection_changed(GtkTreeSelection* selection, GtkListStore* store) -{ - Project& project = g_build_project; - - gtk_list_store_clear(store); - - GtkTreeIter iter; - GtkTreeModel* model; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &iter); - Project::iterator x = Project_find(project, gtk_tree_path_get_indices(path)[0]); - gtk_tree_path_free(path); - - if(x != project.end()) - { - Build& build = (*x).second; - g_current_build = &build; - - for(Build::iterator i = build.begin(); i != build.end(); ++i) - { - GtkTreeIter commandIter; - gtk_list_store_append(store, &commandIter); - gtk_list_store_set(store, &commandIter, 0, const_cast((*i).c_str()), -1); - } - GtkTreeIter lastIter; - gtk_list_store_append(store, &lastIter); - } - else - { - g_current_build = 0; - } - } - else - { - g_current_build = 0; - } - - return FALSE; -} - -gboolean commands_cell_edited(GtkCellRendererText* cell, gchar* path_string, gchar* new_text, GtkListStore* store) -{ - if(g_current_build == 0) - { - return FALSE; - } - Build& build = *g_current_build; + ASSERT_MESSAGE( gtk_tree_path_get_depth( path ) == 1, "invalid path length" ); - GtkTreePath* path = gtk_tree_path_new_from_string(path_string); + GtkTreeIter iter; + gtk_tree_model_get_iter(store, &iter, path ); - ASSERT_MESSAGE(gtk_tree_path_get_depth(path) == 1, "invalid path length"); + Build::iterator i = Build_find( build, gtk_tree_path_get_indices( path )[0] ); + if ( i != build.end() ) { + g_build_changed = true; + ( *i ).setString( new_text ); - GtkTreeIter iter; - gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, path); + gtk_list_store_set( store, &iter, 0, new_text, -1 ); + } + else if ( !string_empty( new_text ) ) { + g_build_changed = true; + build.push_back( Build::value_type( VariableString( new_text ) ) ); - Build::iterator i = Build_find(build, gtk_tree_path_get_indices(path)[0]); - if(i != build.end()) - { - g_build_changed = true; - (*i).setString(new_text); + gtk_list_store_set( store, &iter, 0, new_text, -1 ); - gtk_list_store_set(store, &iter, 0, new_text, -1); - } - else if(!string_empty(new_text)) - { - g_build_changed = true; - build.push_back(Build::value_type(VariableString(new_text))); + store.append(); + } - gtk_list_store_set(store, &iter, 0, new_text, -1); + gtk_tree_path_free( path ); - GtkTreeIter lastIter; - gtk_list_store_append(store, &lastIter); - } + Build_refreshMenu( g_bsp_menu ); - gtk_tree_path_free(path); + return FALSE; +} - return FALSE; +gboolean commands_key_press( ui::TreeView widget, GdkEventKey* event, ui::ListStore store ){ + if ( g_current_build == 0 ) { + return FALSE; + } + Build& build = *g_current_build; + + if ( event->keyval == GDK_KEY_Delete ) { + auto selection = gtk_tree_view_get_selection(widget ); + GtkTreeIter iter; + GtkTreeModel* model; + if ( gtk_tree_selection_get_selected( selection, &model, &iter ) ) { + auto path = gtk_tree_model_get_path( model, &iter ); + Build::iterator i = Build_find( build, gtk_tree_path_get_indices( path )[0] ); + gtk_tree_path_free( path ); + + if ( i != build.end() ) { + g_build_changed = true; + build.erase( i ); + + gtk_list_store_remove( store, &iter ); + } + } + } + return FALSE; } -gboolean commands_key_press(GtkWidget* widget, GdkEventKey* event, GtkListStore* store) -{ - if(g_current_build == 0) - { - return FALSE; - } - Build& build = *g_current_build; - - if(event->keyval == GDK_Delete) - { - GtkTreeSelection* selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(widget)); - GtkTreeIter iter; - GtkTreeModel* model; - if(gtk_tree_selection_get_selected(selection, &model, &iter)) - { - GtkTreePath* path = gtk_tree_model_get_path(model, &iter); - Build::iterator i = Build_find(build, gtk_tree_path_get_indices(path)[0]); - gtk_tree_path_free(path); - - if(i != build.end()) - { - g_build_changed = true; - build.erase(i); - - gtk_list_store_remove(store, &iter); - } - } - } - return FALSE; -} - - -GtkWindow* BuildMenuDialog_construct(ModalDialog& modal, ProjectList& projectList) -{ - GtkWindow* window = create_dialog_window(MainFrame_getWindow(), "Build Menu", G_CALLBACK(dialog_delete_callback), &modal, -1, 400); - - GtkWidget* buildView = 0; - - { - GtkTable* table1 = create_dialog_table(2, 2, 4, 4, 4); - gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(table1)); - { - GtkVBox* vbox = create_dialog_vbox(4); - gtk_table_attach(table1, GTK_WIDGET(vbox), 1, 2, 0, 1, - (GtkAttachOptions) (GTK_FILL), - (GtkAttachOptions) (GTK_FILL), 0, 0); - { - GtkButton* button = create_dialog_button("OK", G_CALLBACK(dialog_button_ok), &modal); - gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0); - } - { - GtkButton* button = create_dialog_button("Cancel", G_CALLBACK(dialog_button_cancel), &modal); - gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(button), FALSE, FALSE, 0); - } - } - { - GtkFrame* frame = create_dialog_frame("Build menu"); - gtk_table_attach(table1, GTK_WIDGET(frame), 0, 1, 0, 1, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - { - GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4); - gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(scr)); - - { - GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - object_set_boolean_property(G_OBJECT(renderer), "editable", TRUE); - g_signal_connect(renderer, "edited", G_CALLBACK(project_cell_edited), &projectList); - - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, 0); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - - GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); - - gtk_widget_show(view); - - buildView = view; - projectList.m_store = store; - gtk_container_add(GTK_CONTAINER (scr), view); - - g_signal_connect(G_OBJECT(view), "key_press_event", G_CALLBACK(project_key_press), &projectList); - - g_object_unref(G_OBJECT(store)); - } - } - } - { - GtkFrame* frame = create_dialog_frame("Commandline"); - gtk_table_attach(table1, GTK_WIDGET(frame), 0, 1, 1, 2, - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), - (GtkAttachOptions) (GTK_EXPAND | GTK_FILL), 0, 0); - { - GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_NEVER, GTK_POLICY_AUTOMATIC, 4); - gtk_container_add(GTK_CONTAINER(frame), GTK_WIDGET(scr)); - - { - GtkListStore* store = gtk_list_store_new(1, G_TYPE_STRING); - - GtkWidget* view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(store)); - gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE); - - GtkCellRenderer* renderer = gtk_cell_renderer_text_new(); - object_set_boolean_property(G_OBJECT(renderer), "editable", TRUE); - g_signal_connect(renderer, "edited", G_CALLBACK(commands_cell_edited), store); - - GtkTreeViewColumn* column = gtk_tree_view_column_new_with_attributes("", renderer, "text", 0, 0); - gtk_tree_view_append_column(GTK_TREE_VIEW(view), column); - - GtkTreeSelection* selection = gtk_tree_view_get_selection (GTK_TREE_VIEW(view)); - gtk_tree_selection_set_mode(selection, GTK_SELECTION_BROWSE); - - gtk_widget_show(view); - - gtk_container_add(GTK_CONTAINER (scr), view); - - g_object_unref(G_OBJECT(store)); - - g_signal_connect(G_OBJECT(view), "key_press_event", G_CALLBACK(commands_key_press), store); - - g_signal_connect(G_OBJECT(gtk_tree_view_get_selection(GTK_TREE_VIEW(buildView))), "changed", G_CALLBACK(project_selection_changed), store); - } - } - } - } - - BSPCommandList_Construct(projectList.m_store, g_build_project); - - return window; + +ui::Window BuildMenuDialog_construct( ModalDialog& modal, ProjectList& projectList ){ + ui::Window window = MainFrame_getWindow().create_dialog_window("Build Menu", G_CALLBACK(dialog_delete_callback ), &modal, -1, 400 ); + + // FIXME: GTK_WIN_POS_CENTER_ON_PARENT must be used instead but does not work + // for unknown reason. + // It's possible MaingFrame_getWindow() does not return the main window. + // It's known the preferences window has same issue when using MaingFrame_getWindow(). + gtk_window_set_position( window, GTK_WIN_POS_CENTER_ALWAYS ); + + { + auto table1 = create_dialog_table( 2, 2, 4, 4, 4 ); + window.add(table1); + { + auto vbox = create_dialog_vbox( 4 ); + table1.attach(vbox, {1, 2, 0, 1}, {GTK_FILL, GTK_FILL}); + { + auto button = create_dialog_button( "OK", G_CALLBACK( dialog_button_ok ), &modal ); + vbox.pack_start( button, FALSE, FALSE, 0 ); + } + { + auto button = create_dialog_button( "Cancel", G_CALLBACK( dialog_button_cancel ), &modal ); + vbox.pack_start( button, FALSE, FALSE, 0 ); + } + } + auto buildViewStore = ui::ListStore::from(gtk_list_store_new( 1, G_TYPE_STRING )); + auto buildView = ui::TreeView( ui::TreeModel::from( buildViewStore._handle )); + { + auto frame = create_dialog_frame( "Build menu" ); + table1.attach(frame, {0, 1, 0, 1}); + { + auto scr = create_scrolled_window( ui::Policy::NEVER, ui::Policy::AUTOMATIC, 4 ); + frame.add(scr); + + { + auto view = buildView; + auto store = buildViewStore; + gtk_tree_view_set_headers_visible(view, FALSE ); + + auto renderer = ui::CellRendererText(ui::New); + object_set_boolean_property( G_OBJECT( renderer ), "editable", TRUE ); + renderer.connect("edited", G_CALLBACK( project_cell_edited ), &projectList ); + + auto column = ui::TreeViewColumn( "", renderer, {{"text", 0}} ); + gtk_tree_view_append_column(view, column ); + + auto selection = gtk_tree_view_get_selection(view ); + gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE ); + + view.show(); + + projectList.m_store = store; + scr.add(view); + + view.connect( "key_press_event", G_CALLBACK( project_key_press ), &projectList ); + + store.unref(); + } + } + } + { + auto frame = create_dialog_frame( "Command line" ); + table1.attach(frame, {0, 1, 1, 2}); + { + auto scr = create_scrolled_window( ui::Policy::NEVER, ui::Policy::AUTOMATIC, 4 ); + frame.add(scr); + + { + auto store = ui::ListStore::from(gtk_list_store_new( 1, G_TYPE_STRING )); + + auto view = ui::TreeView(ui::TreeModel::from( store._handle )); + gtk_tree_view_set_headers_visible(view, FALSE ); + + auto renderer = ui::CellRendererText(ui::New); + object_set_boolean_property( G_OBJECT( renderer ), "editable", TRUE ); + renderer.connect( "edited", G_CALLBACK( commands_cell_edited ), store ); + + auto column = ui::TreeViewColumn( "", renderer, {{"text", 0}} ); + gtk_tree_view_append_column(view, column ); + + auto selection = gtk_tree_view_get_selection(view ); + gtk_tree_selection_set_mode( selection, GTK_SELECTION_BROWSE ); + + view.show(); + + scr.add(view); + + store.unref(); + + view.connect( "key_press_event", G_CALLBACK( commands_key_press ), store ); + + auto sel = ui::TreeSelection::from(gtk_tree_view_get_selection(buildView )); + sel.connect( "changed", G_CALLBACK( project_selection_changed ), store ); + } + } + } + } + + BSPCommandList_Construct( projectList.m_store, g_build_project ); + + return window; } namespace { - CopiedString g_buildMenu; +CopiedString g_buildMenu; } void LoadBuildMenu(); -void DoBuildMenu() -{ - ModalDialog modal; +void DoBuildMenu(){ + ModalDialog modal; - ProjectList projectList(g_build_project); + ProjectList projectList( g_build_project ); - GtkWindow* window = BuildMenuDialog_construct(modal, projectList); + ui::Window window = BuildMenuDialog_construct( modal, projectList ); - if(modal_dialog_show(window, modal) == eIDCANCEL) - { - build_commands_clear(); - LoadBuildMenu(); + if ( modal_dialog_show( window, modal ) == eIDCANCEL ) { + build_commands_clear(); + LoadBuildMenu(); - Build_refreshMenu(g_bsp_menu); - } - else if(projectList.m_changed) - { - g_build_changed = true; - } + Build_refreshMenu( g_bsp_menu ); + } + else if ( projectList.m_changed ) { + g_build_changed = true; + } - gtk_widget_destroy(GTK_WIDGET(window)); + window.destroy(); } @@ -1068,91 +981,85 @@ void DoBuildMenu() #include "preferences.h" #include "qe3.h" -typedef struct _GtkMenuItem GtkMenuItem; - class BuildMenuItem { - const char* m_name; +const char* m_name; public: - GtkMenuItem* m_item; - BuildMenuItem(const char* name, GtkMenuItem* item) - : m_name(name), m_item(item) - { - } - void run() - { - RunBSP(m_name); - } - typedef MemberCaller RunCaller; +ui::MenuItem m_item; +BuildMenuItem( const char* name, ui::MenuItem item ) + : m_name( name ), m_item( item ){ +} +void run(){ + RunBSP( m_name ); +} +typedef MemberCaller RunCaller; }; typedef std::list BuildMenuItems; BuildMenuItems g_BuildMenuItems; -GtkMenu* g_bsp_menu; - -void Build_constructMenu(GtkMenu* menu) -{ - for(Project::iterator i = g_build_project.begin(); i != g_build_project.end(); ++i) - { - g_BuildMenuItems.push_back(BuildMenuItem((*i).first.c_str(), 0)); - g_BuildMenuItems.back().m_item = create_menu_item_with_mnemonic(menu, (*i).first.c_str(), BuildMenuItem::RunCaller(g_BuildMenuItems.back())); - } +ui::Menu g_bsp_menu{ui::null}; + +void Build_constructMenu( ui::Menu menu ){ + for ( Project::iterator i = g_build_project.begin(); i != g_build_project.end(); ++i ) + { + g_BuildMenuItems.push_back( BuildMenuItem( ( *i ).first.c_str(), ui::MenuItem(ui::null) ) ); + if ( is_separator( *i ) ) { + g_BuildMenuItems.back().m_item = menu_separator( menu ); + } + else + { + g_BuildMenuItems.back().m_item = create_menu_item_with_mnemonic( menu, ( *i ).first.c_str(), BuildMenuItem::RunCaller( g_BuildMenuItems.back() ) ); + } + } } -void Build_refreshMenu(GtkMenu* menu) -{ - for(BuildMenuItems::iterator i = g_BuildMenuItems.begin(); i != g_BuildMenuItems.end(); ++i) - { - gtk_container_remove(GTK_CONTAINER(menu), GTK_WIDGET((*i).m_item)); - } +void Build_refreshMenu( ui::Menu menu ){ + for (auto i = g_BuildMenuItems.begin(); i != g_BuildMenuItems.end(); ++i ) + { + menu.remove(ui::MenuItem(i->m_item)); + } - g_BuildMenuItems.clear(); + g_BuildMenuItems.clear(); - Build_constructMenu(menu); + Build_constructMenu( menu ); } -void LoadBuildMenu() -{ - if(string_empty(g_buildMenu.c_str()) || !build_commands_parse(g_buildMenu.c_str())) - { - { - StringOutputStream buffer(256); - buffer << GameToolsPath_get() << "default_build_menu.xml"; +void LoadBuildMenu(){ + if ( string_empty( g_buildMenu.c_str() ) || !build_commands_parse( g_buildMenu.c_str() ) ) { + { + StringOutputStream buffer( 256 ); + buffer << GameToolsPath_get() << "default_build_menu.xml"; - bool success = build_commands_parse(buffer.c_str()); - ASSERT_MESSAGE(success, "failed to parse default build commands: " << buffer.c_str()); - } - { - StringOutputStream buffer(256); - buffer << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << "/build_menu.xml"; + bool success = build_commands_parse( buffer.c_str() ); + ASSERT_MESSAGE( success, "failed to parse default build commands: " << buffer.c_str() ); + } + { + StringOutputStream buffer( 256 ); + buffer << SettingsPath_get() << g_pGameDescription->mGameFile.c_str() << "/build_menu.xml"; - g_buildMenu = buffer.c_str(); - } - } + g_buildMenu = buffer.c_str(); + } + } } -void SaveBuildMenu() -{ - if(g_build_changed) - { - g_build_changed = false; - build_commands_write(g_buildMenu.c_str()); - } +void SaveBuildMenu(){ + if ( g_build_changed ) { + g_build_changed = false; + build_commands_write( g_buildMenu.c_str() ); + } } #include "preferencesystem.h" #include "stringio.h" -void BuildMenu_Construct() -{ - GlobalPreferenceSystem().registerPreference("BuildMenu", CopiedStringImportStringCaller(g_buildMenu), CopiedStringExportStringCaller(g_buildMenu)); - LoadBuildMenu(); +void BuildMenu_Construct(){ + GlobalPreferenceSystem().registerPreference( "BuildMenu", make_property_string( g_buildMenu ) ); + LoadBuildMenu(); } -void BuildMenu_Destroy() -{ - SaveBuildMenu(); +void BuildMenu_Destroy(){ + SaveBuildMenu(); }