/*
This file is part of Universal Modding Engine.
Universal Modding Engine 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 3 of the License, or
(at your option) any later version.
Universal Modding Engine 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 Universal Modding Engine. If not, see .
*/
#include "uMod_Main.h"
wxString uMod_TreeViewModel::LastError = wxString();
void uMod_TreeViewModel::GetValue( wxVariant &variant,
const wxDataViewItem &item, unsigned int col ) const
{
wxASSERT(item.IsOk());
uMod_TreeViewNode *node = (uMod_TreeViewNode*) item.GetID();
switch (col)
{
case 0:
if (node->myElement->Title().IsEmpty()) variant = node->myElement->File();
else variant = node->myElement->Title();
break;
case 1:
variant = (bool) (node->myElement->Status()==uMod_ModElement::Activate);
break;
case 2:
variant = (bool) (node->myElement->Status()==uMod_ModElement::Deactivate);
break;
case 3:
variant = node->myElement->Author();
break;
case 4:
variant = node->myElement->Comment();
break;
default:
break;
}
}
bool uMod_TreeViewModel::SetValue( const wxVariant &variant,
const wxDataViewItem &item, unsigned int col )
{
wxASSERT(item.IsOk());
if (col<1 || col>2) return false;
uMod_TreeViewNode *node = (uMod_TreeViewNode*) item.GetID();
bool set;
variant.Convert( &set);
uMod_ModElement::enumStatus status = uMod_ModElement::NONE;
if (set)
{
switch (col)
{
case 1:
status = uMod_ModElement::Activate;
break;
case 2:
status = uMod_ModElement::Deactivate;
break;
default:
return false;
break;
}
node->myElement->Status() = status;
}
else
{
if (node->myElement->Type() == uMod_ModElement::Group)
{
node->myElement->Status() = uMod_ModElement::NONE;
}
}
return true;
}
bool uMod_TreeViewModel::IsEnabled( const wxDataViewItem &item,
unsigned int col ) const
{
//only the toggle are enabled
if (col<1 || col >3) return false;
uMod_TreeViewNode *node = (uMod_TreeViewNode*) item.GetID();
//an item is only enabled if no one of the parents is set.
uMod_TreeViewNode *parent = node->GetParent();
while (parent != (uMod_TreeViewNode*)0)
{
if (parent->myElement->Status()!=uMod_ModElement::NONE) return false;
parent = parent->GetParent();
}
return true;
}
wxDataViewItem uMod_TreeViewModel::GetParent( const wxDataViewItem &item ) const
{
// the invisible root node has no parent
if (!item.IsOk())
return wxDataViewItem(0);
uMod_TreeViewNode *node = (uMod_TreeViewNode*) item.GetID();
return wxDataViewItem( (void*) node->GetParent() );
}
bool uMod_TreeViewModel::HasContainerColumns( const wxDataViewItem &WXUNUSED(item) ) const
{
return true;
}
bool uMod_TreeViewModel::IsContainer( const wxDataViewItem &item ) const
{
// the invisble root node can have children
if (!item.IsOk())
return true;
uMod_TreeViewNode *node = (uMod_TreeViewNode*) item.GetID();
return node->IsContainer();
}
unsigned int uMod_TreeViewModel::GetChildren( const wxDataViewItem &parent,
wxDataViewItemArray &array ) const
{
uMod_TreeViewNode *node = (uMod_TreeViewNode*) parent.GetID();
if (!node)
{
unsigned int count = myPackages.GetCount();
for (unsigned int pos = 0; pos < count; pos++)
{
uMod_TreeViewNode *child = myPackages.Item( pos );
array.Add( wxDataViewItem( (void*) child ) );
}
return count;
}
if (node->GetChildCount() == 0)
{
return 0;
}
unsigned int count = node->GetChildren().GetCount();
for (unsigned int pos = 0; pos < count; pos++)
{
uMod_TreeViewNode *child = node->GetChildren().Item( pos );
array.Add( wxDataViewItem( (void*) child ) );
}
return count;
}
int uMod_TreeViewModel::CreateSingleNode()
{
if (SingleTextureNode ==(uMod_TreeViewNode*)0)
{
uMod_ModElement *package = new uMod_ModElement(uMod_ModElement::Group, uMod_ModElement::Activate);
SingleTextureNode = new uMod_TreeViewNode( (uMod_TreeViewNode*)0, package);
package->Release();
package->Title() = Language->SingleTextureNode;
myPackages.Add( SingleTextureNode);
wxDataViewItem child( (void*) SingleTextureNode );
wxDataViewItem parent( (void*) 0 );
ItemAdded( parent, child );
}
return 0;
}
int uMod_TreeViewModel::AddPackage(const wxString &file_name)
{
uMod_File file( file_name);
if (! file.FileSupported())
{
LastError << Language->Error_FileNotSupported << "\n" << file_name;
return -1;
}
bool single_file = file.SingleFile();
uMod_TreeViewNode *node;
if (single_file)
{
CreateSingleNode();
node = SingleTextureNode;
}
else
{
uMod_ModElement *package = new uMod_ModElement(uMod_ModElement::Group, uMod_ModElement::Activate);
node = new uMod_TreeViewNode( (uMod_TreeViewNode*)0, package);
package->Release();
package->File() = file_name;
}
if (int ret = file.GetContent(node))
{
LastError = file.LastError;
if (node != SingleTextureNode) delete node;
return ret;
}
if (node != SingleTextureNode)
{
myPackages.Add( node);
wxDataViewItem child( (void*) node );
wxDataViewItem parent( (void*) 0 );
ItemAdded( parent, child );
}
else if (SingleTextureNode != (uMod_TreeViewNode*)0)
{
wxDataViewItem child( (void*) SingleTextureNode->myChildren.Last() );
wxDataViewItem parent( SingleTextureNode );
ItemAdded( parent, child );
}
return 0;
}
int uMod_TreeViewModel::AddPackages(const wxArrayString &files)
{
LastError.Empty();
uMod_File file;
wxDataViewItemArray added_items;
wxDataViewItemArray added_single_items;
/*
bool single_file = false;
// detect if there are more than one single file
for (unsigned int i=0; i1)
{
uMod_ModElement *element = new uMod_ModElement(uMod_ModElement::Group, uMod_ModElement::NONE);
element->Title() = Language->MultipleSingleFiles;
single_file_node = new uMod_TreeViewNode( (uMod_TreeViewNode*)0, element);
element->Release();
}
*/
for (unsigned int i=0; iError_FileNotSupported << "\n" << files[i] << "\n" ;
continue;
}
if (file.SingleFile())
{
CreateSingleNode();
if (file.GetContent(SingleTextureNode))
{
LastError << file.LastError ;
file.LastError.Empty();
continue;
}
wxDataViewItem child( (void*) SingleTextureNode->myChildren.Last() );
added_single_items.Add( child);
}
else
{
uMod_ModElement *package = new uMod_ModElement(uMod_ModElement::Group, uMod_ModElement::Activate);
uMod_TreeViewNode *node = new uMod_TreeViewNode( (uMod_TreeViewNode*)0, package);
package->Release();
package->File() = files[i];
if (file.GetContent(node))
{
LastError << file.LastError;
delete node;
file.LastError.Empty();
continue;
}
myPackages.Add( node);
wxDataViewItem child( (void*) node );
added_items.Add( child);
}
}
if (added_items.GetCount()>0)
{
wxDataViewItem parent( (void*) 0 );
ItemsAdded( parent, added_items);
}
if (added_single_items.GetCount()>0)
{
wxDataViewItem parent( SingleTextureNode );
ItemsAdded( parent, added_single_items);
}
if (LastError.IsEmpty()) return 0;
else return -1;
}
int uMod_TreeViewModel::AddPackagesFromTemplate(const wxArrayString &packages)
{
LastError.Empty();
uMod_File file;
wxDataViewItemArray added_items;
DeleteAllPackages();
for (unsigned int i=0; iRelease();
if (file.GetContentTemplate( packages[i], node))
{
LastError << file.LastError;
file.LastError.Empty();
delete node;
continue;
}
myPackages.Add( node);
wxDataViewItem child( (void*) node );
added_items.Add( child);
if (node->myElement->File().IsEmpty())
{
SingleTextureNode = node;
SingleTextureNode->myElement->Title() = Language->SingleTextureNode;
}
}
if (added_items.GetCount()>0)
{
wxDataViewItem parent( (void*) 0 );
ItemsAdded( parent, added_items);
}
if (LastError.IsEmpty()) return 0;
else return -1;
}
int uMod_TreeViewModel::DeletePackage( const wxDataViewItem &item)
{
uMod_TreeViewNode *node = (uMod_TreeViewNode*) item.GetID();
if (node)
{
if (node->GetParent()== (uMod_TreeViewNode*) 0 )
{
myPackages.Remove( node);
delete node;
if (node == SingleTextureNode) SingleTextureNode = (uMod_TreeViewNode*) 0;
wxDataViewItem parent( (void*) 0 );
ItemDeleted( parent, item );
return 0;
}
return 1;
}
return 2;
}
int uMod_TreeViewModel::DeletePackages( const wxDataViewItemArray &items)
{
int num = items.GetCount();
wxDataViewItemArray deleted_items;
for (int i=0; iGetParent()== (uMod_TreeViewNode*) 0 )
{
myPackages.Remove( node);
delete node;
if (node == SingleTextureNode) SingleTextureNode = (uMod_TreeViewNode*) 0;
deleted_items.Add( items[i]);
}
}
}
wxDataViewItem parent( (void*) 0 );
ItemsDeleted( parent, deleted_items);
return 0;
}
int uMod_TreeViewModel::DeleteAllPackages(void)
{
wxDataViewItemArray deleted_items;
for (unsigned int i=0; iparent1->parent2->current_group)
wxArrayInt counter; // this array store the actual index position for each group in the hierarchy
wxArrayInt active; // this array is need for the inherited active status of parent groups
for (unsigned int p=0; pmyElement->Status()==uMod_ModElement::Deactivate) continue;
if (myPackages.Item(p)->myElement->Type() == uMod_ModElement::Group)
{
buffer.Add(myPackages.Item(p));
counter.Add(0);
if (myPackages.Item(p)->myElement->Status()==uMod_ModElement::Activate) active.Add(1);
else active.Add(0);
while (!buffer.IsEmpty())
{
int pos = buffer.GetCount()-1;
unsigned int index = counter[pos];
if (index < buffer[pos]->myChildren.GetCount()) // it has still childrens
{
if (buffer[pos]->myChildren[index]->myElement->Type() == uMod_ModElement::Group)
{
if ((active[pos]>0) || (buffer[pos]->myChildren[index]->myElement->Status() != uMod_ModElement::Deactivate))
{
buffer.Add(buffer[pos]->myChildren[index]);
counter.Add(0);
if (active[pos]>0 || buffer[pos]->myChildren[index]->myElement->Status()==uMod_ModElement::Activate) active.Add(1);
else active.Add(0);
}
}
else if (buffer[pos]->myChildren[index]->myElement->Type() == uMod_ModElement::Texture)
{
uMod_TextureElement *tex = (uMod_TextureElement*) buffer[pos]->myChildren[index]->myElement;
if (tex->Content().Len()>0 && ((active[pos]>0) || (tex->Status()==uMod_ModElement::Activate)))
{
if( wxNOT_FOUND == texture.Index(tex))
{
texture.Add(tex);
tex->AddRef();
}
}
}
counter[pos]++;
}
else // finished this group
{
buffer.RemoveAt(pos);
counter.RemoveAt(pos);
active.RemoveAt(pos);
}
}
}
else if (myPackages.Item(p)->myElement->Type()==uMod_ModElement::Texture)
{
uMod_TextureElement *tex = (uMod_TextureElement*) myPackages.Item(p)->myElement;
if (tex->Status()==uMod_ModElement::Activate)
if (wxNOT_FOUND == texture.Index(tex))
{
texture.Add(tex);
tex->AddRef();
}
}
}
return 0;
}
int uMod_TreeViewModel::String2Node( const wxString &input, uMod_TreeViewNode* node, uMod_TreeViewNode_ArrayPtr *list_node)
{
if (list_node!=(uMod_TreeViewNode_ArrayPtr*)0) list_node->Empty();
wxStringTokenizer token( input, "\n");
int num = token.CountTokens();
bool found_start = false;
wxString entry;
wxString command;
wxString file;
wxString action;
wxString hash;
uMod_TreeViewNode_ArrayPtr buffer;
buffer.Add(node);
for (int i=0; imyElement->File() = entry_token.GetNextToken().Trim(true).Trim(false);
node->myElement->Title() = entry_token.GetNextToken().Trim(true).Trim(false);
action = entry_token.GetNextToken().Trim(true).Trim(false);
if (action=="D") node->myElement->Status() = uMod_ModElement::Deactivate;
else if (action=="A") node->myElement->Status() = uMod_ModElement::Activate;
else node->myElement->Status() = uMod_ModElement::NONE;
node->myElement->Author() = entry_token.GetNextToken().Trim(true).Trim(false);
node->myElement->Comment() = entry_token.GetNextToken().Trim(true).Trim(false);
}
continue;
}
if (command=="BEGIN_GROUP")
{
uMod_ModElement *element = new uMod_ModElement(uMod_ModElement::Group, uMod_ModElement::NONE);
uMod_TreeViewNode *node_group = new uMod_TreeViewNode(buffer.Last(), element);
element->Title() = entry_token.GetNextToken().Trim(true).Trim(false);
action = entry_token.GetNextToken().Trim(true).Trim(false);
if (action=="D") element->Status() = uMod_ModElement::Deactivate;
else if (action=="A") element->Status() = uMod_ModElement::Activate;
else element->Status() = uMod_ModElement::NONE;
element->Author() = entry_token.GetNextToken().Trim(true).Trim(false);
element->Comment() = entry_token.GetNextToken().Trim(true).Trim(false);
if (list_node != (uMod_TreeViewNode_ArrayPtr*)0) list_node->Add(node_group);
// add node to the last group
buffer.Last()->Append( node_group);
element->Release();
//set this group to the last group
buffer.Add( node_group);
}
else if (command=="END_GROUP")
{
if (buffer.GetCount()==0)
{
LastError << "There is an END_GROUP without a previous BEGIN_GROUP";
return -1;
}
buffer.RemoveAt(buffer.GetCount()-1);
}
else if (command=="TEXTURE")
{
if (buffer.GetCount()==0) continue;
file = entry_token.GetNextToken().Trim(true).Trim(false);
hash = entry_token.GetNextToken().Trim(true).Trim(false);
if (file.IsEmpty())
continue;
if (hash.IsEmpty())
continue;
DWORD64 temp_hash;
if (!hash.ToULongLong( &temp_hash, 16))
{
LastError << Language->Error_Hash << "\n";
continue;
}
uMod_TextureElement *texture = new uMod_TextureElement();
texture->File() = file;
texture->Hash() = temp_hash;
texture->Title() = entry_token.GetNextToken().Trim(true).Trim(false);
action = entry_token.GetNextToken().Trim(true).Trim(false);
if (action=="D") texture->Status() = uMod_ModElement::Deactivate;
else texture->Status() = uMod_TextureElement::Activate;
texture->Author() = entry_token.GetNextToken().Trim(true).Trim(false);
texture->Comment() = entry_token.GetNextToken().Trim(true).Trim(false);
uMod_TreeViewNode *node_texture = new uMod_TreeViewNode( buffer.Last(), texture);
if (list_node != (uMod_TreeViewNode_ArrayPtr*)0) list_node->Add(node_texture);
// add node to the last group
buffer.Last()->Append( node_texture);
texture->Release();
}
}
if (!found_start)
{
LastError = "Did not find 'PACKAGE' directive\n";
return -1;
}
return 0;
}
int uMod_TreeViewModel::Node2String( wxString &out, uMod_TreeViewNode* node)
{
if (node==(uMod_TreeViewNode*)0) return -1;
out.Empty();
uMod_TreeViewNode_ArrayPtr buffer; // this array store the "path" to the current group node (parent0->parent1->parent2->current_group)
wxArrayInt counter; // this array store the actual index position for each group in the hierarchy
if (node->myElement->Type() != uMod_ModElement::Group) return -1;
out << "\nPACKAGE|" << node->myElement->File() << "|";
out << node->myElement->Title() << "|";
if (node->myElement->Status() == uMod_ModElement::Activate) out << "A";
else if (node->myElement->Status() == uMod_ModElement::Deactivate) out << "D";
out << "|" << node->myElement->Author();
out << "|" << node->myElement->Comment() << "\n\n";
buffer.Add( node);
counter.Add(0);
/*
if (node->myElement->Type() == uMod_ModElement::Group)
{
buffer.Add(node);
counter.Add(0);
out << "\nBEGIN_GROUP|"<myElement->Title() << "|";
if (node->myElement->Status() == uMod_ModElement::Activate) out << "A";
else if (node->myElement->Status() == uMod_ModElement::Deactivate) out << "D";
out << "|" << node->myElement->Author();
out << "|" << node->myElement->Comment();
out << "\n\n";
*/
while (!buffer.IsEmpty())
{
int pos = buffer.GetCount()-1;
unsigned int index = counter[pos];
if (index < buffer[pos]->myChildren.GetCount()) // it has still childrens
{
if (buffer[pos]->myChildren[index]->myElement->Type() == uMod_ModElement::Group)
{
uMod_TreeViewNode* node_child = buffer[pos]->myChildren[index];
out << "\nBEGIN_GROUP|"<< node_child->myElement->Title() << "|";
if (node_child->myElement->Status() == uMod_ModElement::Activate) out << "A";
else if (node_child->myElement->Status() == uMod_ModElement::Deactivate) out << "D";
out << "|" << node_child->myElement->Author();
out << "|" << node_child->myElement->Comment();
out << "\n";
buffer.Add(node_child);
counter.Add(0);
}
else if (buffer[pos]->myChildren[index]->myElement->Type() == uMod_ModElement::Texture)
{
uMod_TextureElement *tex = (uMod_TextureElement*) buffer[pos]->myChildren[index]->myElement;
out << "TEXTURE|"<< tex->File() << "|" ;
out << wxString::Format("%#llX", tex->Hash()) << "|";
out << tex->Title() << "|";
if (tex->Status() == uMod_ModElement::Deactivate) out << "D";
out << "|" << tex->Author();
out << "|" << tex->Comment();
out << "\n";
}
counter[pos]++;
}
else // finished this group
{
buffer.RemoveAt(pos);
counter.RemoveAt(pos);
if (buffer.GetCount()>0) out << "END_GROUP\n";
}
}
/*
}
else if (node->myElement->Type()==uMod_ModElement::Texture)
{
uMod_TextureElement *tex = (uMod_TextureElement*) node->myElement;
out << "TEXTURE|"<< tex->File() << "|" ;
out << wxString::Format("%#lX", tex->Hash()) << "|";
out << tex->Title() << "|";
if (tex->Status() == uMod_ModElement::Deactivate) out << "D";
out << "|" << tex->Author();
out << "|" << tex->Comment();
out << "\n\n";
}
*/
return 0;
}
/*
bool uMod_TreeViewModel::IsSameNod(uMod_TreeViewNode* a, uMod_TreeViewNode* b)
{
// at first we test for object specific stats
if (a->myElement->Type()==uMod_ModElement::Group && b->myElement->Type()==uMod_ModElement::Group)
{
//title must be the same
if (a->myElement->Title() != b->myElement->Title()) return false;
}
else if (a->myElement->Type()==uMod_ModElement::Texture && b->myElement->Type()==uMod_ModElement::Texture)
{
uMod_TextureElement *tex_a = (uMod_TextureElement*) a->myElement;
uMod_TextureElement *tex_b = (uMod_TextureElement*) b->myElement;
//Hash, Title, and File must be the same
if (tex_a->Hash() != tex_b->Hash()) return false;
if (tex_a->Title() != tex_b->Title()) return false;
if (tex_a->File() != tex_b->File()) return false;
}
else return false; //not the same objects
// now we compare their parents
// the title of their parents must be the same
if (a->GetParent()!=(uMod_TreeViewNode*)0)
{
if (b->GetParent()!=(uMod_TreeViewNode*)0)
{
if (a->GetParent()->myElement->Title() == b->GetParent()->myElement->Title()) return true;
else return false;
}
else return false;
}
else if (b->GetParent()!=(uMod_TreeViewNode*)0) return false;
else return true; //both are root textures
}
*/