Commit 87c97ae1 authored by Benjamin Pracht's avatar Benjamin Pracht

* Implements selection of a playlist item in the wizard

* The playlist in the wizard had to be displayed as a outlineview if we want to reuse existing code
* cosmetics could still be improved regarding this outline view
* I get this error

2005-07-24 00:08:55.940 VLC[6908] Could not connect the action t3_addressEntered: to target of class VLCWizard

When opening the wizard. I don't know if I messed up something or if it was already here before

* I needed to make some changes to the interface structure regarding the playlist for this : We know have a VLCPlaylist and a VLCPlaylistWizard class. Both are derivated from a VLCPlaylistCommon class that contains methods required by both classes (mostly the datasource, in fact).
parent 46fb23ef
{
IBClasses = (
{CLASS = FirstResponder; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{CLASS = VLCPlaylistCommon; LANGUAGE = ObjC; SUPERCLASS = NSObject; },
{
CLASS = VLCPlaylistWizard;
LANGUAGE = ObjC;
OUTLETS = {
"o_outline_view" = id;
"o_tc_author" = id;
"o_tc_duration" = id;
"o_tc_name" = id;
};
SUPERCLASS = VLCPlaylistCommon;
},
{
ACTIONS = {
cancelRun = id;
......@@ -29,6 +41,7 @@
"o_btn_backward" = id;
"o_btn_cancel" = id;
"o_btn_forward" = id;
"o_playlist_wizard" = id;
"o_t1_btn_mrInfo_strmg" = id;
"o_t1_btn_mrInfo_trnscd" = id;
"o_t1_matrix_strmgOrTrnscd" = id;
......
......@@ -3,9 +3,9 @@
<plist version="1.0">
<dict>
<key>IBDocumentLocation</key>
<string>397 577 356 241 0 0 1440 878 </string>
<string>255 498 356 241 0 0 1024 746 </string>
<key>IBFramework Version</key>
<string>437.0</string>
<string>364.0</string>
<key>IBLockedObjects</key>
<array>
<integer>6</integer>
......@@ -13,12 +13,7 @@
<integer>10</integer>
<integer>270</integer>
</array>
<key>IBOpenObjects</key>
<array>
<integer>6</integer>
<integer>268</integer>
</array>
<key>IBSystem Version</key>
<string>8C46</string>
<string>7W98</string>
</dict>
</plist>
......@@ -23,7 +23,7 @@
*****************************************************************************/
/*****************************************************************************
* VLCPlaylistView interface
* VLCPlaylistView interface
*****************************************************************************/
@interface VLCPlaylistView : NSOutlineView
{
......@@ -32,18 +32,44 @@
@end
/*****************************************************************************
* VLCPlaylist interface
* VLCPlaylistCommon interface
*****************************************************************************/
@interface VLCPlaylist : NSObject
@interface VLCPlaylistCommon : NSObject
{
IBOutlet id o_tc_name;
IBOutlet id o_tc_author;
IBOutlet id o_tc_duration;
IBOutlet id o_outline_view;
int i_current_view;
}
- (void)initStrings;
- (playlist_item_t *)selectedPlaylistItem;
- (NSOutlineView *)outlineView;
@end
/*****************************************************************************
* VLCPlaylistWizard interface
*****************************************************************************/
@interface VLCPlaylistWizard : VLCPlaylistCommon
{
}
- (IBAction)reloadOutlineView;
@end
/*****************************************************************************
* VLCPlaylist interface
*****************************************************************************/
@interface VLCPlaylist : VLCPlaylistCommon
{
IBOutlet id o_controller;
IBOutlet id o_btn_playlist;
IBOutlet id o_playlist_view;
IBOutlet id o_outline_view;
IBOutlet id o_tc_name;
IBOutlet id o_tc_author;
IBOutlet id o_tc_duration;
IBOutlet id o_status_field;
IBOutlet id o_search_field;
IBOutlet id o_random_ckb;
......@@ -70,20 +96,17 @@
NSImage *o_descendingSortingImage;
NSImage *o_ascendingSortingImage;
NSMutableDictionary *o_outline_dict;
NSMutableArray *o_nodes_array;
NSMutableArray *o_items_array;
NSMutableDictionary *o_outline_dict;
BOOL b_selected_item_met;
BOOL b_isSortDescending;
int i_current_view;
id o_tc_sortColumn;
}
- (void)initStrings;
- (void)searchfieldChanged:(NSNotification *)o_notification;
- (NSMenu *)menuForEvent:(NSEvent *)o_event;
- (NSOutlineView *)outlineView;
- (IBAction)handlePopUp:(id)sender;
- (IBAction)searchItem:(id)sender;
......@@ -105,7 +128,6 @@
- (void)appendArray:(NSArray*)o_array atPos:(int)i_position enqueue:(BOOL)b_enqueue;
- (void)appendNodeArray:(NSArray*)o_array inNode:(playlist_item_t *)p_node atPos:(int)i_position inView:(int)i_view enqueue:(BOOL)b_enqueue;
- (playlist_item_t *)selectedPlaylistItem;
@end
......@@ -92,8 +92,256 @@
@end
/*****************************************************************************
* VLCPlaylist implementation
* VLCPlaylistCommon implementation
*
* This class the superclass of the VLCPlaylist and VLCPlaylistWizard.
* It contains the common methods and elements of these 2 entities.
*****************************************************************************/
@implementation VLCPlaylistCommon
- (void)awakeFromNib
{
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
i_current_view = VIEW_CATEGORY;
playlist_ViewUpdate( p_playlist, i_current_view );
[o_outline_view setTarget: self];
[o_outline_view setDelegate: self];
[o_outline_view setDataSource: self];
vlc_object_release( p_playlist );
[self initStrings];
}
- (void)initStrings
{
[[o_tc_name headerCell] setStringValue:_NS("Name")];
[[o_tc_author headerCell] setStringValue:_NS("Author")];
[[o_tc_duration headerCell] setStringValue:_NS("Duration")];
}
- (NSOutlineView *)outlineView
{
return o_outline_view;
}
- (playlist_item_t *)selectedPlaylistItem
{
return [[o_outline_view itemAtRow: [o_outline_view selectedRow]]
pointerValue];
}
@end
@implementation VLCPlaylistCommon (NSOutlineViewDataSource)
/* return the number of children for Obj-C pointer item */ /* DONE */
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
int i_return = 0;
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL || outlineView != o_outline_view )
return 0;
if( item == nil )
{
/* root object */
playlist_view_t *p_view;
p_view = playlist_ViewFind( p_playlist, i_current_view );
if( p_view && p_view->p_root )
{
i_return = p_view->p_root->i_children;
if( i_current_view == VIEW_CATEGORY )
{
i_return--; /* remove the GENERAL item from the list */
i_return += p_playlist->p_general->i_children; /* add the items of the general node */
}
}
}
else
{
playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
if( p_item )
i_return = p_item->i_children;
}
vlc_object_release( p_playlist );
if( i_return <= 0 )
i_return = 0;
return i_return;
}
/* return the child at index for the Obj-C pointer item */ /* DONE */
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
{
playlist_item_t *p_return = NULL;
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
NSValue *o_value;
if( p_playlist == NULL )
return nil;
if( item == nil )
{
/* root object */
playlist_view_t *p_view;
p_view = playlist_ViewFind( p_playlist, i_current_view );
if( p_view && p_view->p_root ) p_return = p_view->p_root->pp_children[index];
if( i_current_view == VIEW_CATEGORY )
{
if( p_playlist->p_general->i_children && index >= 0 && index < p_playlist->p_general->i_children )
{
p_return = p_playlist->p_general->pp_children[index];
}
else if( p_view && p_view->p_root && index >= 0 && index - p_playlist->p_general->i_children < p_view->p_root->i_children )
{
p_return = p_view->p_root->pp_children[index - p_playlist->p_general->i_children + 1];
}
}
}
else
{
playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
if( p_item && index < p_item->i_children && index >= 0 )
p_return = p_item->pp_children[index];
}
vlc_object_release( p_playlist );
o_value = [[NSValue valueWithPointer: p_return] retain];
return o_value;
}
/* is the item expandable */
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
int i_return = 0;
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
return NO;
if( item == nil )
{
/* root object */
playlist_view_t *p_view;
p_view = playlist_ViewFind( p_playlist, i_current_view );
if( p_view && p_view->p_root ) i_return = p_view->p_root->i_children;
if( i_current_view == VIEW_CATEGORY )
{
i_return--;
i_return += p_playlist->p_general->i_children;
}
}
else
{
playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
if( p_item )
i_return = p_item->i_children;
}
vlc_object_release( p_playlist );
if( i_return <= 0 )
return NO;
else
return YES;
}
/* retrieve the string values for the cells */
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)o_tc byItem:(id)item
{
id o_value = nil;
intf_thread_t *p_intf = VLCIntf;
playlist_t *p_playlist;
playlist_item_t *p_item;
if( item == nil || ![item isKindOfClass: [NSValue class]] ) return( @"error" );
p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
{
return( @"error" );
}
p_item = (playlist_item_t *)[item pointerValue];
if( p_item == NULL )
{
vlc_object_release( p_playlist );
return( @"error");
}
if( [[o_tc identifier] isEqualToString:@"1"] )
{
o_value = [NSString stringWithUTF8String:
p_item->input.psz_name];
if( o_value == NULL )
o_value = [NSString stringWithCString:
p_item->input.psz_name];
}
else if( [[o_tc identifier] isEqualToString:@"2"] )
{
char *psz_temp;
psz_temp = vlc_input_item_GetInfo( &p_item->input ,_("Meta-information"),_("Artist") );
if( psz_temp == NULL )
o_value = @"";
else
{
o_value = [NSString stringWithUTF8String: psz_temp];
if( o_value == NULL )
{
o_value = [NSString stringWithCString: psz_temp];
}
free( psz_temp );
}
}
else if( [[o_tc identifier] isEqualToString:@"3"] )
{
char psz_duration[MSTRTIME_MAX_SIZE];
mtime_t dur = p_item->input.i_duration;
if( dur != -1 )
{
secstotimestr( psz_duration, dur/1000000 );
o_value = [NSString stringWithUTF8String: psz_duration];
}
else
{
o_value = @"-:--:--";
}
}
vlc_object_release( p_playlist );
return( o_value );
}
@end
/*****************************************************************************
* VLCPlaylistWizard implementation
*****************************************************************************/
@implementation VLCPlaylistWizard
- (IBAction)reloadOutlineView
{
[o_outline_view reloadData];
}
@end
/*****************************************************************************
* VLCPlaylist implementation
*****************************************************************************/
@implementation VLCPlaylist
......@@ -120,12 +368,8 @@
FIND_ANYWHERE );
int i_index;
i_current_view = VIEW_CATEGORY;
playlist_ViewUpdate( p_playlist, i_current_view );
[o_outline_view setTarget: self];
[o_outline_view setDelegate: self];
[o_outline_view setDataSource: self];
[super awakeFromNib];
[o_outline_view setDoubleAction: @selector(playItem:)];
......@@ -218,7 +462,6 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
[o_search_field setHidden:YES];
}
#endif
[self initStrings];
//[self playlistUpdated];
}
......@@ -229,6 +472,8 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
- (void)initStrings
{
[super initStrings];
[o_mi_save_playlist setTitle: _NS("Save Playlist...")];
[o_mi_play setTitle: _NS("Play")];
[o_mi_delete setTitle: _NS("Delete")];
......@@ -238,9 +483,6 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
[o_mi_sort_name setTitle: _NS("Sort Node by Name")];
[o_mi_sort_author setTitle: _NS("Sort Node by Author")];
[o_mi_services setTitle: _NS("Services discovery")];
[[o_tc_name headerCell] setStringValue:_NS("Name")];
[[o_tc_author headerCell] setStringValue:_NS("Author")];
[[o_tc_duration headerCell] setStringValue:_NS("Duration")];
[o_status_field setStringValue: [NSString stringWithFormat:
_NS("no items in playlist")]];
......@@ -254,11 +496,6 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
[[o_loop_popup itemAtIndex:2] setTitle: _NS("Repeat All")];
}
- (NSOutlineView *)outlineView
{
return o_outline_view;
}
- (void)playlistUpdated
{
unsigned int i;
......@@ -465,7 +702,7 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
}
/* This method is usefull for instance to remove the selected children of an
already selected node, for instance */
already selected node */
- (void)removeItemsFrom:(id)o_items ifChildrenOf:(id)o_nodes
{
unsigned int i, j;
......@@ -1086,12 +1323,6 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
return( o_ctx_menu );
}
- (playlist_item_t *)selectedPlaylistItem
{
return [[o_outline_view itemAtRow: [o_outline_view selectedRow]]
pointerValue];
}
- (void)outlineView: (NSTableView*)o_tv
didClickTableColumn:(NSTableColumn *)o_tc
{
......@@ -1198,82 +1429,14 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
@implementation VLCPlaylist (NSOutlineViewDataSource)
/* return the number of children for Obj-C pointer item */ /* DONE */
- (int)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item
{
int i_return = 0;
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL || outlineView != o_outline_view )
return 0;
if( item == nil )
{
/* root object */
playlist_view_t *p_view;
p_view = playlist_ViewFind( p_playlist, i_current_view );
if( p_view && p_view->p_root )
{
i_return = p_view->p_root->i_children;
if( i_current_view == VIEW_CATEGORY )
{
i_return--; /* remove the GENERAL item from the list */
i_return += p_playlist->p_general->i_children; /* add the items of the general node */
}
}
}
else
{
playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
if( p_item )
i_return = p_item->i_children;
}
vlc_object_release( p_playlist );
if( i_return <= 0 )
i_return = 0;
return i_return;
}
/* return the child at index for the Obj-C pointer item */ /* DONE */
- (id)outlineView:(NSOutlineView *)outlineView child:(int)index ofItem:(id)item
{
playlist_item_t *p_return = NULL;
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
NSValue *o_value;
id o_value = [super outlineView: outlineView child: index ofItem: item];
playlist_t *p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
return nil;
if( !p_playlist ) return nil;
if( item == nil )
{
/* root object */
playlist_view_t *p_view;
p_view = playlist_ViewFind( p_playlist, i_current_view );
if( p_view && p_view->p_root ) p_return = p_view->p_root->pp_children[index];
if( i_current_view == VIEW_CATEGORY )
{
if( p_playlist->p_general->i_children && index >= 0 && index < p_playlist->p_general->i_children )
{
p_return = p_playlist->p_general->pp_children[index];
}
else if( p_view && p_view->p_root && index >= 0 && index - p_playlist->p_general->i_children < p_view->p_root->i_children )
{
p_return = p_view->p_root->pp_children[index - p_playlist->p_general->i_children + 1];
}
}
}
else
{
playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
if( p_item && index < p_item->i_children && index >= 0 )
p_return = p_item->pp_children[index];
}
if( p_playlist->i_size >= 2 )
{
[o_status_field setStringValue: [NSString stringWithFormat:
......@@ -1292,118 +1455,13 @@ belongs to an Apple hidden private API, and then can "disapear" at any time*/
_NS("1 item in playlist"), p_playlist->i_size]];
}
}
vlc_object_release( p_playlist );
o_value = [[NSValue valueWithPointer: p_return] retain];
[o_outline_dict setObject:o_value forKey:[NSString stringWithFormat:@"%p",
[o_value pointerValue]]];
[o_outline_dict setObject:o_value forKey:[NSString stringWithFormat:@"%p", p_return]];
return o_value;
}
/* is the item expandable */
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item
{
int i_return = 0;
playlist_t * p_playlist = vlc_object_find( VLCIntf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
return NO;
if( item == nil )
{
/* root object */
playlist_view_t *p_view;
p_view = playlist_ViewFind( p_playlist, i_current_view );
if( p_view && p_view->p_root ) i_return = p_view->p_root->i_children;
if( i_current_view == VIEW_CATEGORY )
{
i_return--;
i_return += p_playlist->p_general->i_children;
}
}
else
{
playlist_item_t *p_item = (playlist_item_t *)[item pointerValue];
if( p_item )
i_return = p_item->i_children;
}
vlc_object_release( p_playlist );
if( i_return <= 0 )
return NO;
else
return YES;
}
/* retrieve the string values for the cells */
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)o_tc byItem:(id)item
{
id o_value = nil;
intf_thread_t *p_intf = VLCIntf;
playlist_t *p_playlist;
playlist_item_t *p_item;
if( item == nil || ![item isKindOfClass: [NSValue class]] ) return( @"error" );
p_playlist = vlc_object_find( p_intf, VLC_OBJECT_PLAYLIST,
FIND_ANYWHERE );
if( p_playlist == NULL )
{
return( @"error" );
}
p_item = (playlist_item_t *)[item pointerValue];
if( p_item == NULL )
{
vlc_object_release( p_playlist );
return( @"error");
}
if( [[o_tc identifier] isEqualToString:@"1"] )
{
o_value = [NSString stringWithUTF8String:
p_item->input.psz_name];
if( o_value == NULL )
o_value = [NSString stringWithCString:
p_item->input.psz_name];
}
else if( [[o_tc identifier] isEqualToString:@"2"] )
{
char *psz_temp;
psz_temp = vlc_input_item_GetInfo( &p_item->input ,_("Meta-information"),_("Artist") );
if( psz_temp == NULL )
o_value = @"";
else
{
o_value = [NSString stringWithUTF8String: psz_temp];
if( o_value == NULL )
{
o_value = [NSString stringWithCString: psz_temp];
}
free( psz_temp );
}
}
else if( [[o_tc identifier] isEqualToString:@"3"] )
{
char psz_duration[MSTRTIME_MAX_SIZE];
mtime_t dur = p_item->input.i_duration;
if( dur != -1 )
{
secstotimestr( psz_duration, dur/1000000 );
o_value = [NSString stringWithUTF8String: psz_duration];
}
else
{
o_value = @"-:--:--";
}
}
vlc_object_release( p_playlist );
return( o_value );
}
/* Required for drag & drop and reordering */
......
......@@ -39,6 +39,7 @@
IBOutlet id o_wh_txt_title;
IBOutlet id o_wh_txt_text;
IBOutlet id o_wh_btn_okay;
IBOutlet id o_playlist_wizard;
/* page one ("Hello") */
IBOutlet id o_t1_btn_mrInfo_strmg;
......
......@@ -39,6 +39,7 @@
#import "wizard.h"
#import "intf.h"
#import "network.h"
#import "playlist.h"
/*****************************************************************************
* VLCWizard implementation
......@@ -242,9 +243,9 @@ static VLCWizard *_o_sharedInstance = nil;
[o_t2_matrix_inputSourceType selectCellAtRow:0 column:0];
[[o_t2_matrix_inputSourceType cellAtRow:1 column:0] setState: NSOffState];
/* FIXME: we need to refresh the playlist-table as well */
[o_t2_tbl_plst setEnabled:NO];
[o_t2_fld_pathToNewStrm setEnabled:YES];
[o_t2_btn_chooseFile setEnabled:YES];
[o_t2_tbl_plst setEnabled:NO];
/* "Streaming 1" */
[o_t3_fld_address setStringValue: @""];
......@@ -293,8 +294,8 @@ static VLCWizard *_o_sharedInstance = nil;
[[o_t2_matrix_inputSourceType cellAtRow:0 column:0] setTitle: _NS("Select a stream")];
[[o_t2_matrix_inputSourceType cellAtRow:1 column:0] setTitle: _NS("Existing playlist item")];
[o_t2_btn_chooseFile setTitle: _NS("Choose...")];
[[[o_t2_tbl_plst tableColumnWithIdentifier:@"name"] headerCell] setStringValue: _NS("Name")];
[[[o_t2_tbl_plst tableColumnWithIdentifier:@"uri"] headerCell] setStringValue: _NS("URI")];
// [[[o_t2_tbl_plst tableColumnWithIdentifier:@"name"] headerCell] setStringValue: _NS("Name")];
// [[[o_t2_tbl_plst tableColumnWithIdentifier:@"uri"] headerCell] setStringValue: _NS("URI")];
[o_t2_box_prtExtrct setTitle: _NS("Partial Extract")];
[o_t2_ckb_enblPartExtrct setTitle: _NS("Enable")];
[o_t2_ckb_enblPartExtrct setToolTip: _NS("Use this to read only a part of " \
......@@ -389,6 +390,10 @@ static VLCWizard *_o_sharedInstance = nil;
}
[o_btn_backward setEnabled:YES];
[o_tab_pageHolder selectTabViewItemAtIndex:1];
/* Fill the playlist with current playlist items */
[o_playlist_wizard reloadOutlineView];
}
else if ([[[o_tab_pageHolder selectedTabViewItem] label] isEqualToString: @"Input"])
{
......@@ -416,12 +421,25 @@ static VLCWizard *_o_sharedInstance = nil;
{
/* set a flag that no file is selected */
stop = YES;
}else{
}
else
{
[o_userSelections setObject:[@"file://" stringByAppendingString:[o_t2_fld_pathToNewStrm stringValue]] forKey:@"pathToStrm"];
}
}else{
}
else
{
if ([o_t2_tbl_plst selectedRow] != -1)
{
playlist_item_t *p_item =
[o_playlist_wizard selectedPlaylistItem];
if( p_item->i_children <= 0 )
{
[o_userSelections setObject: [NSString stringWithFormat:
@"%s", p_item->input.psz_uri] forKey:@"pathToStrm"];
}
else
stop = YES;
/* FIXME: put the path of the selected pl-item to pathToStrm */
} else {
/* set a flag that no item is selected */
......@@ -443,7 +461,7 @@ static VLCWizard *_o_sharedInstance = nil;
} else {
/* show a sheet that the user didn't select a file */
NSBeginInformationalAlertSheet(_NS("No input selected"), _NS("OK"), @"", @"", o_wizard_window, nil, nil, nil, nil, _NS("You selected neither " \
"a new stream nor an existing playlist item. VLC is unable to " \
"a new stream nor a valid playlist item. VLC is unable to " \
"guess, which input you want use. \n\n Choose one " \
"before going to the next page."));
}
......
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