PATCH: making component choosing (much!) more usable

This commit is contained in:
Henner Zeller 2014-02-14 09:07:20 +01:00 committed by jean-pierre charras
commit 31fea1e766
9 changed files with 1728 additions and 80 deletions

View File

@ -19,6 +19,8 @@ set( EESCHEMA_DLGS
dialogs/dialog_bom.cpp
dialogs/dialog_bom_base.cpp
dialogs/dialog_bom_cfg_keywords.cpp
dialogs/dialog_choose_component.cpp
dialogs/dialog_choose_component_base.cpp
dialogs/dialog_lib_edit_text.cpp
dialogs/dialog_lib_edit_text_base.cpp
dialogs/dialog_edit_component_in_lib.cpp
@ -88,6 +90,7 @@ set( EESCHEMA_SRCS
files-io.cpp
find.cpp
getpart.cpp
component_tree_search_container.cpp
hierarch.cpp
hotkeys.cpp
libarch.cpp

View File

@ -0,0 +1,356 @@
/* -*- c++ -*-
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
* Copyright (C) 2014 KiCad Developers, see change_log.txt for contributors.
*
* This program 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.
*
* This program 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 this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <component_tree_search_container.h>
#include <algorithm>
#include <boost/foreach.hpp>
#include <set>
#include <wx/string.h>
#include <wx/tokenzr.h>
#include <wx/treectrl.h>
#include <wx/arrstr.h>
#include <class_library.h>
#include <macros.h>
// Each node gets this lowest score initially, without any matches applied. Matches
// will then increase this score depending on match quality.
// This way, an empty search string will result in all components being displayed as they
// have the minimum score. However, in that case, we avoid expanding all the nodes asd the
// result is very unspecific.
static const unsigned kLowestDefaultScore = 1;
struct COMPONENT_TREE_SEARCH_CONTAINER::TREE_NODE
{
TREE_NODE(TREE_NODE* aParent, CMP_LIBRARY* aOwningLib,
const wxString& aName, const wxString& aDisplayInfo,
const wxString& aSearchText,
bool aNormallyExpanded = false)
: parent( aParent ),
lib( aOwningLib ),
normally_expanded( aNormallyExpanded ),
name( aName ),
display_info( aDisplayInfo ),
match_name( aName.Lower() ),
search_text( aSearchText.Lower() ),
match_score( 0 ), previous_score( 0 )
{
}
TREE_NODE* parent; // NULL if library, pointer to lib when component.
CMP_LIBRARY* lib; // Owning library of this component.
bool normally_expanded; // If this is a parent node, should it be unfolded ?
wxString name; // Exact name as displayed to the user.
wxString display_info; // Additional info displayed in the tree (description..)
wxString match_name; // Preprocessed: lowercased display name.
wxString search_text; // Other lowercase text (keywords, description..) to search in.
unsigned match_score; // Result-Score after UpdateSearchTerm()
unsigned previous_score; // Optimization: used to see if we need any tree update.
wxTreeItemId tree_id; // Tree-ID if stored in the tree (if match_score > 0).
};
// Sort tree nodes by reverse match-score (bigger is first), then alphabetically.
// Library nodes (i.e. the ones that don't have a parent) are always sorted before any
// leaf nodes.
bool COMPONENT_TREE_SEARCH_CONTAINER::scoreComparator( const TREE_NODE* a1, const TREE_NODE* a2 )
{
if ( a1->parent == NULL && a2->parent != NULL )
return true;
if ( a1->parent != NULL && a2->parent == NULL )
return false;
if ( a1->match_score != a2->match_score )
return a1->match_score > a2->match_score; // biggest first.
if (a1->parent != a2->parent)
return a1->parent->match_name.Cmp(a2->parent->match_name) < 0;
return a1->match_name.Cmp( a2->match_name ) < 0;
}
COMPONENT_TREE_SEARCH_CONTAINER::COMPONENT_TREE_SEARCH_CONTAINER()
: tree( NULL )
{
}
COMPONENT_TREE_SEARCH_CONTAINER::~COMPONENT_TREE_SEARCH_CONTAINER()
{
BOOST_FOREACH( TREE_NODE* node, nodes )
delete node;
nodes.clear();
}
void COMPONENT_TREE_SEARCH_CONTAINER::SetPreselectNode( const wxString& aComponentName )
{
preselect_node_name = aComponentName.Lower();
}
void COMPONENT_TREE_SEARCH_CONTAINER::SetTree( wxTreeCtrl* aTree )
{
tree = aTree;
UpdateSearchTerm( wxEmptyString );
}
void COMPONENT_TREE_SEARCH_CONTAINER::AddLibrary( CMP_LIBRARY& aLib )
{
wxArrayString all_comp;
aLib.GetEntryNames( all_comp );
AddComponentList( aLib.GetName(), all_comp, &aLib, false );
}
void COMPONENT_TREE_SEARCH_CONTAINER::AddComponentList( const wxString& aNodeName,
const wxArrayString& aComponentNameList,
CMP_LIBRARY* aOptionalLib,
bool aNormallyExpanded )
{
TREE_NODE* parent_node = new TREE_NODE( NULL, NULL, aNodeName, wxEmptyString, wxEmptyString,
aNormallyExpanded );
nodes.push_back( parent_node );
BOOST_FOREACH( const wxString& cName, aComponentNameList )
{
LIB_COMPONENT *c;
if (aOptionalLib)
c = aOptionalLib->FindComponent( cName );
else
c = CMP_LIBRARY::FindLibraryComponent( cName, wxEmptyString );
if (c == NULL)
continue;
wxString keywords, descriptions;
wxString display_info;
for ( size_t i = 0; i < c->GetAliasCount(); ++i )
{
LIB_ALIAS *a = c->GetAlias( i );
keywords += a->GetKeyWords();
descriptions += a->GetDescription();
if ( display_info.empty() && !a->GetDescription().empty() )
{
// Preformatting. Unfortunately, the tree widget doesn't have columns
display_info.Printf( wxT(" %s[ %s ]"),
( cName.length() <= 8 ) ? wxT("\t\t") : wxT("\t"),
GetChars( a->GetDescription() ) );
}
}
// If there are no keywords, we give a couple of characters whitespace penalty. We want
// a component with a search-term found in the keywords score slightly higher than another
// component without keywords, but that term in the descriptions.
wxString search_text = ( !keywords.empty() ) ? keywords : wxT(" ");
search_text += descriptions;
nodes.push_back( new TREE_NODE( parent_node, c->GetLibrary(),
cName, display_info, search_text ) );
}
}
LIB_COMPONENT* COMPONENT_TREE_SEARCH_CONTAINER::GetSelectedComponent()
{
const wxTreeItemId& select_id = tree->GetSelection();
BOOST_FOREACH( TREE_NODE* node, nodes )
{
if ( node->match_score > 0 && node->tree_id == select_id && node->lib )
return node->lib->FindComponent( node->name );
}
return NULL;
}
// Creates a score depending on the position of a string match. If the position
// is 0 (= prefix match), this returns the maximum score. This degrades until
// pos == max, which returns a score of 0;
// Evertyhing else beyond that is just 0. Only values >= 0 allowed for position and max.
//
// @param aPosition is the position a string has been found in a substring.
// @param aMaximum is the maximum score this function returns.
// @return position dependent score.
static int matchPosScore(int aPosition, int aMaximum)
{
return ( aPosition < aMaximum ) ? aMaximum - aPosition : 0;
}
void COMPONENT_TREE_SEARCH_CONTAINER::UpdateSearchTerm( const wxString& aSearch )
{
if ( tree == NULL )
return;
// We score the list by going through it several time, essentially with a complexity
// of O(n). For the default library of 2000+ items, this typically takes less than 5ms
// on an i5. Good enough, no index needed.
// Initial AND condition: Leaf nodes are considered to match initially.
BOOST_FOREACH( TREE_NODE* node, nodes )
{
node->previous_score = node->match_score;
node->match_score = node->parent ? kLowestDefaultScore : 0; // start-match for leafs.
}
// Create match scores for each node for all the terms, that come space-separated.
// Scoring adds up values for each term according to importance of the match. If a term does
// not match at all, the result is thrown out of the results (AND semantics).
// From high to low
// - Exact match for a ccmponent name gives the highest score, trumping all.
// - A positional score depending of where a term is found as substring; prefix-match: high.
// - substring-match in library name.
// - substring match in keywords and descriptions with positional score. Keywords come
// first so contribute more to the score.
//
// This is of course subject to tweaking.
wxStringTokenizer tokenizer( aSearch );
while ( tokenizer.HasMoreTokens() )
{
const wxString term = tokenizer.GetNextToken().Lower();
BOOST_FOREACH( TREE_NODE* node, nodes )
{
if ( node->parent == NULL)
continue; // Library nodes are not scored here.
if ( node->match_score == 0)
continue; // Leaf node without score are out of the game.
// Keywords and description we only count if the match string is at
// least two characters long. That avoids spurious, low quality
// matches. Most abbreviations are at three characters long.
int found_pos;
if ( term == node->match_name )
node->match_score += 1000; // exact match. High score :)
else if ( (found_pos = node->match_name.Find( term ) ) != wxNOT_FOUND )
{
// Substring match. The earlier in the string the better. score += 20..40
node->match_score += matchPosScore( found_pos, 20 ) + 20;
}
else if ( node->parent->match_name.Find( term ) != wxNOT_FOUND )
node->match_score += 19; // parent name matches. score += 19
else if ( ( found_pos = node->search_text.Find( term ) ) != wxNOT_FOUND )
{
// If we have a very short string (like one or two letters), we don't want
// to accumulate scores if they just happen to be in keywords or description.
// For longer terms, we add scores 1..18 for positional match (higher in the
// front, where the keywords are). score += 0..18
node->match_score += ( ( term.length() >= 2 )
? matchPosScore( found_pos, 17 ) + 1
: 0 );
}
else
node->match_score = 0; // No match. That's it for this item.
}
}
// Parent nodes have the maximum score seen in any of their children.
unsigned highest_score_seen = 0;
bool any_change = false;
BOOST_FOREACH( TREE_NODE* node, nodes )
{
if ( node->parent == NULL )
continue;
any_change |= (node->previous_score != node->match_score);
node->parent->match_score = std::max( node->parent->match_score, node->match_score );
highest_score_seen = std::max( highest_score_seen, node->match_score );
}
// The tree update might be slow, so we want to bail out if there is no change.
if ( !any_change )
return;
// Now: sort all items according to match score, libraries first.
std::sort( nodes.begin(), nodes.end(), scoreComparator );
// Fill the tree with all items that have a match. Re-arranging, adding and removing changed
// items is pretty complex, so we just re-build the whole tree.
tree->Freeze();
tree->DeleteAllItems();
wxTreeItemId root = tree->AddRoot( wxEmptyString );
const TREE_NODE* first_match = NULL;
const TREE_NODE* preselected_node = NULL;
BOOST_FOREACH( TREE_NODE* node, nodes )
{
if ( node->match_score == 0 )
continue;
// If we have nodes that go beyond the default score, suppress nodes that
// have the default score. That can happen if they have an honary += 0 score due to
// some one-letter match in the keyword or description. In this case, we prefer matches
// that just have higher scores. Improves confusion (and performance as the tree has to
// display less items).
if ( highest_score_seen > kLowestDefaultScore && node->match_score == kLowestDefaultScore )
continue;
wxString node_text;
#if 0
// Node text with scoring information for debugging
node_text.Printf( wxT("%s (s=%u)%s"), GetChars(node->name),
node->match_score, GetChars(node->display_info));
#else
node_text = node->name + node->display_info;
#endif
node->tree_id = tree->AppendItem( ( node->parent == NULL ) ? root : node->parent->tree_id,
node_text);
// If we are a child node, we might need to expand.
if ( node->parent != NULL )
{
if ( node->match_score > kLowestDefaultScore )
{
tree->EnsureVisible( node->tree_id );
if ( first_match == NULL )
first_match = node; // The "I am feeling lucky" element.
}
if ( preselected_node == NULL && node->match_name == preselect_node_name )
preselected_node = node;
}
if ( node->parent == NULL && node->normally_expanded )
tree->Expand( node->tree_id );
}
if ( first_match ) // Highest score search match pre-selected.
tree->SelectItem( first_match->tree_id );
else if ( preselected_node ) // No search, so history item preselected.
tree->SelectItem( preselected_node->tree_id );
tree->Thaw();
}

View File

@ -0,0 +1,108 @@
/* -*- c++ -*-
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
* Copyright (C) 2014 KiCad Developers, see change_log.txt for contributors.
*
* This program 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.
*
* This program 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 this program; if not, you may find one here:
* http: *www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http: *www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <vector>
#include <wx/string.h>
class LIB_COMPONENT;
class CMP_LIBRARY;
class wxTreeCtrl;
class wxArrayString;
// class COMPONENT_TREE_SEARCH_CONTAINER
// A container for components that allows to search them matching their name, keywords
// and descripotions, updating a wxTreeCtrl with the results (toplevel nodes:
// libraries, leafs: components), scored by relevance.
//
// The scored result list is adpated on each update on the search-term: this allows
// to have a search-as-you-type experience.
class COMPONENT_TREE_SEARCH_CONTAINER
{
public:
COMPONENT_TREE_SEARCH_CONTAINER();
~COMPONENT_TREE_SEARCH_CONTAINER();
/** Function AddLibrary
* Add the components of this library to be searched.
* To be called in the setup phase to fill this container.
*
* @param aLib containting all the components to be added.
*/
void AddLibrary( CMP_LIBRARY& aLib );
/** Function AddComponentList
* Add the given list of components, given by name, to be searched.
* To be called in the setup phase to fill this container.
*
* @param aNodeName The parent node name the components will show up as leaf.
* @param aComponentNameList List of component names.
* @param aOptionalLib Library to look up the component names (if NULL: global lookup)
* @param aNormallyExpanded Should the node in the tree be expanded by default.
*/
void AddComponentList( const wxString& aNodeName, const wxArrayString& aComponentNameList,
CMP_LIBRARY* aOptionalLib, bool aNormallyExpanded );
/** Function SetPreselectNode
* Set the component name to be selected in absence of any search-result.
*
* @param aComponentName the component name to be selected.
*/
void SetPreselectNode( const wxString& aComponentName );
/** Function SetTree
* Set the tree to be manipulated.
* Each update of the search term will update the tree, with the most
* scoring component at the top and selected. If a preselect node is set, this
* is displayed. Does not take ownership of the tree.
*
* @param aTree that is to be modified on search updates.
*/
void SetTree( wxTreeCtrl* aTree );
/** Function UpdateSearchTerm
* Update the search string provided by the user and narrow down the result list.
*
* This string is a space-separated list of terms, each of which
* is applied to the components list to narrow it down. Results are scored by
* relevancy (e.g. exact match scores higher than prefix-match which in turn scores
* higher than substring match). This updates the search and tree on each call.
*
* @param aSearch is the user-provided search string.
*/
void UpdateSearchTerm( const wxString& aSearch );
/** Function GetSelectedComponent
*
* @return the selected component or NULL if there is none.
*/
LIB_COMPONENT* GetSelectedComponent();
private:
struct TREE_NODE;
static bool scoreComparator( const TREE_NODE* a1, const TREE_NODE* a2 );
std::vector<TREE_NODE*> nodes;
wxString preselect_node_name;
wxTreeCtrl* tree;
};

View File

@ -0,0 +1,275 @@
/*
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
* Copyright (C) 2014 KiCad Developers, see change_log.txt for contributors.
*
* This program 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.
*
* This program 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 this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <dialog_choose_component.h>
#include <set>
#include <boost/foreach.hpp>
#include <wx/tokenzr.h>
#include <class_library.h>
#include <component_tree_search_container.h>
#include <sch_base_frame.h>
// Work-around broken implementation in wxWidgets <=2.8 tree.
static wxTreeItemId fixedGetPrevVisible( const wxTreeCtrl& tree, const wxTreeItemId& item );
// Combine descriptions of all aliases from given component.
static wxString combineDescriptions( LIB_COMPONENT* aComponent )
{
std::set<wxString> descriptions;
for( size_t i = 0; i < aComponent->GetAliasCount(); ++i )
{
LIB_ALIAS* a = aComponent->GetAlias( i );
if ( !a->GetDescription().empty() )
descriptions.insert( a->GetDescription() );
}
wxString result;
BOOST_FOREACH( const wxString& s, descriptions )
result += s + wxT("\n");
return result;
}
// Combine keywords. Keywords come as a string, but are considered space-separated
// individual words. Return a string with a unique set of these.
static wxString combineKeywords( LIB_COMPONENT* aComponent )
{
std::set<wxString> keywords;
for( size_t i = 0; i < aComponent->GetAliasCount(); ++i )
{
LIB_ALIAS* a = aComponent->GetAlias( i );
wxStringTokenizer tokenizer( a->GetKeyWords() );
while ( tokenizer.HasMoreTokens() )
keywords.insert( tokenizer.GetNextToken() );
}
wxString result;
BOOST_FOREACH( const wxString& s, keywords )
result += s + wxT(" ");
return result;
}
DIALOG_CHOOSE_COMPONENT::DIALOG_CHOOSE_COMPONENT( wxWindow* aParent, const wxString& aTitle,
COMPONENT_TREE_SEARCH_CONTAINER* aContainer )
: DIALOG_CHOOSE_COMPONENT_BASE( aParent, wxID_ANY, aTitle ),
m_search_container( aContainer ),
m_selected_component( NULL ),
m_external_browser_requested( false ),
m_received_doubleclick_in_tree( false )
{
// TODO: restore last size user was choosing.
m_search_container->SetTree( m_libraryComponentTree );
m_searchBox->SetFocus();
m_componentDetails->SetEditable( false );
}
// After this dialog is done: return the component that has been selected, or an
// empty string if there is none.
wxString DIALOG_CHOOSE_COMPONENT::GetSelectedComponentName() const
{
if ( m_selected_component == NULL )
return wxEmptyString;
return m_selected_component->GetName();
}
void DIALOG_CHOOSE_COMPONENT::OnSearchBoxChange( wxCommandEvent& aEvent )
{
m_selected_component = NULL;
m_search_container->UpdateSearchTerm( m_searchBox->GetLineText(0) );
updateSelection();
}
void DIALOG_CHOOSE_COMPONENT::OnSearchBoxEnter( wxCommandEvent& aEvent )
{
EndModal( wxID_OK ); // We are done.
}
void DIALOG_CHOOSE_COMPONENT::SelectIfValid( const wxTreeItemId& aTreeId )
{
if ( aTreeId.IsOk() && aTreeId != m_libraryComponentTree->GetRootItem() )
m_libraryComponentTree->SelectItem( aTreeId );
}
void DIALOG_CHOOSE_COMPONENT::OnInterceptSearchBoxKey( wxKeyEvent& aKeyStroke )
{
// Cursor up/down are forwarded to the tree. This is done by intercepting some navigational
// keystrokes that normally would go to the text search box (which has the focus by default).
const wxTreeItemId sel = m_libraryComponentTree->GetSelection();
switch ( aKeyStroke.GetKeyCode() )
{
case WXK_UP:
SelectIfValid( fixedGetPrevVisible( *m_libraryComponentTree, sel ) );
break;
case WXK_DOWN:
SelectIfValid( m_libraryComponentTree->GetNextVisible( sel ) );
break;
default:
aKeyStroke.Skip(); // Pass on to search box.
break;
}
}
void DIALOG_CHOOSE_COMPONENT::OnTreeSelect( wxTreeEvent& aEvent )
{
updateSelection();
}
void DIALOG_CHOOSE_COMPONENT::OnDoubleClickTreeSelect( wxTreeEvent& aEvent )
{
updateSelection();
if ( m_selected_component == NULL )
return;
// Ok, got selection. We don't just end the modal dialog here, but
// wait for the MouseUp event to occur. Otherwise something (broken?)
// happens: the dialog will close and will deliver the 'MouseUp' event
// to the eeschema canvas, that will immediately place the component.
m_received_doubleclick_in_tree = true;
}
void DIALOG_CHOOSE_COMPONENT::OnTreeMouseUp( wxMouseEvent& aMouseEvent )
{
if ( m_received_doubleclick_in_tree )
EndModal( wxID_OK ); // We are done (see OnDoubleClickTreeSelect)
else
aMouseEvent.Skip(); // Let upstream handle it.
}
void DIALOG_CHOOSE_COMPONENT::OnStartComponentBrowser( wxMouseEvent& aEvent )
{
m_external_browser_requested = true;
EndModal( wxID_OK ); // We are done.
}
void DIALOG_CHOOSE_COMPONENT::updateSelection()
{
LIB_COMPONENT* selection = m_search_container->GetSelectedComponent();
if ( selection == m_selected_component )
return; // no change.
m_selected_component = selection;
m_componentDetails->Clear();
if ( m_selected_component == NULL )
return;
wxFont font_normal = m_componentDetails->GetFont();
wxFont font_bold = m_componentDetails->GetFont();
font_bold.SetWeight( wxFONTWEIGHT_BOLD );
wxTextAttr headline_attribute;
headline_attribute.SetFont(font_bold);
wxTextAttr text_attribute;
text_attribute.SetFont(font_normal);
const wxString description = combineDescriptions( selection );
if ( !description.empty() )
{
m_componentDetails->SetDefaultStyle( headline_attribute );
m_componentDetails->AppendText( _("Description\n") );
m_componentDetails->SetDefaultStyle( text_attribute );
m_componentDetails->AppendText( description );
m_componentDetails->AppendText( wxT("\n") );
}
const wxString keywords = combineKeywords( selection );
if ( !keywords.empty() )
{
m_componentDetails->SetDefaultStyle( headline_attribute );
m_componentDetails->AppendText( _("Keywords\n") );
m_componentDetails->SetDefaultStyle( text_attribute );
m_componentDetails->AppendText( keywords );
}
m_componentDetails->SetInsertionPoint( 0 ); // scroll up.
}
// The GetPrevVisible() method is broken in at least 2.8 wxWidgets. This is mostly copied
// verbatim from the latest 3.x source in which this is fixed.
// ( wxWidgets/src/generic/treectlg.cpp )
static wxTreeItemId fixedGetPrevVisible( const wxTreeCtrl& tree, const wxTreeItemId& item )
{
#if wxCHECK_VERSION( 3, 0, 0 )
return tree.GetPrevVisible(item);
#else
// find out the starting point
wxTreeItemId prevItem = tree.GetPrevSibling(item);
if ( !prevItem.IsOk() )
{
prevItem = tree.GetItemParent(item);
}
// find the first visible item after it
while ( prevItem.IsOk() && !tree.IsVisible(prevItem) )
{
prevItem = tree.GetNext(prevItem);
if ( !prevItem.IsOk() || prevItem == item )
{
// there are no visible items before item
return wxTreeItemId();
}
}
// from there we must be able to navigate until this item
while ( prevItem.IsOk() )
{
const wxTreeItemId nextItem = tree.GetNextVisible(prevItem);
if ( !nextItem.IsOk() || nextItem == item )
break;
prevItem = nextItem;
}
return prevItem;
#endif
}

View File

@ -0,0 +1,69 @@
/* -*- c++ -*-
* This program source code file is part of KiCad, a free EDA CAD application.
*
* Copyright (C) 2014 Henner Zeller <h.zeller@acm.org>
* Copyright (C) 2014 KiCad Developers, see change_log.txt for contributors.
*
* This program 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.
*
* This program 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 this program; if not, you may find one here:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
* or you may search the http://www.gnu.org website for the version 2 license,
* or you may write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <dialog_choose_component_base.h>
class COMPONENT_TREE_SEARCH_CONTAINER;
class LIB_COMPONENT;
class wxTreeItemId;
class DIALOG_CHOOSE_COMPONENT : public DIALOG_CHOOSE_COMPONENT_BASE
{
public:
DIALOG_CHOOSE_COMPONENT( wxWindow* aParent, const wxString& aTitle,
COMPONENT_TREE_SEARCH_CONTAINER* aSearch_container );
/** Function GetSelectedComponentName
* To be called after this dialog returns from ShowModal().
*
* @return the component that has been selected, or an empty string if there is none.
*/
wxString GetSelectedComponentName() const;
/** Function IsExternalBrowserSelected
*
* @return true, iff the browser pressed the browsing button.
*/
bool IsExternalBrowserSelected() const { return m_external_browser_requested; }
protected:
virtual void OnSearchBoxChange( wxCommandEvent& aEvent );
virtual void OnSearchBoxEnter( wxCommandEvent& aEvent );
virtual void OnInterceptSearchBoxKey( wxKeyEvent& aEvent );
virtual void OnTreeSelect( wxTreeEvent& aEvent );
virtual void OnDoubleClickTreeSelect( wxTreeEvent& aEvent );
virtual void OnTreeMouseUp( wxMouseEvent& aMouseEvent );
virtual void OnStartComponentBrowser( wxMouseEvent& aEvent );
private:
void updateSelection();
void SelectIfValid( const wxTreeItemId& aTreeId );
COMPONENT_TREE_SEARCH_CONTAINER* const m_search_container;
LIB_COMPONENT* m_selected_component;
bool m_external_browser_requested;
bool m_received_doubleclick_in_tree;
};

