void SCH_EDIT_FRAME::PasteListOfItems( wxDC* DC )
{
    unsigned       i;
    SCH_ITEM*      item;
    SCH_SHEET_LIST hierarchy;    // This is the entire schematic hierarcy.

    if( m_blockItems.GetCount() == 0 )
    {
        DisplayError( this, _( "No item to paste." ) );
        return;
    }

    wxFileName destFn = m_CurrentSheet->Last()->GetFileName();

    if( destFn.IsRelative() )
        destFn.MakeAbsolute( Prj().GetProjectPath() );

    // Make sure any sheets in the block to be pasted will not cause recursion in
    // the destination sheet.
    for( i = 0; i < m_blockItems.GetCount(); i++ )
    {
        item = (SCH_ITEM*) m_blockItems.GetItem( i );

        if( item->Type() == SCH_SHEET_T )
        {
            SCH_SHEET* sheet = (SCH_SHEET*)item;
            wxFileName srcFn = sheet->GetFileName();

            if( srcFn.IsRelative() )
                srcFn.MakeAbsolute( Prj().GetProjectPath() );

            SCH_SHEET_LIST sheetHierarchy( sheet );

            if( hierarchy.TestForRecursion( sheetHierarchy,
                                            destFn.GetFullPath( wxPATH_UNIX ) ) )
            {
                wxString msg;

                msg.Printf( _( "The sheet changes cannot be made because the destination "
                               "sheet already has the sheet <%s> or one of it's subsheets "
                               "as a parent somewhere in the schematic hierarchy." ),
                            GetChars( sheet->GetFileName() ) );
                DisplayError( this, msg );
                return;
            }

            // Duplicate sheet names and sheet time stamps are not valid.  Use a time stamp
            // based sheet name and update the time stamp for each sheet in the block.
            unsigned long timeStamp = (unsigned long)GetNewTimeStamp();

            sheet->SetName( wxString::Format( wxT( "sheet%8.8lX" ), timeStamp ) );
            sheet->SetTimeStamp( (time_t)timeStamp );
        }
    }

    PICKED_ITEMS_LIST picklist;

    for( i = 0; i < m_blockItems.GetCount(); i++ )
    {
        item = DuplicateStruct( (SCH_ITEM*) m_blockItems.GetItem( i ) );

        // Creates data, and push it as new data in undo item list buffer
        ITEM_PICKER picker( item, UR_NEW );
        picklist.PushItem( picker );

        // Clear annotation and init new time stamp for the new components and sheets:
        if( item->Type() == SCH_COMPONENT_T )
        {
            ( (SCH_COMPONENT*) item )->SetTimeStamp( GetNewTimeStamp() );
            ( (SCH_COMPONENT*) item )->ClearAnnotation( NULL );
        }
        else if( item->Type() == SCH_SHEET_T )
        {
            ( (SCH_SHEET*) item )->SetTimeStamp( GetNewTimeStamp() );
        }

        SetSchItemParent( item, GetScreen() );
        item->Draw( m_canvas, DC, wxPoint( 0, 0 ), GR_DEFAULT_DRAWMODE );
        GetScreen()->Append( item );
    }

    SaveCopyInUndoList( picklist, UR_NEW );

    MoveItemsInList( picklist, GetScreen()->m_BlockLocate.GetMoveVector() );

    // Clear flags for all items.
    GetScreen()->ClearDrawingState();

    OnModify();

    return;
}
bool SCH_EDIT_FRAME::EditSheet( SCH_SHEET* aSheet, SCH_SHEET_PATH* aHierarchy )
{
    if( aSheet == NULL || aHierarchy == NULL )
        return false;

    SCH_SHEET_LIST hierarchy;       // This is the schematic sheet hierarchy.

    // Get the new texts
    DIALOG_SCH_SHEET_PROPS dlg( this );

    wxString units = GetUnitsLabel( g_UserUnit );
    dlg.SetFileName( aSheet->GetFileName() );
    dlg.SetFileNameTextSize( StringFromValue( g_UserUnit, aSheet->GetFileNameSize() ) );
    dlg.SetFileNameTextSizeUnits( units );
    dlg.SetSheetName( aSheet->GetName() );
    dlg.SetSheetNameTextSize( StringFromValue( g_UserUnit, aSheet->GetSheetNameSize() ) );
    dlg.SetSheetNameTextSizeUnits( units );
    dlg.SetSheetTimeStamp( wxString::Format( wxT("%8.8lX"),
                           (unsigned long) aSheet->GetTimeStamp() ) );

    /* This ugly hack fixes a bug in wxWidgets 2.8.7 and likely earlier
     * versions for the flex grid sizer in wxGTK that prevents the last
     * column from being sized correctly.  It doesn't cause any problems
     * on win32 so it doesn't need to wrapped in ugly #ifdef __WXGTK__
     * #endif.
     * Still presen in wxWidgets 3.0.2
     */
    dlg.Layout();
    dlg.Fit();
    dlg.SetMinSize( dlg.GetSize() );
    dlg.GetSizer()->Fit( &dlg );

    if( dlg.ShowModal() == wxID_CANCEL )
        return false;

    wxFileName fileName = dlg.GetFileName();
    fileName.SetExt( SchematicFileExtension );

    if( !fileName.IsOk() )
    {
        DisplayError( this, _( "File name is not valid!" ) );
        return false;
    }

    // Duplicate sheet names are not valid.
    const SCH_SHEET* sheet = hierarchy.FindSheetByName( dlg.GetSheetName() );

    if( sheet && (sheet != aSheet) )
    {
        DisplayError( this, wxString::Format( _( "A sheet named \"%s\" already exists." ),
                                              GetChars( dlg.GetSheetName() ) ) );
        return false;
    }

    wxString msg;
    bool loadFromFile = false;
    SCH_SCREEN* useScreen = NULL;

    wxString newFilename = fileName.GetFullPath();

    // Search for a schematic file having the same filename
    // already in use in the hierarchy or on disk, in order to reuse it.
    if( !g_RootSheet->SearchHierarchy( newFilename, &useScreen ) )
    {
        // if user entered a relative path, allow that to stay, but do the
        // file existence test with an absolute (full) path.  This transformation
        // is local to this scope, but is the same one used at load time later.
        wxString absolute = Prj().AbsolutePath( newFilename );

        loadFromFile = wxFileExists( absolute );
    }

    // Inside Eeschema, filenames are stored using unix notation
    newFilename.Replace( wxT( "\\" ), wxT( "/" ) );

    if( aSheet->GetScreen() == NULL )              // New sheet.
    {
        if( useScreen || loadFromFile )            // Load from existing file.
        {
            if( useScreen != NULL )
            {
                msg.Printf( _( "A file named '%s' already exists in the current schematic "
                               "hierarchy." ), GetChars( newFilename ) );
            }
            else
            {
                msg.Printf( _( "A file named '%s' already exists." ), GetChars( newFilename ) );
            }

            msg += _( "\n\nDo you want to create a sheet with the contents of this file?" );

            if( !IsOK( this, msg ) )
            {
                return false;
            }
        }
        else                                                   // New file.
        {
            aSheet->SetScreen( new SCH_SCREEN( &Kiway() ) );
            aSheet->GetScreen()->SetMaxUndoItems( m_UndoRedoCountMax );
            aSheet->GetScreen()->SetFileName( newFilename );
        }
    }
    else                                                       // Existing sheet.
    {
        bool isUndoable = true;
        bool renameFile = false;

        // We are always using here a case insensitive comparison
        // to avoid issues under Windows, although under Unix
        // filenames are case sensitive.
        // But many users create schematic under both Unix and Windows
        if( newFilename.CmpNoCase( aSheet->GetFileName() ) != 0 )
        {
            // Sheet file name changes cannot be undone.
            isUndoable = false;
            msg = _( "Changing the sheet file name cannot be undone.  " );

            if( useScreen || loadFromFile )                    // Load from existing file.
            {
                wxString tmp;

                if( useScreen != NULL )
                {
                    tmp.Printf( _( "A file named <%s> already exists in the current schematic "
                                   "hierarchy." ), GetChars( newFilename ) );
                }
                else
                {
                    tmp.Printf( _( "A file named <%s> already exists." ),
                                GetChars( newFilename ) );
                }

                msg += tmp;
                msg += _( "\n\nDo you want to replace the sheet with the contents of this file?" );

                if( !IsOK( this, msg ) )
                    return false;

                if( loadFromFile )
                    aSheet->SetScreen( NULL );
            }
            else                                               // Save to new file name.
            {
                if( aSheet->GetScreenCount() > 1 )
                {
                    msg += _( "This sheet uses shared data in a complex hierarchy.\n\n" );
                    msg += _( "Do you wish to convert it to a simple hierarchical sheet?" );

                    if( !IsOK( NULL, msg ) )
                        return false;
                }

                renameFile = true;
            }
        }

        m_canvas->SetIgnoreMouseEvents( true );

        if( isUndoable )
            SaveCopyInUndoList( aSheet, UR_CHANGED );

        if( renameFile )
        {
            aSheet->GetScreen()->SetFileName( newFilename );
            SaveEEFile( aSheet->GetScreen() );

            // If the the associated screen is shared by more than one sheet, remove the
            // screen and reload the file to a new screen.  Failure to do this will trash
            // the screen reference counting in complex hierarchies.
            if( aSheet->GetScreenCount() > 1 )
            {
                aSheet->SetScreen( NULL );
                loadFromFile = true;
            }
        }
    }

    aSheet->SetFileName( newFilename );

    if( useScreen )
        aSheet->SetScreen( useScreen );
    else if( loadFromFile )
        aSheet->Load( this );

    aSheet->SetFileNameSize( ValueFromString( g_UserUnit, dlg.GetFileNameTextSize() ) );
    aSheet->SetName( dlg.GetSheetName() );
    aSheet->SetSheetNameSize( ValueFromString( g_UserUnit, dlg.GetSheetNameTextSize() ) );

    if( aSheet->GetName().IsEmpty() )
        aSheet->SetName( wxString::Format( wxT( "Sheet%8.8lX" ),
                                           (long unsigned) aSheet->GetTimeStamp() ) );

    // Make sure the sheet changes do not cause any recursion.
    SCH_SHEET_LIST sheetHierarchy( aSheet );

    // Make sure files have fully qualified path and file name.
    wxFileName destFn = aHierarchy->Last()->GetFileName();

    if( destFn.IsRelative() )
        destFn.MakeAbsolute( Prj().GetProjectPath() );

    if( hierarchy.TestForRecursion( sheetHierarchy, destFn.GetFullPath( wxPATH_UNIX ) ) )
    {
        msg.Printf( _( "The sheet changes cannot be made because the destination sheet already "
                       "has the sheet <%s> or one of it's subsheets as a parent somewhere in "
                       "the schematic hierarchy." ),
                    GetChars( newFilename ) );
        DisplayError( this, msg );
        return false;
    }

    m_canvas->MoveCursorToCrossHair();
    m_canvas->SetIgnoreMouseEvents( false );
    OnModify();

    return true;
}