2012-08-21 17:00:40 +00:00
using System ;
using System.Collections.Generic ;
using System.Drawing ;
2012-09-08 08:40:36 +00:00
using System.IO ;
2012-08-21 17:00:40 +00:00
using System.Windows.Forms ;
using System.Xml ;
2012-09-08 08:40:36 +00:00
using System.Linq ;
2015-02-21 14:53:11 +00:00
using System.Threading.Tasks ;
using System.Threading ;
using AnxSampleBrowser.Resources ;
2012-08-21 17:00:40 +00:00
namespace AnxSampleBrowser
{
2012-09-08 08:40:36 +00:00
/// <summary>
/// WinForm project which let you browse through the ANX samples
/// </summary>
2012-08-21 17:00:40 +00:00
public partial class AnxSampleBrowser : Form
{
//list of all registered samples
private List < SampleData > _sampleAtlas ;
2015-02-21 14:53:11 +00:00
private SortedList < SampleData > _filteredSamples ;
private Dictionary < SampleData , SampleDataHalfVisual > _sampleDataControlMap ;
private CancellationTokenSource _searchCancellationTokenSource ;
private object _filteredSamplesLock = new object ( ) ;
private volatile bool _alreadyRunInvoke = false ;
2012-09-08 08:40:36 +00:00
2015-02-21 14:53:11 +00:00
private int _previousPage = - 1 ;
2012-09-08 08:40:36 +00:00
private int _currentPage = 1 ;
private int _pageCount ;
//default path to the samples folder
2015-02-21 14:53:11 +00:00
public String SamplePath
{
get ;
private set ;
}
DropDownElement _sortByName = new DropDownElement ( "name" , StringResources . Name ) ;
DropDownElement _sortByCategory = new DropDownElement ( "category" , StringResources . Category ) ;
DropDownElement _dontFilterAll = new DropDownElement ( "all" , StringResources . All ) ;
DropDownElement _selectedCategory = null ;
2012-08-21 17:00:40 +00:00
/// <summary>
/// Constructor of the browser
/// parses the xml and set up lists
/// </summary>
public AnxSampleBrowser ( )
{
2015-02-21 14:53:11 +00:00
SamplePath = "../../Samples/" ;
2012-08-21 17:00:40 +00:00
InitializeComponent ( ) ;
//make the form fixed size
this . FormBorderStyle = FormBorderStyle . FixedDialog ;
// Set the MaximizeBox to false to remove the maximize box.
this . MaximizeBox = false ;
// Set the MinimizeBox to false to remove the minimize box.
this . MinimizeBox = false ;
2015-02-21 14:53:11 +00:00
_dSort . Items . Add ( _sortByName ) ;
_dSort . Items . Add ( _sortByCategory ) ;
_dSort . SelectedIndex = 0 ;
_dSort . DropDownStyle = ComboBoxStyle . DropDownList ;
2012-08-21 17:00:40 +00:00
//add default categorie (everything)...
2015-02-21 14:53:11 +00:00
_dCategories . Items . Add ( _dontFilterAll ) ;
2012-08-21 17:00:40 +00:00
//...and select it
_dCategories . SelectedIndex = 0 ;
_dCategories . DropDownStyle = ComboBoxStyle . DropDownList ;
2015-02-21 14:53:11 +00:00
//init sample list
_sampleAtlas = new List < SampleData > ( ) ;
_filteredSamples = new SortedList < SampleData > ( SamplesComparer ) ;
_sampleDataControlMap = new Dictionary < SampleData , SampleDataHalfVisual > ( ) ;
Application . Idle + = Application_Idle ;
2012-08-21 17:00:40 +00:00
//load out Samples.xml
parseXMl ( ) ;
2012-09-08 08:40:36 +00:00
addAll ( ) ;
2015-02-21 14:53:11 +00:00
buildPages ( ) ;
Size originalSize = _pSamples . Size ;
int right = 0 ;
int bottom = 0 ;
foreach ( Control c in _pSamples . Controls )
{
right = Math . Max ( right , c . Location . X + c . Size . Width ) ;
bottom = Math . Max ( bottom , c . Location . Y + c . Size . Height ) ;
}
//_pSamples gets resized by changing the size of the window.
this . ClientSize = new System . Drawing . Size ( ClientSize . Width + right - originalSize . Width , ClientSize . Height + bottom - originalSize . Height ) ;
2012-08-21 17:00:40 +00:00
_cFilter . CheckOnClick = true ;
2012-09-08 08:40:36 +00:00
2015-02-21 14:53:11 +00:00
2012-08-21 17:00:40 +00:00
for ( int i = 0 ; i < _cFilter . Items . Count ; + + i )
{
_cFilter . SetItemChecked ( i , true ) ;
}
2015-02-21 14:53:11 +00:00
this . _cFilter . ItemCheck + = _cFilter_ItemCheck ;
}
2012-08-21 17:00:40 +00:00
2015-02-21 14:53:11 +00:00
void _cFilter_ItemCheck ( object sender , ItemCheckEventArgs e )
{
search ( ) ;
}
2012-08-21 17:00:40 +00:00
2015-02-21 14:53:11 +00:00
void Application_Idle ( object sender , EventArgs e )
{
_alreadyRunInvoke = false ;
}
2012-08-21 17:00:40 +00:00
2015-02-21 14:53:11 +00:00
private IComparer < SampleData > SamplesComparer
{
get
{
if ( _dSort . SelectedItem = = _sortByCategory )
{
return SampleDataCategoryComparer . Instance ;
}
else if ( _dSort . SelectedItem = = _sortByName )
{
return SampleDataNameComparer . Instance ;
}
else
throw new InvalidOperationException ( "No sort mode specified." ) ;
}
2012-08-21 17:00:40 +00:00
}
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base . CreateParams ;
2015-02-21 14:53:11 +00:00
//Activating DoubleBuffered for form and child controls where possible.
cp . ExStyle | = 0x02000000 ; // WS_EX_COMPOSITED
return cp ;
2012-08-21 17:00:40 +00:00
}
}
2015-02-21 14:53:11 +00:00
private void buildPages ( )
2012-09-08 08:40:36 +00:00
{
2015-02-21 14:53:11 +00:00
Action body = ( ) = >
{
//Makes this async code on the main thread more performant by running it only once per update.
//It can happen that we trigger the buildPage several times before the app gets idle again, in which
//it would usually work through the calls we gave by calling invoke. When that happens, it would run this
//code multiple successive times, but in between these calls it doesn't have the chance to manipulate the
//data upon which we build these controls. Which means, it would be a wasted effort.
//But this check is also from the time were the controls weren't cached and the performance difference isn't
//as big anymore as it once was.
if ( _alreadyRunInvoke )
return ;
bool needsRebuild = false ;
var controls = _pSamples . Controls . Cast < SampleDataHalfVisual > ( ) . ToArray ( ) ;
if ( _filteredSamples . Count ! = 0 )
{
var sourceData = _filteredSamples . GetRange ( ( _currentPage - 1 ) * 6 , Math . Min ( 6 , _filteredSamples . Count - ( _currentPage - 1 ) * 6 ) ) ;
if ( controls . Length = = sourceData . Count )
{
for ( int i = 0 ; i < controls . Length ; i + + )
{
var data = controls [ i ] . SampleData ;
if ( data ! = sourceData [ i ] )
{
needsRebuild = true ;
break ;
}
}
}
else
needsRebuild = true ;
}
else
needsRebuild = true ;
if ( _previousPage ! = _currentPage )
needsRebuild = true ;
_previousPage = _currentPage ;
if ( needsRebuild )
{
_pSamples . Controls . Clear ( ) ;
2012-09-08 08:40:36 +00:00
2015-02-21 14:53:11 +00:00
_pageCount = ( int ) Math . Ceiling ( _filteredSamples . Count / 6f ) ;
_currentPage = Math . Min ( _currentPage , _pageCount ) ;
if ( _currentPage < 1 & & _pageCount > = 1 )
_currentPage = 1 ;
_lCurrentPage . Text = _currentPage . ToString ( ) ;
_lMaxPage . Text = _pageCount . ToString ( ) ;
if ( _filteredSamples . Count > 0 )
{
for ( int i = 6 * ( _currentPage - 1 ) ; i < _currentPage * 6 & & i < _filteredSamples . Count ; + + i )
{
addSampleDataVisual ( _filteredSamples [ i ] ) ;
}
}
}
_alreadyRunInvoke = true ;
} ;
if ( this . InvokeRequired )
this . Invoke ( body ) ;
else
{
//Just making sure, that if we are running this code not on the idle event, it actually runs.
_alreadyRunInvoke = false ;
body ( ) ;
_alreadyRunInvoke = false ;
2012-09-08 08:40:36 +00:00
}
}
2012-08-21 17:00:40 +00:00
private void parseXMl ( )
{
XmlDocument sampleDescription = new XmlDocument ( ) ;
try
{
2015-02-21 14:53:11 +00:00
sampleDescription . Load ( SamplePath + "SampleCatalog.xml" ) ;
2012-08-21 17:00:40 +00:00
}
2012-11-04 08:46:52 +00:00
catch ( FileNotFoundException )
2012-08-21 17:00:40 +00:00
{
OpenFileDialog openSampleXML = new OpenFileDialog ( ) ;
openSampleXML . Filter = "xml files (*.xml)|*.xml" ;
2015-02-21 14:53:11 +00:00
openSampleXML . Title = "Pick SampleCatalog.xml" ;
2012-08-21 17:00:40 +00:00
if ( openSampleXML . ShowDialog ( ) = = DialogResult . OK )
{
2015-02-21 14:53:11 +00:00
SamplePath = Path . GetDirectoryName ( openSampleXML . FileName ) ;
2012-08-21 17:00:40 +00:00
sampleDescription . Load ( openSampleXML . FileName ) ;
}
else
{
MessageBox . Show ( "Samples.xml not found" ) ;
this . Close ( ) ;
2015-02-21 14:53:11 +00:00
return ;
2012-08-21 17:00:40 +00:00
}
}
XmlNode sampleRoot = sampleDescription . ChildNodes [ 1 ] ;
List < String > _categorieAtlas = new List < string > ( ) ;
2015-02-21 14:53:11 +00:00
List < String > _tagAtlas = new List < string > ( ) ;
2012-08-21 17:00:40 +00:00
foreach ( XmlNode sample in sampleRoot . ChildNodes )
{
2015-02-21 14:53:11 +00:00
SampleData data = new SampleData ( )
{
2012-08-21 17:00:40 +00:00
Name = sample [ "Name" ] . InnerText ,
Description = sample [ "Description" ] . InnerText ,
ExecPath = sample [ "ExecPath" ] . InnerText ,
2015-02-21 14:53:11 +00:00
ProjectPath = sample [ "ProjectPath" ] . InnerText ,
Category = sample [ "Category" ] . InnerText ,
2012-08-21 17:00:40 +00:00
} ;
XmlNode imagePath = sample [ "ImagePath" ] ;
if ( imagePath ! = null )
data . ImagePath = imagePath . InnerText ;
else
data . ImagePath = "" ;
data . Validate ( ) ;
2015-02-21 14:53:11 +00:00
if ( ! _categorieAtlas . Contains ( sample [ "Category" ] . InnerText ) )
_categorieAtlas . Add ( sample [ "Category" ] . InnerText ) ;
2012-08-21 17:00:40 +00:00
XmlNode tags = sample [ "Tags" ] ;
2015-02-21 14:53:11 +00:00
List < String > dataTags = new List < string > ( ) ;
2012-08-21 17:00:40 +00:00
foreach ( XmlNode tag in tags . ChildNodes )
{
if ( ! _tagAtlas . Contains ( tag . InnerText ) )
_tagAtlas . Add ( tag . InnerText ) ;
dataTags . Add ( tag . InnerText ) ;
}
data . Tags = dataTags . ToArray ( ) ;
_sampleAtlas . Add ( data ) ;
addSampleDataVisual ( data ) ;
}
2015-02-21 14:53:11 +00:00
_dCategories . Items . AddRange ( _categorieAtlas . Select ( ( categoryName ) = > new DropDownElement ( categoryName , categoryName ) ) . ToArray ( ) ) ;
2012-08-21 17:00:40 +00:00
2015-02-21 14:53:11 +00:00
_cFilter . Items . AddRange ( _tagAtlas . ToArray ( ) ) ;
2012-08-21 17:00:40 +00:00
}
private void addAll ( )
{
2015-02-21 14:53:11 +00:00
lock ( _filteredSamplesLock )
{
_filteredSamples . Clear ( ) ;
_filteredSamples . AddRange ( _sampleAtlas ) ;
buildPages ( ) ;
}
2012-09-08 08:40:36 +00:00
}
private void addAll ( List < SampleData > value )
{
2015-02-21 14:53:11 +00:00
lock ( _filteredSamplesLock )
{
_filteredSamples . Clear ( ) ;
_filteredSamples . AddRange ( value ) ;
buildPages ( ) ;
}
2012-09-08 08:40:36 +00:00
}
2015-02-21 14:53:11 +00:00
private bool isAllowed ( SampleData data )
2012-09-08 08:40:36 +00:00
{
2015-02-21 14:53:11 +00:00
if ( _selectedCategory ! = _dontFilterAll )
{
if ( data . Category ! = _selectedCategory . Name )
return false ;
}
if ( data . Tags . Length = = 0 )
return true ;
2012-09-08 08:40:36 +00:00
foreach ( String tag in data . Tags )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
if ( _cFilter . CheckedItems . Contains ( tag ) )
2012-09-08 08:40:36 +00:00
return true ;
2012-08-21 17:00:40 +00:00
}
2012-09-08 08:40:36 +00:00
return false ;
2012-08-21 17:00:40 +00:00
}
private void addSampleDataVisual ( SampleData data )
{
2015-02-21 14:53:11 +00:00
SampleDataHalfVisual dataV ;
if ( ! _sampleDataControlMap . TryGetValue ( data , out dataV ) )
{
dataV = new SampleDataHalfVisual ( data , this ) ;
_sampleDataControlMap . Add ( data , dataV ) ;
}
2012-09-08 08:40:36 +00:00
if ( this . _pSamples . Controls . Count % 2 = = 0 )
2015-02-21 14:53:11 +00:00
dataV . Location = new Point ( 0 , ( this . _pSamples . Controls . Count / 2 ) * ( dataV . Size . Height + 5 ) ) ;
2012-09-08 08:40:36 +00:00
else
2015-02-21 14:53:11 +00:00
dataV . Location = new Point ( dataV . Width + 5 , ( ( this . _pSamples . Controls . Count - 1 ) / 2 ) * ( dataV . Size . Height + 5 ) ) ;
2012-08-21 17:00:40 +00:00
this . _pSamples . Controls . Add ( dataV ) ;
}
2015-02-21 14:53:11 +00:00
private Task search ( )
{
if ( _searchCancellationTokenSource ! = null )
{
_searchCancellationTokenSource . Cancel ( ) ;
}
_searchCancellationTokenSource = new CancellationTokenSource ( ) ;
return Task . Factory . StartNew ( ( ) = > search ( _searchCancellationTokenSource . Token ) , _searchCancellationTokenSource . Token ) ;
}
private void search ( CancellationToken cancellationToken )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
if ( ! this . IsHandleCreated )
return ;
lock ( _filteredSamplesLock )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
if ( cancellationToken . IsCancellationRequested )
return ;
_filteredSamples . Clear ( ) ;
//Search by any of the specified words and remove empty entries to make sure that we don't just return everything if we end with one of the split characters.
String [ ] phrases = _tSearch . Text . Split ( new char [ ] { ' ' , ',' , ';' } , StringSplitOptions . RemoveEmptyEntries ) ;
//If we have nothing or just the split characters, we return everything.
if ( phrases . Length = = 0 )
phrases = new string [ ] { "" } ;
foreach ( SampleData data in _sampleAtlas )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
if ( cancellationToken . IsCancellationRequested )
return ;
if ( ! isAllowed ( data ) )
continue ;
bool add = false ;
foreach ( string phrase in phrases )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
if ( data . Name . Contains ( phrase , StringComparison . OrdinalIgnoreCase ) | |
data . Description . Contains ( phrase , StringComparison . OrdinalIgnoreCase ) | |
data . Category . Contains ( phrase , StringComparison . OrdinalIgnoreCase ) )
2012-08-21 17:00:40 +00:00
{
add = true ;
break ;
}
2015-02-21 14:53:11 +00:00
foreach ( String tag in data . Tags )
{
if ( tag . ToLower ( ) . Equals ( phrase . ToLower ( ) ) )
{
add = true ;
break ;
}
}
}
if ( add )
_filteredSamples . Add ( data ) ;
2012-08-21 17:00:40 +00:00
}
2015-02-21 14:53:11 +00:00
buildPages ( ) ;
2012-08-21 17:00:40 +00:00
}
}
2015-02-21 14:53:11 +00:00
2012-08-21 17:00:40 +00:00
private void _bSearch_Click ( object sender , EventArgs e )
{
search ( ) ;
}
2015-02-21 14:53:11 +00:00
private void _tSearch_KeyDown ( object sender , KeyEventArgs e )
{
if ( e . KeyCode = = Keys . Enter )
{
e . SuppressKeyPress = true ;
e . Handled = true ;
search ( ) ;
}
}
private void _tSearch_TextChanged ( object sender , EventArgs e )
{
search ( ) ;
}
2012-08-21 17:00:40 +00:00
private void _bClear_Click ( object sender , EventArgs e )
{
this . _tSearch . Text = "" ;
addAll ( ) ;
}
2012-09-08 08:40:36 +00:00
private void AnxSampleBrowser_Load ( object sender , EventArgs e )
{
this . Text + = " v" + System . Reflection . Assembly . GetExecutingAssembly ( ) . GetName ( ) . Version . ToString ( ) ;
}
private void _cSort_SelectedIndexChanged ( object sender , EventArgs e )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
//Make sure our List has been initialized.
if ( _filteredSamples = = null )
2012-09-08 08:40:36 +00:00
return ;
2015-02-21 14:53:11 +00:00
lock ( _filteredSamplesLock )
2012-09-08 08:40:36 +00:00
{
2015-02-21 14:53:11 +00:00
_filteredSamples . Comparer = SamplesComparer ;
buildPages ( ) ;
2012-09-08 08:40:36 +00:00
}
2012-08-21 17:00:40 +00:00
}
2012-09-08 08:40:36 +00:00
private void pictureBox2_Click ( object sender , EventArgs e )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
_currentPage = _currentPage + 1 > _pageCount ? _currentPage : _currentPage + 1 ;
buildPages ( ) ;
2012-08-21 17:00:40 +00:00
}
2012-09-08 08:40:36 +00:00
private void pictureBox1_Click ( object sender , EventArgs e )
2012-08-22 11:29:03 +00:00
{
2012-09-08 08:40:36 +00:00
_currentPage = _currentPage - 1 < = 0 ? _currentPage : _currentPage - 1 ;
2015-02-21 14:53:11 +00:00
buildPages ( ) ;
2012-08-22 11:29:03 +00:00
}
2012-09-08 10:32:05 +00:00
2015-02-21 14:53:11 +00:00
private void _dCategories_SelectedIndexChanged ( object sender , EventArgs e )
2012-08-21 17:00:40 +00:00
{
2015-02-21 14:53:11 +00:00
_selectedCategory = ( DropDownElement ) _dCategories . SelectedItem ;
search ( ) ;
2012-08-21 17:00:40 +00:00
}
}
}