View File

@ -0,0 +1,109 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Nov 6 2013)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#include "dialog_choose_component_base.h"
///////////////////////////////////////////////////////////////////////////
DIALOG_CHOOSE_COMPONENT_BASE::DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) : DIALOG_SHIM( parent, id, title, pos, size, style )
{
this->SetSizeHints( wxSize( 450,-1 ), wxDefaultSize );
wxBoxSizer* bSizer1;
bSizer1 = new wxBoxSizer( wxVERTICAL );
wxBoxSizer* bSearchSizer;
bSearchSizer = new wxBoxSizer( wxHORIZONTAL );
m_searchLabel = new wxStaticText( this, wxID_ANY, wxT("Search"), wxDefaultPosition, wxDefaultSize, 0 );
m_searchLabel->Wrap( -1 );
bSearchSizer->Add( m_searchLabel, 0, wxALL, 5 );
m_searchBox = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
bSearchSizer->Add( m_searchBox, 1, wxALL, 5 );
bSizer1->Add( bSearchSizer, 0, wxEXPAND, 5 );
m_libraryComponentTree = new wxTreeCtrl( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT );
m_libraryComponentTree->SetMinSize( wxSize( -1,50 ) );
bSizer1->Add( m_libraryComponentTree, 2, wxALL|wxEXPAND, 5 );
wxBoxSizer* bSizer3;
bSizer3 = new wxBoxSizer( wxHORIZONTAL );
m_componentView = new wxStaticText( this, wxID_ANY, wxT("TODO\n(mini. comp image)"), wxDefaultPosition, wxSize( 100,100 ), 0 );
m_componentView->Wrap( -1 );
m_componentView->SetMinSize( wxSize( 100,100 ) );
bSizer3->Add( m_componentView, 0, wxALL, 5 );
wxBoxSizer* bSizer6;
bSizer6 = new wxBoxSizer( wxVERTICAL );
m_componentDetails = new wxTextCtrl( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize( -1,100 ), wxTE_MULTILINE );
bSizer6->Add( m_componentDetails, 1, wxALL|wxEXPAND, 5 );
m_unitChoice = new wxComboBox( this, wxID_ANY, wxT("Unit A"), wxDefaultPosition, wxDefaultSize, 0, NULL, 0 );
m_unitChoice->Enable( false );
m_unitChoice->Hide();
bSizer6->Add( m_unitChoice, 0, wxALL, 5 );
bSizer3->Add( bSizer6, 2, wxEXPAND, 5 );
bSizer1->Add( bSizer3, 1, wxEXPAND, 5 );
wxBoxSizer* bSizer5;
bSizer5 = new wxBoxSizer( wxHORIZONTAL );
bSizer5->Add( 0, 0, 1, wxEXPAND, 5 );
m_button = new wxStdDialogButtonSizer();
m_buttonOK = new wxButton( this, wxID_OK );
m_button->AddButton( m_buttonOK );
m_buttonCancel = new wxButton( this, wxID_CANCEL );
m_button->AddButton( m_buttonCancel );
m_button->Realize();
bSizer5->Add( m_button, 0, wxEXPAND, 5 );
bSizer1->Add( bSizer5, 0, wxEXPAND, 5 );
this->SetSizer( bSizer1 );
this->Layout();
this->Centre( wxBOTH );
// Connect Events
m_searchBox->Connect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnInterceptSearchBoxKey ), NULL, this );
m_searchBox->Connect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxChange ), NULL, this );
m_searchBox->Connect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxEnter ), NULL, this );
m_libraryComponentTree->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeMouseUp ), NULL, this );
m_libraryComponentTree->Connect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnDoubleClickTreeSelect ), NULL, this );
m_libraryComponentTree->Connect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeSelect ), NULL, this );
m_componentView->Connect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnStartComponentBrowser ), NULL, this );
}
DIALOG_CHOOSE_COMPONENT_BASE::~DIALOG_CHOOSE_COMPONENT_BASE()
{
// Disconnect Events
m_searchBox->Disconnect( wxEVT_KEY_DOWN, wxKeyEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnInterceptSearchBoxKey ), NULL, this );
m_searchBox->Disconnect( wxEVT_COMMAND_TEXT_UPDATED, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxChange ), NULL, this );
m_searchBox->Disconnect( wxEVT_COMMAND_TEXT_ENTER, wxCommandEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnSearchBoxEnter ), NULL, this );
m_libraryComponentTree->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeMouseUp ), NULL, this );
m_libraryComponentTree->Disconnect( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnDoubleClickTreeSelect ), NULL, this );
m_libraryComponentTree->Disconnect( wxEVT_COMMAND_TREE_SEL_CHANGED, wxTreeEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnTreeSelect ), NULL, this );
m_componentView->Disconnect( wxEVT_LEFT_UP, wxMouseEventHandler( DIALOG_CHOOSE_COMPONENT_BASE::OnStartComponentBrowser ), NULL, this );
}

