Commit 7dbcbf6d authored by jean-pierre charras's avatar jean-pierre charras

Kicad manager: cleanup code, remove dead or not working code. Fix minor isssues

parent 7ae228d7
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <wxEeschemaStruct.h> #include <wxEeschemaStruct.h>
#include <general.h> #include <general.h>
//#include <protos.h>
#include <viewlib_frame.h> #include <viewlib_frame.h>
#include <class_library.h> #include <class_library.h>
#include <hotkeys.h> #include <hotkeys.h>
......
...@@ -77,94 +77,11 @@ wxString TREEPROJECT_ITEM::GetDir() const ...@@ -77,94 +77,11 @@ wxString TREEPROJECT_ITEM::GetDir() const
wxFileName filename = wxFileName( m_FileName ); wxFileName filename = wxFileName( m_FileName );
filename.MakeRelativeTo( wxGetCwd() ); wxString dir = filename.GetPath();
wxArrayString dirs = filename.GetDirs();
wxString dir;
for( unsigned int i = 0; i < dirs.Count(); i++ )
{
dir += dirs[i] + filename.GetPathSeparator();
}
return dir; return dir;
} }
// Move the object to dest
void TREEPROJECT_ITEM::Move( TREEPROJECT_ITEM* dest )
{
// function not safe.
return;
const wxString sep = wxFileName().GetPathSeparator();
if( m_Type == TREE_DIRECTORY )
return;
if( !dest )
return;
if( m_parent != dest->m_parent )
return; // Can not cross move!
if( dest == this )
return; // Can not move to ourself...
wxTreeItemId parent = m_parent->GetItemParent( GetId() );
if( dest == dynamic_cast<TREEPROJECT_ITEM*>( m_parent->GetItemData( parent ) ) )
return; // same parent ?
// We need to create a new item from us, and move
// data to there ...
// First move file on the disk
wxFileName fname( m_FileName );
wxString destName;
if( !dest->GetDir().IsEmpty() )
destName = dest->GetDir() + sep;
destName += fname.GetFullName();
if( destName == GetFileName() )
return; // Same place ??
// Move the file on the disk:
if( !wxRenameFile( GetFileName(), destName, false ) )
{
wxMessageDialog( m_parent, _( "Unable to move file ... " ),
_( "Permission error ?" ), wxICON_ERROR | wxOK );
return;
}
SetFileName( destName );
if( TREE_DIRECTORY != GetType() )
{
// Move the tree item itself now:
wxTreeItemId oldId = GetId();
int i = m_parent->GetItemImage( oldId );
wxString text = m_parent->GetItemText( oldId );
// Bye bye old Id :'(
wxTreeItemId newId = m_parent->AppendItem( dest->GetId(), text, i );
m_parent->SetItemData( newId, this );
m_parent->SetItemData( oldId, NULL );
m_parent->Delete( oldId );
}
else
{
// We should move recursively all files, but that's quite boring
// let's just refresh that's all ... TODO (change this to a better code ...)
wxCommandEvent dummy;
dynamic_cast<TREEPROJECTFILES*>( m_parent )->GetParent()->m_Parent->OnRefresh( dummy );
}
}
/* rename the file checking if extension change occurs */ /* rename the file checking if extension change occurs */
bool TREEPROJECT_ITEM::Rename( const wxString& name, bool check ) bool TREEPROJECT_ITEM::Rename( const wxString& name, bool check )
{ {
...@@ -218,7 +135,9 @@ type.\n Do you want to continue ?" ...@@ -218,7 +135,9 @@ type.\n Do you want to continue ?"
return false; return false;
} }
#ifndef KICAD_USE_FILES_WATCHER
SetFileName( newFile ); SetFileName( newFile );
#endif
return true; return true;
} }
...@@ -263,7 +182,7 @@ bool TREEPROJECT_ITEM::Delete( bool check ) ...@@ -263,7 +182,7 @@ bool TREEPROJECT_ITEM::Delete( bool check )
} }
/* Called under item activation */ // Called under item activation
void TREEPROJECT_ITEM::Activate( TREE_PROJECT_FRAME* prjframe ) void TREEPROJECT_ITEM::Activate( TREE_PROJECT_FRAME* prjframe )
{ {
wxString sep = wxFileName().GetPathSeparator(); wxString sep = wxFileName().GetPathSeparator();
......
...@@ -15,7 +15,6 @@ public: ...@@ -15,7 +15,6 @@ public:
bool m_WasPopulated; // True the name is a directory, and its content was read bool m_WasPopulated; // True the name is a directory, and its content was read
private: private:
wxTreeCtrl* m_parent; wxTreeCtrl* m_parent;
wxMenu m_fileMenu;
int m_state; int m_state;
public: public:
...@@ -50,17 +49,15 @@ public: ...@@ -50,17 +49,15 @@ public:
m_FileName = name; m_FileName = name;
} }
/**
* @return the path of an item.
* if this item is a directory, returns the stored filename
* if this is a file, returns its path
*/
wxString GetDir() const; wxString GetDir() const;
bool Rename( const wxString& name, bool check = true ); bool Rename( const wxString& name, bool check = true );
bool Delete( bool check = true ); bool Delete( bool check = true );
void Move( TREEPROJECT_ITEM* dest );
void Activate( TREE_PROJECT_FRAME* prjframe ); void Activate( TREE_PROJECT_FRAME* prjframe );
const wxMenu* GetMenu()
{
return &m_fileMenu;
}
void SetState( int state ); void SetState( int state );
}; };
...@@ -106,14 +106,11 @@ const wxString TextFileWildcard( wxT( "Text files (*.txt)|*.txt" ) ); ...@@ -106,14 +106,11 @@ const wxString TextFileWildcard( wxT( "Text files (*.txt)|*.txt" ) );
* only useful files are shown. * only useful files are shown.
*/ */
/*****************************************************************************/ /*****************************************************************************/
BEGIN_EVENT_TABLE( TREE_PROJECT_FRAME, wxSashLayoutWindow ) BEGIN_EVENT_TABLE( TREE_PROJECT_FRAME, wxSashLayoutWindow )
EVT_TREE_ITEM_ACTIVATED( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnSelect ) EVT_TREE_ITEM_ACTIVATED( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnSelect )
EVT_TREE_ITEM_EXPANDED( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnExpand ) EVT_TREE_ITEM_EXPANDED( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnExpand )
EVT_TREE_ITEM_RIGHT_CLICK( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnRight ) EVT_TREE_ITEM_RIGHT_CLICK( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnRight )
EVT_TREE_BEGIN_DRAG( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnDragStart )
EVT_TREE_END_DRAG( ID_PROJECT_TREE, TREE_PROJECT_FRAME::OnDragEnd )
EVT_MENU( ID_PROJECT_TXTEDIT, TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor ) EVT_MENU( ID_PROJECT_TXTEDIT, TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor )
EVT_MENU( ID_PROJECT_NEWDIR, TREE_PROJECT_FRAME::OnCreateNewDirectory ) EVT_MENU( ID_PROJECT_NEWDIR, TREE_PROJECT_FRAME::OnCreateNewDirectory )
EVT_MENU( ID_PROJECT_DELETE, TREE_PROJECT_FRAME::OnDeleteFile ) EVT_MENU( ID_PROJECT_DELETE, TREE_PROJECT_FRAME::OnDeleteFile )
...@@ -134,8 +131,6 @@ TREE_PROJECT_FRAME::TREE_PROJECT_FRAME( KICAD_MANAGER_FRAME* parent ) : ...@@ -134,8 +131,6 @@ TREE_PROJECT_FRAME::TREE_PROJECT_FRAME( KICAD_MANAGER_FRAME* parent ) :
{ {
m_Parent = parent; m_Parent = parent;
m_TreeProject = NULL; m_TreeProject = NULL;
wxMenuItem* item;
m_PopupMenu = NULL;
#ifdef KICAD_USE_FILES_WATCHER #ifdef KICAD_USE_FILES_WATCHER
m_watcher = NULL; m_watcher = NULL;
Connect( wxEVT_FSWATCHER, Connect( wxEVT_FSWATCHER,
...@@ -154,156 +149,18 @@ TREE_PROJECT_FRAME::TREE_PROJECT_FRAME( KICAD_MANAGER_FRAME* parent ) : ...@@ -154,156 +149,18 @@ TREE_PROJECT_FRAME::TREE_PROJECT_FRAME( KICAD_MANAGER_FRAME* parent ) :
m_filters.push_back( wxT( "^no KiCad files found" ) ); m_filters.push_back( wxT( "^no KiCad files found" ) );
for( int i = 0; i < TREE_MAX; i++ )
m_ContextMenus.push_back( new wxMenu() );
wxMenu* menu;
// New files context menu:
wxMenu* menus[2];
menus[0] = m_ContextMenus[TREE_DIRECTORY];
menus[1] = m_ContextMenus[TREE_PROJECT];
for( int i = 0; i < 2; i++ )
{
menu = menus[i];
// ID_PROJECT_NEWDIR
item = new wxMenuItem( menu,
ID_PROJECT_NEWDIR,
_( "New D&irectory" ),
_( "Create a New Directory" ) );
item->SetBitmap( KiBitmap( directory_xpm ) );
menu->Append( item );
}
// Put the Rename and Delete file menu commands:
for( int i = TREE_PROJECT + 1; i < TREE_MAX; i++ )
{
menu = m_ContextMenus[i];
// ID_PROJECT_RENAME
item = new wxMenuItem( menu, ID_PROJECT_RENAME,
TREE_DIRECTORY != i ? _( "&Rename file" ) :
_( "&Rename directory" ),
TREE_DIRECTORY != i ? _( "Rename file" ) :
_( "Rename directory" ) );
item->SetBitmap( KiBitmap( right_xpm ) );
menu->Append( item );
if( TREE_DIRECTORY != i )
{
// ID_PROJECT_TXTEDIT
item = new wxMenuItem( menu,
ID_PROJECT_TXTEDIT,
_( "&Edit in a text editor" ),
_( "Open the file in a Text Editor" ) );
item->SetBitmap( KiBitmap( icon_txt_xpm ) );
menu->Append( item );
}
// ID_PROJECT_DELETE
item = new wxMenuItem( menu,
ID_PROJECT_DELETE,
TREE_DIRECTORY != i ? _( "&Delete File" ) :
_( "&Delete Directory" ),
TREE_DIRECTORY != i ? _( "Delete the File" ) :
_( "Delete the Directory and its content" ) );
item->SetBitmap( KiBitmap( delete_xpm ) );
menu->Append( item );
}
ReCreateTreePrj(); ReCreateTreePrj();
} }
TREE_PROJECT_FRAME::~TREE_PROJECT_FRAME() TREE_PROJECT_FRAME::~TREE_PROJECT_FRAME()
{ {
size_t i;
wxMenu* menu;
for( i = 0; i < m_ContextMenus.size(); i++ )
{
menu = m_ContextMenus[i];
delete menu;
}
if( m_PopupMenu )
delete m_PopupMenu;
#ifdef KICAD_USE_FILES_WATCHER #ifdef KICAD_USE_FILES_WATCHER
delete m_watcher; delete m_watcher;
#endif #endif
} }
/**
* @brief Allowing drag & drop of file other than the currently opened project
*/
/*****************************************************************************/
void TREE_PROJECT_FRAME::OnDragStart( wxTreeEvent& event )
/*****************************************************************************/
{
/* Ensure item is selected
* (Under Windows start drag does not activate the item)
*/
wxTreeItemId curr_item = event.GetItem();
m_TreeProject->SelectItem( curr_item );
TREEPROJECT_ITEM* data = GetSelectedData();
if( data->GetFileName() == m_Parent->m_ProjectFileName.GetFullPath() )
return;
wxImage img = m_TreeProject->GetImageList()->GetBitmap( data->GetType() - 1 ).ConvertToImage();
m_DragCursor = wxCursor( img );
m_Parent->wxWindow::SetCursor( (wxCursor&) m_DragCursor );
event.Allow();
}
/*****************************************************************************/
void TREE_PROJECT_FRAME::OnDragEnd( wxTreeEvent& event )
/*****************************************************************************/
{
m_Parent->SetCursor( wxNullCursor );
TREEPROJECT_ITEM* source_data = GetSelectedData();
wxTreeItemId dest = event.GetItem();
if( !dest.IsOk() )
return; // Cancelled ...
TREEPROJECT_ITEM* destData =
dynamic_cast<TREEPROJECT_ITEM*>( m_TreeProject->GetItemData( dest ) );
if( !destData )
return;
// the item can be a member of the selected directory; get the directory itself
if( TREE_DIRECTORY != destData->GetType()
&& !m_TreeProject->ItemHasChildren( dest ) )
{
// the item is a member of the selected directory; get the directory itself
dest = m_TreeProject->GetItemParent( dest );
if( !dest.IsOk() )
return; // no parent ?
// Select the right destData:
destData =
dynamic_cast<TREEPROJECT_ITEM*>( m_TreeProject->GetItemData( dest ) );
if( !destData )
return;
}
source_data->Move( destData );
}
/*****************************************************************************/ /*****************************************************************************/
void TREE_PROJECT_FRAME::RemoveFilter( const wxString& filter ) void TREE_PROJECT_FRAME::RemoveFilter( const wxString& filter )
/*****************************************************************************/ /*****************************************************************************/
...@@ -319,16 +176,6 @@ void TREE_PROJECT_FRAME::RemoveFilter( const wxString& filter ) ...@@ -319,16 +176,6 @@ void TREE_PROJECT_FRAME::RemoveFilter( const wxString& filter )
} }
/**
* @brief TODO
*/
/*****************************************************************************/
wxMenu* TREE_PROJECT_FRAME::GetContextMenu( int type )
/*****************************************************************************/
{
return m_ContextMenus[type];
}
/** /**
* Called by the popup menu in the tree frame * Called by the popup menu in the tree frame
...@@ -379,7 +226,11 @@ void TREE_PROJECT_FRAME::OnCreateNewDirectory( wxCommandEvent& event ) ...@@ -379,7 +226,11 @@ void TREE_PROJECT_FRAME::OnCreateNewDirectory( wxCommandEvent& event )
return; return;
if( wxMkdir( subdir ) ) if( wxMkdir( subdir ) )
{
#ifndef KICAD_USE_FILES_WATCHER
AddItemToTreeProject( subdir, root ); AddItemToTreeProject( subdir, root );
#endif
}
} }
...@@ -578,40 +429,52 @@ bool TREE_PROJECT_FRAME::AddItemToTreeProject( const wxString& aName, ...@@ -578,40 +429,52 @@ bool TREE_PROJECT_FRAME::AddItemToTreeProject( const wxString& aName,
// at the top of the hierarchy. The schematic is top level only if // at the top of the hierarchy. The schematic is top level only if
// there is a line in the header saying: // there is a line in the header saying:
// "Sheet 1 " // "Sheet 1 "
// However if the file has the same name as the project, it is always
// shown, because it is expected the root sheet.
// (and to fix an issue (under XP but could exist under other OS),
// when a .sch file is created, the file
// create is sent to the wxFileSystemWatcher, but the file still has 0 byte
// so it cannot detected as root sheet
// This is an ugly fix.
if( isSchematic ) if( isSchematic )
{ {
char line[128]; // small because we just need a few bytes from the start of a line wxString fullFileName = aName.BeforeLast( '.' );
FILE* fp; wxString rootName;
TREEPROJECT_ITEM* itemData = GetItemIdData( m_root );
wxString FullFileName = aName; if( itemData )
rootName = itemData->m_FileName.BeforeLast( '.' );
fp = wxFopen( FullFileName, wxT( "rt" ) ); if( fullFileName != rootName )
if( fp == NULL )
{ {
return false; char line[128]; // small because we just need a few bytes from the start of a line
} FILE* fp;
addFile = false; fullFileName = aName;
fp = wxFopen( fullFileName, wxT( "rt" ) );
// check the first 100 lines for the "Sheet 1" string if( fp == NULL )
int l =0; return false;
for( int i = 0; i<100; ++i, l++ )
{ addFile = false;
if( !fgets( line, sizeof(line), fp ) )
break;
if( !strncmp( line, "Sheet 1 ", 8 ) ) // check the first 100 lines for the "Sheet 1" string
for( int i = 0; i<100; ++i )
{ {
addFile = true; if( !fgets( line, sizeof(line), fp ) )
break; break;
if( !strncmp( line, "Sheet 1 ", 8 ) )
{
addFile = true;
break;
}
} }
}
fclose( fp ); fclose( fp );
if( !addFile ) if( !addFile )
return false; // it is a non-top-level schematic return false; // it is a non-top-level schematic
}
} }
for( int i = TREE_PROJECT; i < TREE_MAX; i++ ) for( int i = TREE_PROJECT; i < TREE_MAX; i++ )
...@@ -728,7 +591,7 @@ void TREE_PROJECT_FRAME::ReCreateTreePrj() ...@@ -728,7 +591,7 @@ void TREE_PROJECT_FRAME::ReCreateTreePrj()
m_TreeProject->SetItemData( rootcellule, m_TreeProject->SetItemData( rootcellule,
new TREEPROJECT_ITEM( TREE_PROJECT, new TREEPROJECT_ITEM( TREE_PROJECT,
wxEmptyString, fn.GetFullPath(),
m_TreeProject ) ); m_TreeProject ) );
// Now adding all current files if available // Now adding all current files if available
...@@ -776,11 +639,6 @@ void TREE_PROJECT_FRAME::OnRight( wxTreeEvent& Event ) ...@@ -776,11 +639,6 @@ void TREE_PROJECT_FRAME::OnRight( wxTreeEvent& Event )
/* Ensure item is selected (Under Windows right click does not select the item) */ /* Ensure item is selected (Under Windows right click does not select the item) */
m_TreeProject->SelectItem( curr_item ); m_TreeProject->SelectItem( curr_item );
// Delete and recreate the context menu
delete ( m_PopupMenu );
m_PopupMenu = new wxMenu();
// Get the current filename:
tree_data = GetSelectedData(); tree_data = GetSelectedData();
if( !tree_data ) if( !tree_data )
...@@ -789,41 +647,45 @@ void TREE_PROJECT_FRAME::OnRight( wxTreeEvent& Event ) ...@@ -789,41 +647,45 @@ void TREE_PROJECT_FRAME::OnRight( wxTreeEvent& Event )
tree_id = tree_data->GetType(); tree_id = tree_data->GetType();
FullFileName = tree_data->GetFileName(); FullFileName = tree_data->GetFileName();
// copy menu contents in order of the next array: wxMenu popupMenu;
wxMenu* menus[] =
{
GetContextMenu( tree_id ),
const_cast<wxMenu*>( tree_data->GetMenu() )
};
for( unsigned int j = 0; j < sizeof(menus) / sizeof(wxMenu*); j++ ) switch( tree_id )
{ {
wxMenu* menu = menus[j]; case TREE_PROJECT:
AddMenuItem( &popupMenu, ID_PROJECT_NEWDIR,
if( !menu ) _( "New D&irectory" ),
continue; _( "Create a New Directory" ),
KiBitmap( directory_xpm ) );
break;
wxMenuItemList list = menu->GetMenuItems(); case TREE_DIRECTORY:
AddMenuItem( &popupMenu, ID_PROJECT_NEWDIR,
_( "New D&irectory" ),
_( "Create a New Directory" ),
KiBitmap( directory_xpm ) );
AddMenuItem( &popupMenu, ID_PROJECT_DELETE,
_( "&Delete Directory" ),
_( "Delete the Directory and its content" ),
KiBitmap( delete_xpm ) );
break;
for( unsigned int i = 0; i < list.GetCount(); i++ ) default:
{ AddMenuItem( &popupMenu, ID_PROJECT_TXTEDIT,
// Grrrr! wxMenu does not have any copy constructor !! (do it by hand) _( "&Edit in a text editor" ),
wxMenuItem* src = list[i]; _( "Open the file in a Text Editor" ),
wxString label = src->GetItemLabelText(); KiBitmap( icon_txt_xpm ) );
AddMenuItem( &popupMenu, ID_PROJECT_RENAME,
// for obscure reasons, the & is translated into _ ... so replace it _( "&Rename file" ),
label.Replace( wxT( "_" ), wxT( "&" ), true ); _( "Rename file" ),
wxMenuItem* item = new wxMenuItem( m_PopupMenu, src->GetId(), KiBitmap( right_xpm ) );
label, AddMenuItem( &popupMenu, ID_PROJECT_DELETE,
src->GetHelp(), src->GetKind() ); _( "&Delete File" ),
_( "Delete the Directory and its content" ),
item->SetBitmap( src->GetBitmap() ); KiBitmap( delete_xpm ) );
m_PopupMenu->Append( item ); break;
}
} }
if( m_PopupMenu ) PopupMenu( &popupMenu );
PopupMenu( m_PopupMenu );
} }
/* /*
...@@ -837,6 +699,9 @@ void TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor( wxCommandEvent& event ...@@ -837,6 +699,9 @@ void TREE_PROJECT_FRAME::OnOpenSelectedFileWithTextEditor( wxCommandEvent& event
if( !tree_data ) if( !tree_data )
return; return;
if( tree_data->GetType() == TREE_DIRECTORY )
return;
wxString FullFileName = tree_data->GetFileName(); wxString FullFileName = tree_data->GetFileName();
AddDelimiterString( FullFileName ); AddDelimiterString( FullFileName );
wxString editorname = wxGetApp().GetEditorName(); wxString editorname = wxGetApp().GetEditorName();
...@@ -893,8 +758,8 @@ void TREE_PROJECT_FRAME::OnRenameFile( wxCommandEvent& ) ...@@ -893,8 +758,8 @@ void TREE_PROJECT_FRAME::OnRenameFile( wxCommandEvent& )
} }
/** /*
* @brief TODO * called on a double click on an item
*/ */
/*****************************************************************************/ /*****************************************************************************/
void TREE_PROJECT_FRAME::OnSelect( wxTreeEvent& Event ) void TREE_PROJECT_FRAME::OnSelect( wxTreeEvent& Event )
......
...@@ -46,13 +46,10 @@ class TREE_PROJECT_FRAME : public wxSashLayoutWindow ...@@ -46,13 +46,10 @@ class TREE_PROJECT_FRAME : public wxSashLayoutWindow
public: public:
KICAD_MANAGER_FRAME* m_Parent; KICAD_MANAGER_FRAME* m_Parent;
TREEPROJECTFILES* m_TreeProject; TREEPROJECTFILES* m_TreeProject;
wxTreeItemId m_root;
private: private:
std::vector<wxMenu*> m_ContextMenus; wxTreeItemId m_root;
std::vector<wxString> m_filters; std::vector<wxString> m_filters;
wxMenu* m_PopupMenu;
wxCursor m_DragCursor;
wxCursor m_Default;
#ifdef KICAD_USE_FILES_WATCHER #ifdef KICAD_USE_FILES_WATCHER
wxFileSystemWatcher* m_watcher; // file system watcher (since wxWidgets 2.9.2) wxFileSystemWatcher* m_watcher; // file system watcher (since wxWidgets 2.9.2)
...@@ -73,7 +70,6 @@ public: ...@@ -73,7 +70,6 @@ public:
#endif #endif
protected: protected:
wxMenu* GetContextMenu( int type );
static wxString GetFileExt( TreeFileType type ); static wxString GetFileExt( TreeFileType type );
static wxString GetFileWildcard( TreeFileType type ); static wxString GetFileWildcard( TreeFileType type );
...@@ -94,10 +90,19 @@ protected: ...@@ -94,10 +90,19 @@ protected:
TREEPROJECT_ITEM* GetItemIdData( wxTreeItemId aId ); TREEPROJECT_ITEM* GetItemIdData( wxTreeItemId aId );
private: private:
/**
* Called on a double click on an item
*/
void OnSelect( wxTreeEvent& Event ); void OnSelect( wxTreeEvent& Event );
/**
* Called on a click on the + or - button of an item with children
*/
void OnExpand( wxTreeEvent& Event ); void OnExpand( wxTreeEvent& Event );
void OnDragStart( wxTreeEvent& event );
void OnDragEnd( wxTreeEvent& event ); /**
* Called on a right click on an item
*/
void OnRight( wxTreeEvent& Event ); void OnRight( wxTreeEvent& Event );
/** /**
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment