Update of /cvsroot/audacity/audacity-src/src
In directory 23jxhf1.ch3.sourceforge.com:/tmp/cvs-serv20171/src

Modified Files:
        AudacityApp.h LabelTrack.cpp LabelTrack.h Makefile.in 
        Menus.cpp Project.cpp Project.h TrackPanel.cpp TrackPanel.h 
Added Files:
        CaptureEvents.cpp CaptureEvents.h 
Log Message:
Fix bugs in Edit->Labeled Regions commands; changes for copy-paste of labels; a 
few linking considerations.


Index: Project.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Project.h,v
retrieving revision 1.167
retrieving revision 1.168
diff -u -d -r1.167 -r1.168
--- Project.h   20 Sep 2009 19:06:06 -0000      1.167
+++ Project.h   31 Oct 2009 15:24:22 -0000      1.168
@@ -249,7 +249,7 @@
    void Rewind(bool shift);
    void SkipEnd(bool shift);
    void SetStop(bool bStopped);
-   void EditByLabel( WaveTrack::EditFunction action ); 
+   void EditByLabel( WaveTrack::EditFunction action, bool groupIteration ); 
    void EditClipboardByLabel( WaveTrack::EditDestFunction action );
    bool IsSticky();
    bool GetStickyFlag() { return mStickyFlag; };
@@ -387,6 +387,14 @@
    
    static bool GetCacheBlockFiles();
    
+   // Given a track list and selection boundaries, returns a string
+   // representation of all the labels
+   wxString AllLabelsText(TrackList *l, double t0, double t1,
+                          bool selectedOnly = false);
+
+   // Copies the text of each selected label to the system clipboard
+   void CopyLabelTracksText();
+
  public:
    bool IsSoloSimple() { return mSoloPref == wxT("Simple"); };
    bool IsSoloNone() { return mSoloPref == wxT("None"); };

Index: LabelTrack.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/LabelTrack.cpp,v
retrieving revision 1.119
retrieving revision 1.120
diff -u -d -r1.119 -r1.120
--- LabelTrack.cpp      18 Oct 2009 19:58:16 -0000      1.119
+++ LabelTrack.cpp      31 Oct 2009 15:24:21 -0000      1.120
@@ -57,96 +57,7 @@
 #include "Project.h"
 #include "commands/CommandManager.h"
 
-#if defined(__WXGTK__) & defined(HAVE_GTK)
-// As of wxGTK 2.8.9, there is a problem in the wxClipboard class that
-// allows recursive event processing.  This problem has been corrected
-// by wxWidgets 2.9+.  However, this han't made it into a release yet,
-// so we have to work around it.
-//
-// This is done by pulling/merging in some code from wx29 and creating
-// the following class to capture events while accessing the clipboard
-// to prevent the asynchronous clipboard access from causing recursive
-// event processing.
-
-#include <wx/app.h>
-#include <wx/dynarray.h>
-
-#include <gtk/gtk.h>
-
-extern GtkWidget *wxGetRootWindow();
-
-static void main_do_event(GdkEvent *event, wxArrayPtrVoid *queue)
-{
-   switch (event->type)
-   {
-      case GDK_NOTHING:
-         // Ignore it
-      break;
-
-      case GDK_SELECTION_REQUEST:
-      case GDK_SELECTION_NOTIFY:
-      case GDK_SELECTION_CLEAR:
-#if GTK_CHECK_VERSION(2,6,0)
-      case GDK_OWNER_CHANGE:
-#endif
-         // process it now
-         gtk_main_do_event(event);
-      break;
-
-      default:
-         // process it later (but make a copy; the caller will free the event 
pointer)
-         queue->Add(gdk_event_copy(event));
-      break;
-   }
-
-   // don't allow idle callbacks while we're active
-   wxTheApp->SuspendIdleCallback();
-
-   return;
-}
-
-class CaptureEvents
-{
- public:
-   CaptureEvents()
-   {
-#if wxUSE_LOG
-      // disable log flushing from here because a call to wxYield() shouldn't
-      // normally result in message boxes popping up &c
-      wxLog::Suspend();
-#endif
-
-      // temporarily replace the global GDK event handler with our function
-      gdk_event_handler_set((GdkEventFunc)main_do_event, &queue, NULL);
-
-      // temporarily suspend idle callbacks
-      wxTheApp->SuspendIdleCallback();
-   }
-
-   virtual ~CaptureEvents()
-   {
-      gdk_event_handler_set((GdkEventFunc)gtk_main_do_event, NULL, NULL);
-   
-      // put all unprocessed GDK events back in the queue
-      GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
-      size_t cnt = queue.GetCount();
-      for (size_t i = 0; i < cnt; i++) {
-         GdkEvent* event = (GdkEvent*)queue[i];
-         // NOTE: gdk_display_put_event makes a copy of the event passed to it
-         gdk_display_put_event(disp, event);
-         gdk_event_free(event);
-      }
-
-#if wxUSE_LOG
-      // let the logs be flashed again
-      wxLog::Resume();
-#endif
-   }
-
- private:
-   wxArrayPtrVoid queue;
-};
-#endif
+#include "CaptureEvents.h"
 
 wxFont LabelTrack::msFont;
 
@@ -2251,13 +2162,43 @@
    int len = mLabels.Count();
 
    for (int i = 0; i < len; i++) {
-      if (t0 <= mLabels[i]->t && mLabels[i]->t <= t1) {
+      // If the label "surrounds" the selection, split it around the selection
+      if (mLabels[i]->t < t0 && t1 < mLabels[i]->t1)
+      {
+         LabelStruct *l = new LabelStruct();
+         l->t = t1;
+         l->t1 = mLabels[i]->t1;
+         l->title = mLabels[i]->title;
+
+         mLabels[i]->t1 = t0;
+
+         // This might not be the right place to insert, but we sort at the end
+         ++i;
+         mLabels.Insert(l, i);
+      }
+
+      // If label begins in the selection, move the beginning to selection end
+      if (t0 <= mLabels[i]->t && mLabels[i]->t <= t1)
+      {
+         mLabels[i]->t = t1;
+      }
+      // If label ends in the selection, move the end to selection beginning
+      if (t0 <= mLabels[i]->t1 && mLabels[i]->t1 <= t1)
+      {
+         mLabels[i]->t1 = t0;
+      }
+
+      // Delete labels that were totally selected
+      if (mLabels[i]->t1 < mLabels[i]->t)
+      {
          DeleteLabel( i );
          len--;
          i--;
       }
    }
 
+   SortLabels();
+
    return true;
 }
 
@@ -2539,6 +2480,25 @@
    }
 }
 
+wxString LabelTrack::GetTextOfLabels(double t0, double t1)
+{
+   bool firstLabel = true;
+   wxString retVal;
+
+   for (unsigned int i=0; i < mLabels.GetCount(); ++i)
+   {
+      if (mLabels[i]->t >= t0 && mLabels[i]->t1 <= t1)
+      {
+         if (!firstLabel)
+            retVal += '\t';
+         firstLabel = false;
+         retVal += mLabels[i]->title;
+      }
+   }
+
+   return retVal;
+}
+
 // Indentation settings for Vim and Emacs and unique identifier for Arch, a
 // version control system. Please do not modify past this point.
 //

Index: TrackPanel.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackPanel.h,v
retrieving revision 1.140
retrieving revision 1.141
diff -u -d -r1.140 -r1.141
--- TrackPanel.h        10 Sep 2009 06:28:25 -0000      1.140
+++ TrackPanel.h        31 Oct 2009 15:24:23 -0000      1.141
@@ -252,6 +252,7 @@
    void ExtendSelection(int mouseXCoordinate, int trackLeftEdge,
                         Track *pTrack);
    void SelectTracksByLabel( LabelTrack *t );
+   void SelectTrackLength(Track *t);
 
 
    // AS: Cursor handling

Index: Makefile.in
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Makefile.in,v
retrieving revision 1.168
retrieving revision 1.169
diff -u -d -r1.168 -r1.169
--- Makefile.in 16 Sep 2009 20:17:18 -0000      1.168
+++ Makefile.in 31 Oct 2009 15:24:21 -0000      1.169
@@ -57,6 +57,7 @@
        BatchCommands.o \
        BatchProcessDialog.o \
        Benchmark.o \
+       CaptureEvents.o \
        Dependencies.o \
        Envelope.o \
        FFmpeg.o \

Index: AudacityApp.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/AudacityApp.h,v
retrieving revision 1.59
retrieving revision 1.60
diff -u -d -r1.59 -r1.60
--- AudacityApp.h       15 Oct 2009 19:56:50 -0000      1.59
+++ AudacityApp.h       31 Oct 2009 15:24:21 -0000      1.60
@@ -81,6 +81,7 @@
    NoteTracksExistFlag    = 0x00800000,  //gsw
    NoteTracksSelectedFlag = 0x01000000,  //gsw
    HaveRecentFiles        = 0x02000000,
+   LinkingDisabledFlag    = 0x04000000,  //awd
 
    NoFlagsSpecifed        = 0xffffffff
 };

--- NEW FILE: CaptureEvents.h ---
/**********************************************************************

   Audacity: A Digital Audio Editor
   Audacity(R) is copyright (c) 1999-2008 Audacity Team.
   License: GPL v2.  See License.txt.

   CaptureEvents.h
   Created by Al Dimond, Oct. 2009 (from code by someone else)

******************************************************************//**

\class CaptureEvents
\brief RAII-style class to work around a bug in wxGTK 2.8.9-?

*//*******************************************************************/

#ifndef _AUDACITY_CAPTURE_EVENTS_
#define _AUDACITY_CAPTURE_EVENTS_

#if defined(__WXGTK__) && defined(HAVE_GTK)
// As of wxGTK 2.8.9, there is a problem in the wxClipboard class that
// allows recursive event processing.  This problem has been corrected
// by wxWidgets 2.9+.  However, this han't made it into a release yet,
// so we have to work around it.
//
// This is done by pulling/merging in some code from wx29 and creating
// the following class to capture events while accessing the clipboard
// to prevent the asynchronous clipboard access from causing recursive
// event processing.

#include <wx/dynarray.h>

class CaptureEvents
{
 public:
   CaptureEvents();

   virtual ~CaptureEvents();

 private:
   wxArrayPtrVoid queue;
};
#endif

#endif

Index: LabelTrack.h
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/LabelTrack.h,v
retrieving revision 1.52
retrieving revision 1.53
diff -u -d -r1.52 -r1.53
--- LabelTrack.h        18 Oct 2009 19:58:17 -0000      1.52
+++ LabelTrack.h        31 Oct 2009 15:24:21 -0000      1.53
@@ -75,11 +75,11 @@
    friend class LabelStruct;
 
  public:
-       bool IsGoodLabelCharacter(int keyCode, wxChar charCode);
-       bool IsGoodLabelFirstCharacter(int keyCode, wxChar charCode);
+   bool IsGoodLabelCharacter(int keyCode, wxChar charCode);
+   bool IsGoodLabelFirstCharacter(int keyCode, wxChar charCode);
    bool IsTextSelected();
 
-       void CreateCustomGlyphs();
+   void CreateCustomGlyphs();
    LabelTrack(DirManager * projDirManager);
    LabelTrack(const LabelTrack &orig);
 
@@ -174,6 +174,9 @@
    void ChangeLabelsOnReverse(double b, double e);
    void ScaleLabels(double b, double e, double change);
    double AdjustTimeStampOnScale(double t, double b, double e, double change);
+   
+   // Returns tab-separated text of all labels completely within given region
+   wxString GetTextOfLabels(double t0, double t1);
 
  public:
    void SortLabels();

Index: TrackPanel.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/TrackPanel.cpp,v
retrieving revision 1.478
retrieving revision 1.479
diff -u -d -r1.478 -r1.479
--- TrackPanel.cpp      20 Oct 2009 23:08:27 -0000      1.478
+++ TrackPanel.cpp      31 Oct 2009 15:24:22 -0000      1.479
@@ -776,6 +776,45 @@
    }
 }
 
+/// Set selection length to the length of a track -- but if linking is turned
+/// on, use the largest possible selection in the group.  And if it's a stereo
+/// track, do the same for the stereo channels.
+void TrackPanel::SelectTrackLength(Track *t)
+{
+   AudacityProject *p = GetActiveProject();
+   TrackGroupIterator it(mTracks);
+   Track *t1 = it.First(t);
+   double minOffset = t->GetOffset();
+   double maxEnd = t->GetEndTime();
+
+   // If we have a group and linking is on, check the group tracks
+   if (p->IsSticky() && t1 != NULL)
+   {
+      for ( ; t1; t1 = it.Next())
+      {
+         if (t1->GetOffset() < minOffset)
+            minOffset = t1->GetOffset();
+         if (t1->GetEndTime() > maxEnd)
+            maxEnd = t1->GetEndTime();
+      }
+   }
+   else
+   {
+      // Otherwise, check for a stereo pair
+      t1 = t->GetLink();
+      if (t1)
+      {
+         if (t1->GetOffset() < minOffset)
+            minOffset = t1->GetOffset();
+         if (t1->GetEndTime() > maxEnd)
+            maxEnd = t1->GetEndTime();
+      }
+   }
+
+   mViewInfo->sel0 = minOffset;
+   mViewInfo->sel1 = maxEnd;
+}
+
 void TrackPanel::GetTracksUsableArea(int *width, int *height) const
 {
    GetSize(width, height);
@@ -1684,9 +1723,7 @@
       mTracks->Select(mCapturedTrack);
 
       // Default behavior: select whole track
-      mViewInfo->sel0 = mCapturedTrack->GetOffset();
-      mViewInfo->sel1 = mCapturedTrack->GetEndTime();
-      
+      SelectTrackLength(mCapturedTrack);
       
       // Special case: if we're over a clip in a WaveTrack,
       // select just that clip
@@ -3726,17 +3763,7 @@
    SelectNone();
    mTracks->Select(t);
    SetFocusedTrack(t);
-   Track *t1 = t->GetLink();
-   if(t1)
-   {
-      mViewInfo->sel0 = wxMin(t->GetOffset(), t1->GetOffset());
-      mViewInfo->sel1 = wxMax(t->GetEndTime(), t1->GetEndTime());
-   }
-   else
-   {
-      mViewInfo->sel0 = t->GetOffset();
-      mViewInfo->sel1 = t->GetEndTime();
-   }
+   SelectTrackLength(t);
 
    this->Refresh(false);  
    #ifdef EXPERIMENTAL_MIXER_BOARD

Index: Menus.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Menus.cpp,v
retrieving revision 1.531
retrieving revision 1.532
diff -u -d -r1.531 -r1.532
--- Menus.cpp   20 Oct 2009 23:32:09 -0000      1.531
+++ Menus.cpp   31 Oct 2009 15:24:21 -0000      1.532
@@ -110,6 +110,8 @@
 #include "SplashDialog.h"
 #include "widgets/ErrorDialog.h"
 
+#include "CaptureEvents.h"
+
 #ifdef EXPERIMENTAL_SCOREALIGN
 #include "audioreader.h"
 #include "scorealign.h"
@@ -414,21 +416,28 @@
    
/////////////////////////////////////////////////////////////////////////////
 
    c->BeginSubMenu(_("La&beled Regions"));
-   c->SetDefaultFlags(LabelsSelectedFlag, LabelsSelectedFlag);
+   c->SetDefaultFlags(AudioIONotBusyFlag | LabelsSelectedFlag | 
TimeSelectedFlag,
+                      AudioIONotBusyFlag | LabelsSelectedFlag | 
TimeSelectedFlag);
 
-   c->AddItem(wxT("CutLabels"), _("&Cut"), FN(OnCutLabels), wxT("Alt+X"));
+   c->AddItem(wxT("CutLabels"), _("&Cut"), FN(OnCutLabels), wxT("Alt+X"),
+              AudioIONotBusyFlag | LabelsSelectedFlag | TimeSelectedFlag | 
LinkingDisabledFlag,
+              AudioIONotBusyFlag | LabelsSelectedFlag | TimeSelectedFlag | 
LinkingDisabledFlag);
    c->AddItem(wxT("SplitCutLabels"), _("&Split Cut"), FN(OnSplitCutLabels), 
wxT("Shift+Alt+X"));
    c->AddItem(wxT("CopyLabels"), _("Co&py"), FN(OnCopyLabels), 
wxT("Shift+Alt+C"));
 
    c->AddSeparator();
 
-   c->AddItem(wxT("DeleteLabels"), _("&Delete"), FN(OnDeleteLabels), 
wxT("Alt+K"));
+   c->AddItem(wxT("DeleteLabels"), _("&Delete"), FN(OnDeleteLabels), 
wxT("Alt+K"),
+              AudioIONotBusyFlag | LabelsSelectedFlag | TimeSelectedFlag | 
LinkingDisabledFlag,
+              AudioIONotBusyFlag | LabelsSelectedFlag | TimeSelectedFlag | 
LinkingDisabledFlag);
    c->AddItem(wxT("SplitDeleteLabels"), _("Sp&lit Delete"), 
FN(OnSplitDeleteLabels), wxT("Shift+Alt+K"));
    c->AddItem(wxT("SilenceLabels"), _("Sile&nce"), FN(OnSilenceLabels), 
wxT("Alt+L"));
 
    c->AddSeparator();
 
-   c->AddItem(wxT("SplitLabels"), _("Spli&t"), FN(OnSplitLabels), 
wxT("Alt+I"));
+   c->AddItem(wxT("SplitLabels"), _("Spli&t"), FN(OnSplitLabels), wxT("Alt+I"),
+              AudioIONotBusyFlag | LabelsSelectedFlag,
+              AudioIONotBusyFlag | LabelsSelectedFlag);
    c->AddItem(wxT("JoinLabels"), _("&Join"),  FN(OnJoinLabels), wxT("Alt+J"));
    c->AddItem(wxT("DisjoinLabels"), _("Detac&h at Silences"), 
FN(OnDisjoinLabels), wxT("Shift+Alt+J"));
 
@@ -1449,6 +1458,9 @@
    if (wxGetApp().GetRecentFiles()->GetCount() > 0)
       flags |= HaveRecentFiles;
 
+   if (!IsSticky())
+      flags |= LinkingDisabledFlag;
+
    return flags;
 }
 