View File

@ -0,0 +1,710 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<wxFormBuilder_Project>
<FileVersion major="1" minor="11" />
<object class="Project" expanded="1">
<property name="class_decoration"></property>
<property name="code_generation">C++</property>
<property name="disconnect_events">1</property>
<property name="disconnect_mode">source_name</property>
<property name="disconnect_php_events">0</property>
<property name="disconnect_python_events">0</property>
<property name="embedded_files_path">res</property>
<property name="encoding">UTF-8</property>
<property name="event_generation">connect</property>
<property name="file">dialog_choose_component_base</property>
<property name="first_id">1000</property>
<property name="help_provider">none</property>
<property name="internationalize">0</property>
<property name="name">dialog_choose_component_base</property>
<property name="namespace"></property>
<property name="path">.</property>
<property name="precompiled_header"></property>
<property name="relative_path">1</property>
<property name="skip_lua_events">1</property>
<property name="skip_php_events">1</property>
<property name="skip_python_events">1</property>
<property name="ui_table">UI</property>
<property name="use_enum">0</property>
<property name="use_microsoft_bom">0</property>
<object class="Dialog" expanded="1">
<property name="aui_managed">0</property>
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property>
<property name="bg"></property>
<property name="center">wxBOTH</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="enabled">1</property>
<property name="event_handler">impl_virtual</property>
<property name="extra_style"></property>
<property name="fg"></property>
<property name="font"></property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="maximum_size"></property>
<property name="minimum_size">450,-1</property>
<property name="name">DIALOG_CHOOSE_COMPONENT_BASE</property>
<property name="pos"></property>
<property name="size">450,500</property>
<property name="style">wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER</property>
<property name="subclass">DIALOG_SHIM; dialog_shim.h</property>
<property name="title"></property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnActivate"></event>
<event name="OnActivateApp"></event>
<event name="OnAuiFindManager"></event>
<event name="OnAuiPaneButton"></event>
<event name="OnAuiPaneClose"></event>
<event name="OnAuiPaneMaximize"></event>
<event name="OnAuiPaneRestore"></event>
<event name="OnAuiRender"></event>
<event name="OnChar"></event>
<event name="OnClose"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnHibernate"></event>
<event name="OnIconize"></event>
<event name="OnIdle"></event>
<event name="OnInitDialog"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer1</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="0">
<property name="minimum_size"></property>
<property name="name">bSearchSizer</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">Search</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_searchLabel</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size">-1,-1</property>
<property name="maxlength"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_searchBox</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxTE_PROCESS_ENTER</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown">OnInterceptSearchBoxKey</event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnText">OnSearchBoxChange</event>
<event name="OnTextEnter">OnSearchBoxEnter</event>
<event name="OnTextMaxLen"></event>
<event name="OnTextURL"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">2</property>
<object class="wxTreeCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,50</property>
<property name="moveable">1</property>
<property name="name">m_libraryComponentTree</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style">wxTR_DEFAULT_STYLE|wxTR_HIDE_ROOT</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp">OnTreeMouseUp</event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnTreeBeginDrag"></event>
<event name="OnTreeBeginLabelEdit"></event>
<event name="OnTreeBeginRDrag"></event>
<event name="OnTreeDeleteItem"></event>
<event name="OnTreeEndDrag"></event>
<event name="OnTreeEndLabelEdit"></event>
<event name="OnTreeGetInfo"></event>
<event name="OnTreeItemActivated">OnDoubleClickTreeSelect</event>
<event name="OnTreeItemCollapsed"></event>
<event name="OnTreeItemCollapsing"></event>
<event name="OnTreeItemExpanded"></event>
<event name="OnTreeItemExpanding"></event>
<event name="OnTreeItemGetTooltip"></event>
<event name="OnTreeItemMenu"></event>
<event name="OnTreeItemMiddleClick"></event>
<event name="OnTreeItemRightClick"></event>
<event name="OnTreeKeyDown"></event>
<event name="OnTreeSelChanged">OnTreeSelect</event>
<event name="OnTreeSelChanging"></event>
<event name="OnTreeSetInfo"></event>
<event name="OnTreeStateImageClick"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer3</property>
<property name="orient">wxHORIZONTAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxStaticText" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="label">TODO&#x0A;(mini. comp image)</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">100,100</property>
<property name="moveable">1</property>
<property name="name">m_componentView</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size">100,100</property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<property name="wrap">-1</property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp">OnStartComponentBrowser</event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">2</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer6</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL|wxEXPAND</property>
<property name="proportion">1</property>
<object class="wxTextCtrl" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">1</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">0</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="maxlength"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size">-1,100</property>
<property name="moveable">1</property>
<property name="name">m_componentDetails</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="show">1</property>
<property name="size">-1,-1</property>
<property name="style">wxTE_MULTILINE</property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value"></property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnText"></event>
<event name="OnTextEnter"></event>
<event name="OnTextMaxLen"></event>
<event name="OnTextURL"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxALL</property>
<property name="proportion">0</property>
<object class="wxComboBox" expanded="0">
<property name="BottomDockable">1</property>
<property name="LeftDockable">1</property>
<property name="RightDockable">1</property>
<property name="TopDockable">1</property>
<property name="aui_layer"></property>
<property name="aui_name"></property>
<property name="aui_position"></property>
<property name="aui_row"></property>
<property name="best_size"></property>
<property name="bg"></property>
<property name="caption"></property>
<property name="caption_visible">1</property>
<property name="center_pane">0</property>
<property name="choices"></property>
<property name="close_button">1</property>
<property name="context_help"></property>
<property name="context_menu">1</property>
<property name="default_pane">0</property>
<property name="dock">Dock</property>
<property name="dock_fixed">0</property>
<property name="docking">Left</property>
<property name="enabled">0</property>
<property name="fg"></property>
<property name="floatable">1</property>
<property name="font"></property>
<property name="gripper">0</property>
<property name="hidden">1</property>
<property name="id">wxID_ANY</property>
<property name="max_size"></property>
<property name="maximize_button">0</property>
<property name="maximum_size"></property>
<property name="min_size"></property>
<property name="minimize_button">0</property>
<property name="minimum_size"></property>
<property name="moveable">1</property>
<property name="name">m_unitChoice</property>
<property name="pane_border">1</property>
<property name="pane_position"></property>
<property name="pane_size"></property>
<property name="permission">protected</property>
<property name="pin_button">1</property>
<property name="pos"></property>
<property name="resize">Resizable</property>
<property name="selection">-1</property>
<property name="show">1</property>
<property name="size"></property>
<property name="style"></property>
<property name="subclass"></property>
<property name="toolbar_pane">0</property>
<property name="tooltip"></property>
<property name="validator_data_type"></property>
<property name="validator_style">wxFILTER_NONE</property>
<property name="validator_type">wxDefaultValidator</property>
<property name="validator_variable"></property>
<property name="value">Unit A</property>
<property name="window_extra_style"></property>
<property name="window_name"></property>
<property name="window_style"></property>
<event name="OnChar"></event>
<event name="OnCombobox"></event>
<event name="OnEnterWindow"></event>
<event name="OnEraseBackground"></event>
<event name="OnKeyDown"></event>
<event name="OnKeyUp"></event>
<event name="OnKillFocus"></event>
<event name="OnLeaveWindow"></event>
<event name="OnLeftDClick"></event>
<event name="OnLeftDown"></event>
<event name="OnLeftUp"></event>
<event name="OnMiddleDClick"></event>
<event name="OnMiddleDown"></event>
<event name="OnMiddleUp"></event>
<event name="OnMotion"></event>
<event name="OnMouseEvents"></event>
<event name="OnMouseWheel"></event>
<event name="OnPaint"></event>
<event name="OnRightDClick"></event>
<event name="OnRightDown"></event>
<event name="OnRightUp"></event>
<event name="OnSetFocus"></event>
<event name="OnSize"></event>
<event name="OnText"></event>
<event name="OnTextEnter"></event>
<event name="OnUpdateUI"></event>
</object>
</object>
</object>
</object>
</object>
</object>
<object class="sizeritem" expanded="1">
<property name="border">5</property>
<property name="flag">wxALIGN_RIGHT</property>
<property name="proportion">0</property>
<object class="wxBoxSizer" expanded="1">
<property name="minimum_size"></property>
<property name="name">bSizer5</property>
<property name="orient">wxVERTICAL</property>
<property name="permission">none</property>
<object class="sizeritem" expanded="0">
<property name="border">5</property>
<property name="flag">wxEXPAND</property>
<property name="proportion">0</property>
<object class="wxStdDialogButtonSizer" expanded="0">
<property name="Apply">0</property>
<property name="Cancel">1</property>
<property name="ContextHelp">0</property>
<property name="Help">0</property>
<property name="No">0</property>
<property name="OK">1</property>
<property name="Save">0</property>
<property name="Yes">0</property>
<property name="minimum_size"></property>
<property name="name">m_button</property>
<property name="permission">protected</property>
<event name="OnApplyButtonClick"></event>
<event name="OnCancelButtonClick"></event>
<event name="OnContextHelpButtonClick"></event>
<event name="OnHelpButtonClick"></event>
<event name="OnNoButtonClick"></event>
<event name="OnOKButtonClick"></event>
<event name="OnSaveButtonClick"></event>
<event name="OnYesButtonClick"></event>
</object>
</object>
</object>
</object>
</object>
</object>
</object>
</wxFormBuilder_Project>

View File

@ -0,0 +1,67 @@
///////////////////////////////////////////////////////////////////////////
// C++ code generated with wxFormBuilder (version Nov 6 2013)
// http://www.wxformbuilder.org/
//
// PLEASE DO "NOT" EDIT THIS FILE!
///////////////////////////////////////////////////////////////////////////
#ifndef __DIALOG_CHOOSE_COMPONENT_BASE_H__
#define __DIALOG_CHOOSE_COMPONENT_BASE_H__
#include <wx/artprov.h>
#include <wx/xrc/xmlres.h>
class DIALOG_SHIM;
#include "dialog_shim.h"
#include <wx/string.h>
#include <wx/stattext.h>
#include <wx/gdicmn.h>
#include <wx/font.h>
#include <wx/colour.h>
#include <wx/settings.h>
#include <wx/textctrl.h>
#include <wx/sizer.h>
#include <wx/treectrl.h>
#include <wx/combobox.h>
#include <wx/button.h>
#include <wx/dialog.h>
///////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
/// Class DIALOG_CHOOSE_COMPONENT_BASE
///////////////////////////////////////////////////////////////////////////////
class DIALOG_CHOOSE_COMPONENT_BASE : public DIALOG_SHIM
{
private:
protected:
wxStaticText* m_searchLabel;
wxTextCtrl* m_searchBox;
wxTreeCtrl* m_libraryComponentTree;
wxStaticText* m_componentView;
wxTextCtrl* m_componentDetails;
wxComboBox* m_unitChoice;
wxStdDialogButtonSizer* m_button;
wxButton* m_buttonOK;
wxButton* m_buttonCancel;
// Virtual event handlers, overide them in your derived class
virtual void OnInterceptSearchBoxKey( wxKeyEvent& event ) { event.Skip(); }
virtual void OnSearchBoxChange( wxCommandEvent& event ) { event.Skip(); }
virtual void OnSearchBoxEnter( wxCommandEvent& event ) { event.Skip(); }
virtual void OnTreeMouseUp( wxMouseEvent& event ) { event.Skip(); }
virtual void OnDoubleClickTreeSelect( wxTreeEvent& event ) { event.Skip(); }
virtual void OnTreeSelect( wxTreeEvent& event ) { event.Skip(); }
virtual void OnStartComponentBrowser( wxMouseEvent& event ) { event.Skip(); }
public:
DIALOG_CHOOSE_COMPONENT_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 450,500 ), long style = wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER );
~DIALOG_CHOOSE_COMPONENT_BASE();
};
#endif //__DIALOG_CHOOSE_COMPONENT_BASE_H__