@@ -2971,7 +2983,7 @@
       }
       n = iter.Next();
    }
-   
+
    ClearClipboard();
    n = iter.First();
    while (n) {
@@ -3000,6 +3012,9 @@
       n = iter.Next();
    }
 
+   // Set the system clipboard
+   CopyLabelTracksText();
+
    n = iter.First();
    while (n) {
       if (n->GetSelected()) {
@@ -3049,6 +3064,9 @@
    Track *n = iter.First();
    Track *dest;
 
+   // Set the system clipboard
+   CopyLabelTracksText();
+
    ClearClipboard();
    n = iter.First();
    while (n) {
@@ -3059,7 +3077,8 @@
             ((WaveTrack*)n)->SplitCut(mViewInfo.sel0, mViewInfo.sel1, &dest);
          } else
          {
-            n->Cut(mViewInfo.sel0, mViewInfo.sel1, &dest);
+            n->Copy(mViewInfo.sel0, mViewInfo.sel1, &dest);
+            n->Silence(mViewInfo.sel0, mViewInfo.sel1);
          }
          if (dest) {
             dest->SetChannel(n->GetChannel());
@@ -3118,6 +3137,9 @@
 
    msClipLen = (mViewInfo.sel1 - mViewInfo.sel0);
    msClipProject = this;
+
+   // Set system clipboard
+   CopyLabelTracksText();
    
    //Make sure the menus/toolbar states get updated
    mTrackPanel->Refresh(false);
@@ -3125,16 +3147,13 @@
 
 void AudacityProject::OnPaste()
 {
-   // Handle Label tracks first
+   // Handle text pastes first
    TrackListOfKindIterator iterlt(Track::Label, mTracks);
 
    LabelTrack *lt = (LabelTrack *) iterlt.First();
    if (lt) {
 
-      // Look for selected label tracks and active labels
-      bool selected = false;
       while (lt) {
-
          // Does this track have an active label?
          if (lt->IsSelected()) {
 
@@ -3154,63 +3173,84 @@
             }
          }
 
-         // Remember that we found a selected one
-         if (lt->GetSelected()) {
-            selected = true;
-         }
-
          // Find the next one
          lt = (LabelTrack *) iterlt.Next();
       }
+   }
 
-      // Were any Label tracks without active labels selected?
-      if (selected) {
-         LabelTrack *plt = NULL;
-         bool pasted = false;
+   // If there are no tracks on the clipboard, or if the external clipboard has
+   // been set more recently than the internal one (that is, if the external
+   // clipboard's text doesn't match the internal clipboard's label text), then
+   // we try to create a label in all selected label tracks with the clipboard
+   // text
+   wxString sysCbText;
 
-         // Paste new labels into all selected label tracks
-         lt = (LabelTrack *) iterlt.First();
-         while (lt) {
-            if (lt->GetSelected()) {
-               // Ensure that the last pasted label gets unselected.  This will
-               // leave only one "active" label when we're done.
-               if (plt) {
-                  plt->Unselect();
-               }
+   {
+#if defined(__WXGTK__) && HAVE_GTK
+      CaptureEvents capture;
+#endif
 
-               // Add a new label
-               lt->AddLabel(mViewInfo.sel0, mViewInfo.sel1);
+      if (wxTheClipboard->IsSupported(wxDF_TEXT))
+      {
+         if (wxTheClipboard->Open())
+         {
+            wxTextDataObject data;
+            wxTheClipboard->GetData(data);
+            wxTheClipboard->Close();
+            sysCbText = data.GetText();
+         }
+      }
+   }
 
-               // Now paste the text into it
-               if (lt->PasteSelectedText(mViewInfo.sel0, mViewInfo.sel1)) {
+   if (msClipboard->GetCount() == 0 ||
+         sysCbText != AllLabelsText(msClipboard, 0.0, msClipLen))
+   {
+      LabelTrack *plt = NULL;
+      bool pasted = false;
 
-                  // Remember that we pasted something
-                  pasted = true;
+      // Paste new labels into all selected label tracks
+      lt = (LabelTrack *) iterlt.First();
+      while (lt) {
+         if (lt->GetSelected()) {
+            // Ensure that the last pasted label gets unselected.  This will
+            // leave only one "active" label when we're done.
+            if (plt) {
+               plt->Unselect();
+            }
 
-                  // Make sure caret is in view
-                  int x;
-                  if (lt->CalcCursorX(this, &x)) {
-                     mTrackPanel->ScrollIntoView(x);
-                  }
-               }
+            // Add a new label
+            lt->AddLabel(mViewInfo.sel0, mViewInfo.sel1);
 
-               // Remember this track so we can unselect the new label if its
-               // not the last one pasted
-               plt = lt;
+            // Now paste the text into it
+            if (lt->PasteSelectedText(mViewInfo.sel0, mViewInfo.sel1)) {
+
+               // Remember that we pasted something
+               pasted = true;
+
+               // Make sure caret is in view
+               int x;
+               if (lt->CalcCursorX(this, &x)) {
+                  mTrackPanel->ScrollIntoView(x);
+               }
             }
 
-            // Find the next one
-            lt = (LabelTrack *) iterlt.Next();
+            // Remember this track so we can unselect the new label if its
+            // not the last one pasted
+            plt = lt;
          }
 
-         // We're done if we pasted into any tracks
-         if (pasted) {
-            PushState(_("Pasted from the clipboard"), _("Paste"));
+         // Find the next one
+         lt = (LabelTrack *) iterlt.Next();
+      }
 
-            // Redraw everyting (is that necessary???) and bail
-            RedrawProject();
-            return;
-         }
+      // If we pasted into any tracks we're done
+      if (pasted) {
+         PushState(_("Pasted from the clipboard"), _("Paste"));
+
+         // Redraw everyting (is that necessary???)
+         RedrawProject();
+
+         return;
       }
    }
 
@@ -3222,7 +3262,6 @@
 
    int numSelected = 0;
 
-   // Pastes text into the first label track or counts selected wave tracks
    while (countTrack) {
       if (countTrack->GetSelected()) {
          numSelected++;
@@ -3234,7 +3273,7 @@
    if (numSelected == 0) {
       TrackListIterator clipIter(msClipboard);
       Track *c = clipIter.First();
-      if(c == NULL)  // if there is no audio to paste...
+      if(c == NULL)  // if there is nothing to paste
          return;
       Track *n;
       Track *f = NULL;
@@ -3298,8 +3337,6 @@
 
    // Otherwise, paste into the selected tracks.
 
-   // This old logic is no longer necessary now that we have WaveClips:
-   //
    double t0 = mViewInfo.sel0;
    double t1 = mViewInfo.sel1;
 
@@ -3308,7 +3345,7 @@
 
    Track *n = iter.First();
    Track *c = clipIter.First();
-   if(c == NULL)    // if there is no audio to paste...
+   if (c == NULL)
       return;
    Track *f = NULL;
    Track *tmpSrc = NULL;
@@ -3318,7 +3355,6 @@
    bool pastedSomething = false;
    bool trackTypeMismatch = false;
    bool advanceClipboard = true;
-   double srcLength = c->GetEndTime();
 
    // Keeps track of whether n would be the first WaveTrack in its group to
    // receive data from the paste.
@@ -3350,9 +3386,9 @@
             c = tmpC;
             while (n && (c->GetKind() != n->GetKind()) )
             {
-               n = iter.Next();
                if (n && n->GetKind() == Track::Label)
                   firstInGroup = true;
+               n = iter.Next();
             }
             if (!n) c = NULL;               
          }
@@ -3390,10 +3426,29 @@
             // If not the first in group we set useHandlePaste to true
             pastedSomething = ((WaveTrack*)n)->ClearAndPaste(t0, t1,
                   (WaveTrack*)c, true, true, NULL, false, !firstInGroup);
-            firstInGroup = !pastedSomething;
+            firstInGroup = firstInGroup && !pastedSomething;
+         }
+         else if (c->GetKind() == Track::Label &&
+                  n && n->GetKind() == Track::Label)
+         {
+            // AWD: LabelTrack::Paste() doesn't shift future labels (and
+            // WaveTrack::HandleGroupPaste() doesn't adjust selected group
+            // tracks, so some other track's paste hasn't done it either).  To
+            // be (sort of) consistent with Clear behavior, we'll only shift
+            // them if linking is on and we have already pasted into a wave
+            // track in this group.
+            if (IsSticky() && !firstInGroup)
+            {
+               ((LabelTrack *)n)->ShiftLabelsOnClear(t0, t1);
+               ((LabelTrack *)n)->ShiftLabelsOnInsert(msClipLen, t0);
+            }
+
+            pastedSomething = n->Paste(t0, c);
          }
          else
+         {
             pastedSomething = n->Paste(t0, c);
+         }
                  
          // When copying from mono to stereo track, paste the wave form
          // to both channels
@@ -3434,19 +3489,20 @@
          }
       }
 
-      n = iter.Next();
       if (n && n->GetKind() == Track::Label)
          firstInGroup = true;
+      n = iter.Next();
    }
    
    // This block handles the cases where our clipboard is smaller
    // than the amount of selected destination tracks. We take the 
    // last wave track, and paste that one into the remaining
    // selected tracks.
-   if ( n && !c ){
-      WaveTrack *tmp;
+   if ( n && !c )
+   {
       bool foundSrcTrack = false;
       c = clipIter.Last();
+
       // First, we find the last audio track. This is the track 
       // we'll be pasting into the excess selected tracks.
       if (c->GetKind() != Track::Wave){
@@ -3482,16 +3538,34 @@
       while (n){
          if (n->GetSelected() && n->GetKind()==Track::Wave){
             if (c && c->GetKind() == Track::Wave){
-               ((WaveTrack *)n)->HandleClear(t0, t1, false, false);
-               ((WaveTrack *)n)->HandlePaste(t0, (WaveTrack *)c);
+               pastedSomething = ((WaveTrack *)n)->ClearAndPaste(t0, t1,
+                     (WaveTrack *)c, true, true, NULL, false, !firstInGroup);
+               firstInGroup = firstInGroup && !pastedSomething;
             }else{
+               WaveTrack *tmp;
                tmp = mTrackFactory->NewWaveTrack( 
((WaveTrack*)n)->GetSampleFormat(), ((WaveTrack*)n)->GetRate());
-               tmp->InsertSilence(0.0, srcLength);
+               tmp->InsertSilence(0.0, msClipLen);
                tmp->Flush();
-               ((WaveTrack *)n)->HandlePaste(t0, tmp);
+
+               pastedSomething = ((WaveTrack *)n)->ClearAndPaste(t0, t1,
+                     tmp, true, true, NULL, false, !firstInGroup);
+               firstInGroup = firstInGroup && !pastedSomething;
+
                delete tmp;
             }
          }
+         else if (n->GetSelected() && n->GetKind() == Track::Label)
+         {
+            // Make room in label tracks as necessary
+            if (IsSticky() && !firstInGroup)
+            {
+               ((LabelTrack *)n)->ShiftLabelsOnClear(t0, t1);
+               ((LabelTrack *)n)->ShiftLabelsOnInsert(msClipLen, t0);
+            }
+         }
+
+         if (n && n->GetKind() == Track::Label)
+            firstInGroup = true;
          n = iter.Next();
       }
    }
@@ -3673,15 +3747,22 @@
 {
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
+
+  // Set the system clipboard
+  CopyLabelTracksText();
  
+  // Because of grouping the copy may need to operate on different tracks than
+  // the clear, so we do these actions separately.
+  EditClipboardByLabel( &WaveTrack::Copy );
+
   if( gPrefs->Read( wxT( "/GUI/EnableCutLines" ), ( long )0 ) )
-     EditClipboardByLabel( &WaveTrack::CutAndAddCutLine );
+     EditByLabel( &WaveTrack::ClearAndAddCutLine, true );
   else
-     EditClipboardByLabel( &WaveTrack::Cut );
+     EditByLabel( &WaveTrack::Clear, true );
   
   msClipProject = this;
 
-  mViewInfo.sel1 = mViewInfo.sel0 = 0.0;
+  mViewInfo.sel1 = mViewInfo.sel0;
   
   PushState( _( "Cut labeled regions to the clipboard" ), _( "Cut Labels" ) );
 
@@ -3693,6 +3774,9 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
 
+  // Set the system clipboard
+  CopyLabelTracksText();
+
   EditClipboardByLabel( &WaveTrack::SplitCut );
   
   msClipProject = this;
@@ -3708,6 +3792,9 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
 
+  // Set the system clipboard
+  CopyLabelTracksText();
+
   EditClipboardByLabel( &WaveTrack::Copy );
   
   msClipProject = this;
@@ -3722,7 +3809,9 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
   
-  EditByLabel( &WaveTrack::Clear );
+  EditByLabel( &WaveTrack::Clear, true );
+
+  mViewInfo.sel1 = mViewInfo.sel0;
   
   PushState( _( "Deleted labeled regions" ), _( "Delete Labels" ) );
 
@@ -3734,7 +3823,7 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
   
-  EditByLabel( &WaveTrack::SplitDelete );
+  EditByLabel( &WaveTrack::SplitDelete, false );
   
   PushState( _( "Split Deleted labeled regions" ), _( "Split Delete Labels" ) 
);
 
@@ -3746,7 +3835,7 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
   
-  EditByLabel( &WaveTrack::Silence );
+  EditByLabel( &WaveTrack::Silence, false );
   
   PushState( _( "Silenced labeled regions" ), _( "Silence Labels" ) );
 
@@ -3755,10 +3844,7 @@
 
 void AudacityProject::OnSplitLabels()
 {
-  if( mViewInfo.sel0 >= mViewInfo.sel1 )
-     return;
-  
-  EditByLabel( &WaveTrack::Split );
+  EditByLabel( &WaveTrack::Split, false );
   
   PushState( _( "Split labeled regions" ), _( "Split Labels" ) );
 
@@ -3770,7 +3856,7 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
   
-  EditByLabel( &WaveTrack::Join );
+  EditByLabel( &WaveTrack::Join, false );
   
   PushState( _( "Joined labeled regions" ), _( "Join Labels" ) );
 
@@ -3782,7 +3868,7 @@
   if( mViewInfo.sel0 >= mViewInfo.sel1 )
      return;
   
-  EditByLabel( &WaveTrack::Disjoin );
+  EditByLabel( &WaveTrack::Disjoin, false );
   
   PushState( _( "Detached labeled regions" ), _( "Detach Labels" ) );
 

--- NEW FILE: CaptureEvents.cpp ---
/**********************************************************************

   Audacity: A Digital Audio Editor
   Audacity(R) is copyright (c) 1999-2008 Audacity Team.
   License: GPL v2.  See License.txt.

   CaptureEvents.h
   Created by Al Dimond, Oct. 2009 (from code by someone else)

******************************************************************//**

\class CaptureEvents
\brief RAII-style class to work around a bug in wxGTK 2.8.9-?

*//*******************************************************************/

#include "Audacity.h"
#include "CaptureEvents.h"

#if defined(__WXGTK__) && defined(HAVE_GTK)
// As of wxGTK 2.8.9, there is a problem in the wxClipboard class that
// allows recursive event processing.  This problem has been corrected
// by wxWidgets 2.9+.  However, this han't made it into a release yet,
// so we have to work around it.
//
// This is done by pulling/merging in some code from wx29 and creating
// the following class to capture events while accessing the clipboard
// to prevent the asynchronous clipboard access from causing recursive
// event processing.

#include <wx/app.h>
#include <wx/dynarray.h>
#include <wx/log.h>
#include <gtk/gtk.h>

extern GtkWidget *wxGetRootWindow();

static void main_do_event(GdkEvent *event, wxArrayPtrVoid *queue)
{
   switch (event->type)
   {
      case GDK_NOTHING:
         // Ignore it
      break;

      case GDK_SELECTION_REQUEST:
      case GDK_SELECTION_NOTIFY:
      case GDK_SELECTION_CLEAR:
#if GTK_CHECK_VERSION(2,6,0)
      case GDK_OWNER_CHANGE:
#endif
         // process it now
         gtk_main_do_event(event);
      break;

      default:
         // process it later (but make a copy; the caller will free the event 
pointer)
         queue->Add(gdk_event_copy(event));
      break;
   }

   // don't allow idle callbacks while we're active
   wxTheApp->SuspendIdleCallback();

   return;
}

CaptureEvents::CaptureEvents()
{
#if wxUSE_LOG
   // disable log flushing from here because a call to wxYield() shouldn't
   // normally result in message boxes popping up &c
   wxLog::Suspend();
#endif

   // temporarily replace the global GDK event handler with our function
   gdk_event_handler_set((GdkEventFunc)main_do_event, &queue, NULL);

   // temporarily suspend idle callbacks
   wxTheApp->SuspendIdleCallback();
}

CaptureEvents::~CaptureEvents()
{
   gdk_event_handler_set((GdkEventFunc)gtk_main_do_event, NULL, NULL);

   // put all unprocessed GDK events back in the queue
   GdkDisplay* disp = gtk_widget_get_display(wxGetRootWindow());
   size_t cnt = queue.GetCount();
   for (size_t i = 0; i < cnt; i++) {
      GdkEvent* event = (GdkEvent*)queue[i];
      // NOTE: gdk_display_put_event makes a copy of the event passed to it
      gdk_display_put_event(disp, event);
      gdk_event_free(event);
   }

#if wxUSE_LOG
   // let the logs be flashed again
   wxLog::Resume();
#endif
}


#endif


Index: Project.cpp
===================================================================
RCS file: /cvsroot/audacity/audacity-src/src/Project.cpp,v
retrieving revision 1.464
retrieving revision 1.465
diff -u -d -r1.464 -r1.465
--- Project.cpp 20 Oct 2009 23:08:26 -0000      1.464
+++ Project.cpp 31 Oct 2009 15:24:22 -0000      1.465
@@ -154,6 +154,8 @@
 #include "commands/Command.h"
 #include "commands/CommandType.h"
 
+#include "CaptureEvents.h"
+
 using std::cout;
 
 TrackList *AudacityProject::msClipboard = new TrackList();
@@ -2306,6 +2308,39 @@
       while (t) {
          if (t->GetErrorOpening())
             err = true;
+
+         // Sanity checks for linked tracks; unsetting the linked property
+         // doesn't fix the problem, but it likely leaves us with orphaned
+         // blockfiles instead of much worse problems.
+         if (t->GetLinked())
+         {
+            Track *l = t->GetLink();
+            if (l)
+            {
+               // A linked track's partner should never itself be linked
+               if (l->GetLinked())
+               {
+                  err = true;
+                  t->SetLinked(false);
+               }
+               
+               // Channels should be left and right
+               if ( !(  (t->GetChannel() == Track::LeftChannel &&
+                           l->GetChannel() == Track::RightChannel) ||
+                        (t->GetChannel() == Track::RightChannel &&
+                           l->GetChannel() == Track::LeftChannel) ) )
+               {
+                  err = true;
+                  t->SetLinked(false);
+               }
+            }
+            else
+            {
+               err = true;
+               t->SetLinked(false);
+            }
+         }
+
          mLastSavedTracks->Add(t->Duplicate());
          t = iter.Next();
       }
@@ -3801,7 +3836,7 @@
    
    //determine labelled regions
    for( n = iter.First(); n; n = iter.Next() )
-      if( n->GetKind() == Track::Label )
+      if( n->GetKind() == Track::Label && n->GetSelected() )
       {
          LabelTrack *lt = ( LabelTrack* )n;
          for( int i = 0; i < lt->GetNumLabels(); i++ ) 
@@ -3843,7 +3878,10 @@
 //Executes the edit function on all selected wave tracks with
 //regions specified by selected labels
 //If No tracks selected, function is applied on all tracks
-void AudacityProject::EditByLabel( WaveTrack::EditFunction action )
+//If the function deletes audio, groupIteration should probably be set to true,
+// so it won't delete too many times.
+void AudacityProject::EditByLabel( WaveTrack::EditFunction action,
+                                   bool groupIteration )
 { 
    Regions regions;
    
@@ -3851,7 +3889,7 @@
    if( regions.GetCount() == 0 )
       return;
 
-   TrackListIterator iter( mTracks );
+   TrackAndGroupIterator iter( mTracks );
    Track *n;
    bool allTracks = true;
 
@@ -3867,13 +3905,27 @@
    //Apply action on wavetracks starting from
    //labeled regions in the end. This is to correctly perform
    //actions like 'Delete' which collapse the track area.
-   for( n = iter.First(); n; n = iter.Next() )
+   n = iter.First();
+   while (n)
+   {
       if( n->GetKind() == Track::Wave && ( allTracks || n->GetSelected() ) )
       {
          WaveTrack *wt = ( WaveTrack* )n;
          for( int i = ( int )regions.GetCount() - 1; i >= 0; i-- )
             ( wt->*action )( regions.Item( i )->start, regions.Item( i )->end 
);
+
+         // Tracks operated on may need group iteration
+         if (IsSticky() && groupIteration)
+            n = iter.NextGroup();
+         else
+            n = iter.Next();
       }
+      else
+      {
+         // Tracks not operated on need normal iteration
+         n = iter.Next();
+      }
+   }
 
    //delete label regions
    for( unsigned int i = 0; i < regions.GetCount(); i++ )
@@ -3883,7 +3935,9 @@
 //Executes the edit function on all selected wave tracks with
 //regions specified by selected labels
 //If No tracks selected, function is applied on all tracks
-//functions copy the edited regions to clipboard, possibly in multiple tracks
+//Functions copy the edited regions to clipboard, possibly in multiple tracks
+//This probably should not be called if *action() changes the timeline, because
+// the copy needs to happen by track, and the timeline change by group.
 void AudacityProject::EditClipboardByLabel( WaveTrack::EditDestFunction action 
)
 { 
    Regions regions;
@@ -4403,6 +4457,48 @@
    }
 }
 
+wxString AudacityProject::AllLabelsText(TrackList *l, double t0, double t1,
+                                        bool selectedOnly /* = false */)
+{
+   bool firstLabelTrack = true;
+   wxString retVal;
+   TrackListOfKindIterator iter(Track::Label, l);
+   // Clipboard functions don't do newline magic, so here's a lame workaround
+   wxString newline;
+#if defined(__WXMSW__)
+   newline = wxT("\r\n");  // On Windows systems this should be \x0d\x0a
+#else
+   newline = wxT("\n");    // This is \x0a most places, \x0d on old Macs
+#endif
+   
+   for (Track *t = iter.First(); t; t = iter.Next())
+   {
+      if (!selectedOnly || t->GetSelected())
+      {
+         if (!firstLabelTrack)
+            retVal += newline;
+         retVal += ((LabelTrack *)t)->GetTextOfLabels(t0, t1);
+         firstLabelTrack = false;
+      }
+   }
+
+   return retVal;
+}
+
+void AudacityProject::CopyLabelTracksText()
+{
+   wxString text = AllLabelsText(mTracks, mViewInfo.sel0, mViewInfo.sel1, 
true);
+
+   if (wxTheClipboard->Open())
+   {
+#if defined(__WXGTK__) && defined(HAVE_GTK)
+      CaptureEvents capture;
+#endif
+      wxTheClipboard->SetData(new wxTextDataObject(text));
+      wxTheClipboard->Close();
+   }
+}
+
 // Indentation settings for Vim and Emacs and unique identifier for Arch, a
 // version control system. Please do not modify past this point.
 //


------------------------------------------------------------------------------
Come build with us! The BlackBerry(R) Developer Conference in SF, CA
is the only developer event you need to attend this year. Jumpstart your
developing skills, take BlackBerry mobile applications to market and stay 
ahead of the curve. Join us from November 9 - 12, 2009. Register now!
http://p.sf.net/sfu/devconference
_______________________________________________
Audacity-cvs mailing list
Audacity-cvs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/audacity-cvs

Reply via email to