View File

@ -45,11 +45,14 @@
#include <viewlib_frame.h>
#include <eeschema_id.h>
#include <dialog_choose_component.h>
#include <component_tree_search_container.h>
#include <dialog_get_component.h>
#include <boost/foreach.hpp>
// TODO(hzeller): would be good if we could give a pre-selected component.
wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( void )
{
wxSemaphore semaphore( 0, 1 );
@ -76,118 +79,66 @@ wxString SCH_BASE_FRAME::SelectComponentFromLibBrowser( void )
return cmpname;
}
wxString SCH_BASE_FRAME::SelectComponentFromLibrary( const wxString& aLibname,
wxArrayString& aHistoryList,
bool aUseLibBrowser,
int* aUnit,
int* aConvert )
{
int CmpCount = 0;
LIB_COMPONENT* libEntry = NULL;
CMP_LIBRARY* currLibrary = NULL;
wxString cmpName, keys, msg;
bool allowWildSeach = true;
int cmpCount = 0;
wxString dialogTitle;
COMPONENT_TREE_SEARCH_CONTAINER search_container; // Container doing search-as-you-type
if( !aLibname.IsEmpty() )
{
currLibrary = CMP_LIBRARY::FindLibrary( aLibname );
CMP_LIBRARY* currLibrary = CMP_LIBRARY::FindLibrary( aLibname );
if( currLibrary != NULL )
CmpCount = currLibrary->GetCount();
{
cmpCount = currLibrary->GetCount();
search_container.AddLibrary( *currLibrary );
}
}
else
{
BOOST_FOREACH( CMP_LIBRARY& lib, CMP_LIBRARY::GetLibraryList() )
{
CmpCount += lib.GetCount();
cmpCount += lib.GetCount();
search_container.AddLibrary( lib );
}
}
// Ask for a component name or key words
msg.Printf( _( "Component selection (%d items loaded):" ), CmpCount );
if( !aHistoryList.empty() )
{
// This is good for a transition for experineced users: giving them a History. Ideally,
// we actually make this part even faster to access with a popup on ALT-a or something.
search_container.AddComponentList( _("-- History --"), aHistoryList, NULL, true );
search_container.SetPreselectNode( aHistoryList[0] );
}
DIALOG_GET_COMPONENT dlg( this, aHistoryList, msg, aUseLibBrowser );
if( aHistoryList.GetCount() )
dlg.SetComponentName( aHistoryList[0] );
dialogTitle.Printf( _( "Choose Component (%d items loaded)" ), cmpCount );
DIALOG_CHOOSE_COMPONENT dlg( this, dialogTitle, &search_container );
if( dlg.ShowModal() == wxID_CANCEL )
return wxEmptyString;
if( dlg.m_GetExtraFunction )
wxString cmpName = dlg.GetSelectedComponentName();
if( dlg.IsExternalBrowserSelected() )
{
cmpName = SelectComponentFromLibBrowser();
cmpName = SelectComponentFromLibBrowser(); // Would be good if we could pre-select.
if( aUnit )
*aUnit = LIB_VIEW_FRAME::GetUnit();
if( aConvert )
*aConvert = LIB_VIEW_FRAME::GetConvert();
if( !cmpName.IsEmpty() )
}
if ( !cmpName.empty() )
AddHistoryComponentName( aHistoryList, cmpName );
return cmpName;
}
else
cmpName = dlg.GetComponentName();
if( cmpName.IsEmpty() )
return wxEmptyString;
// Here, cmpName contains the component name,
// or "*" if the Select All dialog button was pressed
#ifndef KICAD_KEEPCASE
cmpName.MakeUpper();
#endif
if( dlg.IsKeyword() )
{
allowWildSeach = false;
keys = cmpName;
cmpName = DataBaseGetName( this, keys, cmpName );
if( cmpName.IsEmpty() )
return wxEmptyString;
}
else if( cmpName == wxT( "*" ) )
{
allowWildSeach = false;
if( GetNameOfPartToLoad( this, currLibrary, cmpName ) == 0 )
return wxEmptyString;
}
else if( cmpName.Contains( wxT( "?" ) ) || cmpName.Contains( wxT( "*" ) ) )
{
allowWildSeach = false;
cmpName = DataBaseGetName( this, keys, cmpName );
if( cmpName.IsEmpty() )
return wxEmptyString;
}
libEntry = CMP_LIBRARY::FindLibraryComponent( cmpName, aLibname );
if( !libEntry && allowWildSeach ) // Search with wildcard
{
allowWildSeach = false;
wxString wildname = wxChar( '*' ) + cmpName + wxChar( '*' );
cmpName = wildname;
cmpName = DataBaseGetName( this, keys, cmpName );
if( !cmpName.IsEmpty() )
libEntry = CMP_LIBRARY::FindLibraryComponent( cmpName, aLibname );
if( !libEntry )
return wxEmptyString;
}
if( !libEntry )
{
msg.Printf( _( "Failed to find part <%s> in library" ), GetChars( cmpName ) );
DisplayError( this, msg );
return wxEmptyString;
}
AddHistoryComponentName( aHistoryList, cmpName );
return cmpName;
}