Ticket #8901: cutlist_undo_stack_v7.patch

File cutlist_undo_stack_v7.patch, 21.9 KB (added by Jim Stichnoth <stichnot@…>, 9 years ago)
  • mythtv/libs/libmyth/programinfo.cpp

    diff --git a/mythtv/libs/libmyth/programinfo.cpp b/mythtv/libs/libmyth/programinfo.cpp
    index 01b81a3..b126012 100644
    a b AutoExpireType ProgramInfo::QueryAutoExpire(void) const 
    26952695    return kDisableAutoExpire;
    26962696}
    26972697
    2698 void ProgramInfo::QueryCutList(frm_dir_map_t &delMap) const
     2698bool ProgramInfo::QueryCutList(frm_dir_map_t &delMap, bool loadAutoSave) const
    26992699{
    2700     QueryMarkupMap(delMap, MARK_CUT_START);
    2701     QueryMarkupMap(delMap, MARK_CUT_END, true);
     2700    frm_dir_map_t autosaveMap;
     2701    QueryMarkupMap(autosaveMap, MARK_TMP_CUT_START);
     2702    QueryMarkupMap(autosaveMap, MARK_TMP_CUT_END, true);
     2703    QueryMarkupMap(autosaveMap, MARK_PLACEHOLDER, true);
     2704    bool result = !autosaveMap.isEmpty();
     2705
     2706    if (loadAutoSave)
     2707    {
     2708        // Convert the temporary marks into regular marks.
     2709        delMap.clear();
     2710        frm_dir_map_t::const_iterator i = autosaveMap.constBegin();
     2711        for (; i != autosaveMap.constEnd(); ++i)
     2712        {
     2713            uint64_t frame = i.key();
     2714            MarkTypes mark = i.value();
     2715            if (mark == MARK_TMP_CUT_START)
     2716                mark = MARK_CUT_START;
     2717            else if (mark == MARK_TMP_CUT_END)
     2718                mark = MARK_CUT_END;
     2719            delMap[frame] = mark;
     2720        }
     2721    }
     2722    else
     2723    {
     2724        QueryMarkupMap(delMap, MARK_CUT_START);
     2725        QueryMarkupMap(delMap, MARK_CUT_END, true);
     2726        QueryMarkupMap(delMap, MARK_PLACEHOLDER, true);
     2727    }
     2728
     2729    return result;
    27022730}
    27032731
    2704 void ProgramInfo::SaveCutList(frm_dir_map_t &delMap) const
     2732void ProgramInfo::SaveCutList(frm_dir_map_t &delMap, bool isAutoSave) const
    27052733{
    2706     ClearMarkupMap(MARK_CUT_START);
    2707     ClearMarkupMap(MARK_CUT_END);
     2734    if (!isAutoSave)
     2735    {
     2736        ClearMarkupMap(MARK_CUT_START);
     2737        ClearMarkupMap(MARK_CUT_END);
     2738    }
    27082739    ClearMarkupMap(MARK_PLACEHOLDER);
    2709     SaveMarkupMap(delMap);
     2740    ClearMarkupMap(MARK_TMP_CUT_START);
     2741    ClearMarkupMap(MARK_TMP_CUT_END);
     2742
     2743    frm_dir_map_t tmpDelMap;
     2744    frm_dir_map_t::const_iterator i = delMap.constBegin();
     2745    for (; i != delMap.constEnd(); ++i)
     2746    {
     2747        uint64_t frame = i.key();
     2748        MarkTypes mark = i.value();
     2749        if (isAutoSave)
     2750        {
     2751            if (mark == MARK_CUT_START)
     2752                mark = MARK_TMP_CUT_START;
     2753            else if (mark == MARK_CUT_END)
     2754                mark = MARK_TMP_CUT_END;
     2755        }
     2756        tmpDelMap[frame] = mark;
     2757    }
     2758    SaveMarkupMap(tmpDelMap);
    27102759
    27112760    if (IsRecording())
    27122761    {
  • mythtv/libs/libmyth/programinfo.h

    diff --git a/mythtv/libs/libmyth/programinfo.h b/mythtv/libs/libmyth/programinfo.h
    index 60934ec..cf7e908 100644
    a b class MPUBLIC ProgramInfo 
    534534                           bool forceCheckLocal = false) const;
    535535
    536536    // Edit flagging map
    537     void QueryCutList(frm_dir_map_t &) const;
    538     void SaveCutList(frm_dir_map_t &) const;
     537    bool QueryCutList(frm_dir_map_t &, bool loadAutosave=false) const;
     538    void SaveCutList(frm_dir_map_t &, bool isAutoSave=false) const;
    539539
    540540    // Commercial flagging map
    541541    void QueryCommBreakList(frm_dir_map_t &) const;
  • mythtv/libs/libmyth/programtypes.cpp

    diff --git a/mythtv/libs/libmyth/programtypes.cpp b/mythtv/libs/libmyth/programtypes.cpp
    index 019655c..f38643a 100644
    a b QString toString(MarkTypes type) 
    2222    switch (type)
    2323    {
    2424        case MARK_UNSET:        return "UNSET";
     25        case MARK_TMP_CUT_END:  return "TMP_CUT_END";
     26        case MARK_TMP_CUT_START:return "TMP_CUT_START";
    2527        case MARK_UPDATED_CUT:  return "UPDATED_CUT";
    2628        case MARK_PLACEHOLDER:  return "PLACEHOLDER";
    2729        case MARK_CUT_END:      return "CUT_END";
  • mythtv/libs/libmyth/programtypes.h

    diff --git a/mythtv/libs/libmyth/programtypes.h b/mythtv/libs/libmyth/programtypes.h
    index 23e1bf6..64c386e 100644
    a b typedef QMap<uint64_t, uint64_t> frm_pos_map_t; 
    4040typedef enum {
    4141    MARK_ALL           = -100,
    4242    MARK_UNSET         = -10,
     43    MARK_TMP_CUT_END   = -5,
     44    MARK_TMP_CUT_START = -4,
    4345    MARK_UPDATED_CUT   = -3,
    4446    MARK_PLACEHOLDER   = -2,
    4547    MARK_CUT_END       = 0,
  • mythtv/libs/libmythtv/deletemap.cpp

    diff --git a/mythtv/libs/libmythtv/deletemap.cpp b/mythtv/libs/libmythtv/deletemap.cpp
    index 05d2228..4695502 100644
    a b  
    1010#define EDIT_CHECK if(!m_editing) \
    1111  { VERBOSE(VB_IMPORTANT, LOC_ERR + "Cannot edit outside editmode."); return; }
    1212
     13DeleteMapUndoEntry::DeleteMapUndoEntry(frm_dir_map_t dm, QString msg) :
     14    deleteMap(dm), message(msg) { }
     15
     16DeleteMapUndoEntry::DeleteMapUndoEntry(void)
     17{
     18    frm_dir_map_t dm;
     19    deleteMap = dm;
     20    message = "";
     21}
     22
     23void DeleteMap::Push(QString undoMessage)
     24{
     25    DeleteMapUndoEntry entry(m_deleteMap, undoMessage);
     26    // Remove all "redo" entries
     27    while (m_undoStack.size() > m_undoStackPointer + 1)
     28        m_undoStack.pop_back();
     29    m_undoStack.append(entry);
     30    m_undoStackPointer ++;
     31    SaveMap(0, m_ctx, true);
     32}
     33
     34bool DeleteMap::Undo(void)
     35{
     36    if (!HasUndo())
     37        return false;
     38    m_undoStackPointer --;
     39    m_deleteMap = m_undoStack[m_undoStackPointer].deleteMap;
     40    m_changed = true;
     41    SaveMap(0, m_ctx, true);
     42    return true;
     43}
     44
     45bool DeleteMap::Redo(void)
     46{
     47    if (!HasRedo())
     48        return false;
     49    m_undoStackPointer ++;
     50    m_deleteMap = m_undoStack[m_undoStackPointer].deleteMap;
     51    m_changed = true;
     52    SaveMap(0, m_ctx, true);
     53    return true;
     54}
     55
     56QString DeleteMap::GetUndoMessage(void)
     57{
     58    return (HasUndo() ? m_undoStack[m_undoStackPointer].message :
     59            QObject::tr("(No more undo operations)"));
     60}
     61
     62QString DeleteMap::GetRedoMessage(void)
     63{
     64    return (HasRedo() ? m_undoStack[m_undoStackPointer + 1].message :
     65            QObject::tr("(No more redo operations)"));
     66}
     67
    1368bool DeleteMap::HandleAction(QString &action, uint64_t frame,
    1469                             uint64_t played, uint64_t total, double rate)
    1570{
    bool DeleteMap::HandleAction(QString &action, uint64_t frame, 
    2176    else if (action == ACTION_DOWN)
    2277        UpdateSeekAmount(-1, rate);
    2378    else if (action == ACTION_CLEARMAP)
    24         Clear();
     79        Clear(QObject::tr("Clear Cut List"));
    2580    else if (action == ACTION_INVERTMAP)
    2681        ReverseAll(total);
    2782    else if (action == "MOVEPREV")
    bool DeleteMap::HandleAction(QString &action, uint64_t frame, 
    2984    else if (action == "MOVENEXT")
    3085        MoveRelative(frame, total, true);
    3186    else if (action == "CUTTOBEGINNING")
    32         Add(frame, total, MARK_CUT_END);
     87        Add(frame, total, MARK_CUT_END, QObject::tr("Cut To Beginning"));
    3388    else if (action == "CUTTOEND")
    34         Add(frame, total, MARK_CUT_START);
     89        Add(frame, total, MARK_CUT_START, QObject::tr("Cut To End"));
    3590    else if (action == "NEWCUT")
    3691        NewCut(frame, total);
    3792    else if (action == "DELETE")
    38         Delete(frame, total);
     93        Delete(frame, total, QObject::tr("Delete Cut Area"));
     94    else if (action == "UNDO")
     95        Undo();
     96    else if (action == "REDO")
     97        Redo();
    3998    else
    4099        handled = false;
    41100    return handled;
    bool DeleteMap::IsEmpty(void) 
    150209}
    151210
    152211/// Clears the deleteMap.
    153 void DeleteMap::Clear(void)
     212void DeleteMap::Clear(QString undoMessage)
    154213{
    155214    m_deleteMap.clear();
    156215    m_changed = true;
     216    if (!undoMessage.isEmpty())
     217        Push(undoMessage);
    157218}
    158219
    159220/// Reverses the direction of each mark in the map.
    void DeleteMap::ReverseAll(uint64_t total) 
    165226        Add(it.key(), it.value() == MARK_CUT_END ? MARK_CUT_START :
    166227                                                   MARK_CUT_END);
    167228    CleanMap(total);
     229    Push(QObject::tr("Invert Cut List"));
    168230}
    169231
    170232/**
    void DeleteMap::ReverseAll(uint64_t total) 
    172234 *        existing redundant mark of that type is removed. This simplifies
    173235 *        the cleanup code.
    174236 */
    175 void DeleteMap::Add(uint64_t frame, uint64_t total, MarkTypes type)
     237void DeleteMap::Add(uint64_t frame, uint64_t total, MarkTypes type,
     238                    QString undoMessage)
    176239{
    177240    EDIT_CHECK
    178241    if ((MARK_CUT_START != type) && (MARK_CUT_END != type) &&
    void DeleteMap::Add(uint64_t frame, uint64_t total, MarkTypes type) 
    186249        {
    187250            // Delete the temporary mark before putting a real mark at its
    188251            // location
    189             Delete(frame, total);
     252            Delete(frame, total, "");
    190253        }
    191254        else // Don't add a mark on top of a mark
    192255            return;
    void DeleteMap::Add(uint64_t frame, uint64_t total, MarkTypes type) 
    241304        Delete((uint64_t)remove);
    242305    Add(frame, type);
    243306    CleanMap(total);
     307    if (!undoMessage.isEmpty())
     308        Push(undoMessage);
    244309}
    245310
    246311/// Remove the mark at the given frame.
    247 void DeleteMap::Delete(uint64_t frame, uint64_t total)
     312void DeleteMap::Delete(uint64_t frame, uint64_t total, QString undoMessage)
    248313{
    249314    EDIT_CHECK
    250315    if (m_deleteMap.isEmpty())
    void DeleteMap::Delete(uint64_t frame, uint64_t total) 
    271336    if (prev != next)
    272337        Delete(next);
    273338    CleanMap(total);
     339    if (!undoMessage.isEmpty())
     340        Push(undoMessage);
    274341}
    275342
    276343/// Reverse the direction of the mark at the given frame.
    void DeleteMap::Reverse(uint64_t frame, uint64_t total) 
    278345{
    279346    EDIT_CHECK
    280347    int type = Delete(frame);
    281     Add(frame, total, type == MARK_CUT_END ? MARK_CUT_START : MARK_CUT_END);
     348    Add(frame, total, type == MARK_CUT_END ? MARK_CUT_START : MARK_CUT_END, "");
     349    Push(QObject::tr("Reverse Mark Direction"));
    282350}
    283351
    284352/// Add a new cut marker (to start or end a cut region)
    void DeleteMap::NewCut(uint64_t frame, uint64_t total) 
    376444        Add(frame, MARK_PLACEHOLDER);
    377445
    378446    CleanMap(total);
     447    Push(QObject::tr("New Cut"));
    379448}
    380449
    381450/// Move the previous (!right) or next (right) cut to frame.
    void DeleteMap::MoveRelative(uint64_t frame, uint64_t total, bool right) 
    397466        {
    398467            // If on a mark, don't collapse a cut region to 0;
    399468            // instead, delete the region
    400             Delete(frame, total);
     469            Delete(frame, total, QObject::tr("Delete Cut Area"));
    401470            return;
    402471        }
    403472        else if (MARK_PLACEHOLDER == type)
    404473        {
    405474            // Delete the temporary mark before putting a real mark at its
    406475            // location
    407             Delete(frame, total);
     476            Delete(frame, total, "");
    408477        }
    409478    }
    410479
    void DeleteMap::Move(uint64_t frame, uint64_t to, uint64_t total) 
    424493        else if (frame == total)
    425494            type = MARK_CUT_END;
    426495    }
    427     Add(to, total, type);
     496    Add(to, total, type, QObject::tr("Move Mark"));
    428497}
    429498
    430499/// Private addition to the deleteMap.
    void DeleteMap::SetMap(const frm_dir_map_t &map) 
    586655    Clear();
    587656    m_deleteMap = map;
    588657    m_deleteMap.detach();
     658    Push(QObject::tr("Set New Cut List"));
    589659}
    590660
    591661/// Loads the given commercial break map into the deleteMap.
    void DeleteMap::LoadCommBreakMap(uint64_t total, frm_dir_map_t &map) 
    597667        Add(it.key(), it.value() == MARK_COMM_START ?
    598668                MARK_CUT_START : MARK_CUT_END);
    599669    CleanMap(total);
     670    Push(QObject::tr("Load Commskip List"));
    600671}
    601672
    602673/// Loads the delete map from the database.
    603 void DeleteMap::LoadMap(uint64_t total, PlayerContext *ctx)
     674void DeleteMap::LoadMap(uint64_t total, PlayerContext *ctx, QString undoMessage)
    604675{
    605676    if (!ctx || !ctx->playingInfo || gCoreContext->IsDatabaseIgnored())
    606677        return;
    void DeleteMap::LoadMap(uint64_t total, PlayerContext *ctx) 
    610681    ctx->playingInfo->QueryCutList(m_deleteMap);
    611682    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    612683    CleanMap(total);
     684    if (!undoMessage.isEmpty())
     685        Push(undoMessage);
     686}
     687
     688/// Returns true if an auto-save map was loaded.
     689/// Does nothing and returns false if not.
     690bool DeleteMap::LoadAutoSaveMap(uint64_t total, PlayerContext *ctx)
     691{
     692    if (!ctx || !ctx->playingInfo || gCoreContext->IsDatabaseIgnored())
     693        return false;
     694
     695    frm_dir_map_t tmpDeleteMap = m_deleteMap;
     696    Clear();
     697    ctx->LockPlayingInfo(__FILE__, __LINE__);
     698    bool result = ctx->playingInfo->QueryCutList(m_deleteMap, true);
     699    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     700    CleanMap(total);
     701    if (result)
     702        Push(QObject::tr("Load Auto-Save Cut List"));
     703    else
     704        m_deleteMap = tmpDeleteMap;
     705
     706    return result;
    613707}
    614708
    615709/// Saves the delete map to the database.
    616 void DeleteMap::SaveMap(uint64_t total, PlayerContext *ctx)
     710void DeleteMap::SaveMap(uint64_t total, PlayerContext *ctx, bool isAutoSave)
    617711{
    618712    if (!ctx || !ctx->playingInfo || gCoreContext->IsDatabaseIgnored())
    619713        return;
    620714
     715    if (!isAutoSave)
     716    {
    621717    // Remove temporary placeholder marks
    622718    QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap);
    623719    while (it.hasNext())
    void DeleteMap::SaveMap(uint64_t total, PlayerContext *ctx) 
    631727    }
    632728
    633729    CleanMap(total);
     730    }
    634731    ctx->LockPlayingInfo(__FILE__, __LINE__);
    635732    ctx->playingInfo->SaveMarkupFlag(MARK_UPDATED_CUT);
    636     ctx->playingInfo->SaveCutList(m_deleteMap);
     733    ctx->playingInfo->SaveCutList(m_deleteMap, isAutoSave);
    637734    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    638735}
    639736
  • mythtv/libs/libmythtv/deletemap.h

    diff --git a/mythtv/libs/libmythtv/deletemap.h b/mythtv/libs/libmythtv/deletemap.h
    index e6a599b..1253014 100644
    a b  
    44#include "programinfo.h"
    55#include "playercontext.h"
    66
     7class DeleteMap;
     8
     9typedef struct DeleteMapUndoEntry
     10{
     11    frm_dir_map_t deleteMap;
     12    QString message; // how we got from previous map to this map
     13    DeleteMapUndoEntry(frm_dir_map_t dm, QString msg);
     14    DeleteMapUndoEntry(void);
     15} DeleteMapUndoEntry;
     16
    717class DeleteMap
    818{
    919  public:
    1020    DeleteMap(): m_editing(false),   m_nextCutStart(0), m_changed(true),
    11                  m_seekamountpos(4), m_seekamount(30) { }
     21                 m_seekamountpos(4), m_seekamount(30),
     22                 m_ctx(0), m_undoStackPointer(-1) { Push(""); }
    1223
     24    void SetPlayerContext(PlayerContext *ctx) { m_ctx = ctx; }
    1325    bool HandleAction(QString &action, uint64_t frame, uint64_t played,
    1426                      uint64_t total, double rate);
    1527    int  GetSeekAmount(void) { return m_seekamount; }
    class DeleteMap 
    2840
    2941    void SetMap(const frm_dir_map_t &map);
    3042    void LoadCommBreakMap(uint64_t total, frm_dir_map_t &map);
    31     void SaveMap(uint64_t total, PlayerContext *ctx);
    32     void LoadMap(uint64_t total, PlayerContext *ctx);
     43    void SaveMap(uint64_t total, PlayerContext *ctx, bool isAutoSave=false);
     44    void LoadMap(uint64_t total, PlayerContext *ctx, QString undoMessage="");
     45    bool LoadAutoSaveMap(uint64_t total, PlayerContext *ctx);
    3346    void CleanMap(uint64_t total);
    3447
    35     void Clear(void);
     48    void Clear(QString undoMessage="");
    3649    void ReverseAll(uint64_t total);
    37     void Add(uint64_t frame, uint64_t total, MarkTypes type);
     50    void Add(uint64_t frame, uint64_t total, MarkTypes type,
     51             QString undoMessage);
    3852    void NewCut(uint64_t frame, uint64_t total);
    39     void Delete(uint64_t frame, uint64_t total);
     53    void Delete(uint64_t frame, uint64_t total, QString undoMessage);
    4054    void Reverse(uint64_t frame, uint64_t total);
    4155    void MoveRelative(uint64_t frame, uint64_t total, bool right);
    4256    void Move(uint64_t frame, uint64_t to, uint64_t total);
    class DeleteMap 
    5064    void TrackerReset(uint64_t frame, uint64_t total);
    5165    bool TrackerWantsToJump(uint64_t frame, uint64_t total, uint64_t &to);
    5266
     67    bool Undo(void);
     68    bool Redo(void);
     69    bool HasUndo(void) { return m_undoStackPointer > 0; }
     70    bool HasRedo(void) { return m_undoStackPointer < m_undoStack.size() - 1; }
     71    QString GetUndoMessage(void);
     72    QString GetRedoMessage(void);
     73
    5374  private:
    5475    void Add(uint64_t frame, MarkTypes type);
    5576    MarkTypes Delete(uint64_t frame);
    5677
     78    void Push(QString undoMessage);
     79
    5780    bool          m_editing;
    5881    uint64_t      m_nextCutStart;
    5982    frm_dir_map_t m_deleteMap;
    class DeleteMap 
    6184    bool          m_changed;
    6285    int           m_seekamountpos;
    6386    int           m_seekamount;
     87    PlayerContext *m_ctx;
     88
     89    // Invariant: m_undoStack[m_undoStackPointer].deleteMap == m_deleteMap
     90    QVector<DeleteMapUndoEntry> m_undoStack;
     91    int m_undoStackPointer;
    6492};
    6593
    6694#endif // DELETEMAP_H
  • mythtv/libs/libmythtv/mythplayer.cpp

    diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
    index 4997bed..8750ae3 100644
    a b void MythPlayer::ClearAfterSeek(bool clearvideobuffers) 
    35293529void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget,
    35303530                               bool frame_exact_seek, PlayerContext *ctx)
    35313531{
     3532    deleteMap.SetPlayerContext(ctx);
    35323533    m_tv = tv;
    35333534    parentWidget = widget;
    35343535    exactseeks   = frame_exact_seek;
    bool MythPlayer::EnableEdit(void) 
    35603561    osd->DialogQuit();
    35613562    ResetCaptions();
    35623563    osd->HideAll();
     3564
     3565    bool loadedAutoSave = deleteMap.LoadAutoSaveMap(totalFrames, player_ctx);
     3566    if (loadedAutoSave)
     3567    {
     3568        SetOSDMessage(QObject::tr("Using previously auto-saved cut list"),
     3569                      kOSDTimeout_Short);
     3570    }
     3571
    35633572    deleteMap.UpdateSeekAmount(0, video_frame_rate);
    35643573    deleteMap.UpdateOSD(framesPlayed, totalFrames, video_frame_rate,
    35653574                        player_ctx, osd);
    void MythPlayer::DisableEdit(bool save) 
    35803589        return;
    35813590
    35823591    deleteMap.SetEditing(false, osd);
    3583     if (save)
    3584         deleteMap.SaveMap(totalFrames, player_ctx);
    3585     else
     3592    if (!save)
    35863593        deleteMap.LoadMap(totalFrames, player_ctx);
     3594    // Unconditionally save to remove temporary marks from the DB.
     3595    deleteMap.SaveMap(totalFrames, player_ctx);
    35873596    deleteMap.TrackerReset(framesPlayed, totalFrames);
    35883597    deleteMap.SetFileEditing(player_ctx, false);
    35893598    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    bool MythPlayer::HandleProgramEditorActions(QStringList &actions, 
    36783687        }
    36793688        else if (action == "DELETE")
    36803689        {
    3681             deleteMap.Delete(frame, totalFrames);
     3690            deleteMap.Delete(frame, totalFrames,
     3691                             QObject::tr("Delete cut area"));
    36823692            refresh = true;
    36833693        }
    36843694        else if (action == "REVERT")
    36853695        {
    3686             deleteMap.LoadMap(totalFrames, player_ctx);
     3696            deleteMap.LoadMap(totalFrames, player_ctx,
     3697                              QObject::tr("Load Cut List"));
    36873698            refresh = true;
    36883699        }
    36893700        else if (action == "REVERTEXIT")
    bool MythPlayer::HandleProgramEditorActions(QStringList &actions, 
    37033714        }
    37043715        else
    37053716        {
     3717            QString undoMessage = deleteMap.GetUndoMessage();
     3718            QString redoMessage = deleteMap.GetRedoMessage();
    37063719            handled = deleteMap.HandleAction(action, frame, framesPlayed,
    37073720                                             totalFrames, video_frame_rate);
    37083721            if (handled && (action == "CUTTOBEGINNING" ||
    bool MythPlayer::HandleProgramEditorActions(QStringList &actions, 
    37103723            {
    37113724                SetOSDMessage(QObject::tr("New cut added."), kOSDTimeout_Short);
    37123725            }
     3726            else if (handled && action == "UNDO")
     3727            {
     3728                SetOSDMessage(QObject::tr("Undo") + " - " + undoMessage,
     3729                              kOSDTimeout_Short);
     3730            }
     3731            else if (handled && action == "REDO")
     3732            {
     3733                SetOSDMessage(QObject::tr("Redo") + " - " + redoMessage,
     3734                              kOSDTimeout_Short);
     3735            }
    37133736        }
    37143737    }
    37153738
  • mythtv/libs/libmythtv/mythplayer.h

    diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
    index b454aa2..543811b 100644
    a b class MPUBLIC MythPlayer 
    397397    bool IsTemporaryMark(uint64_t frame);
    398398    bool HasTemporaryMark(void);
    399399    bool IsCutListSaved(PlayerContext *ctx) { return deleteMap.IsSaved(ctx); }
     400    bool DeleteMapHasUndo(void) { return deleteMap.HasUndo(); }
     401    bool DeleteMapHasRedo(void) { return deleteMap.HasRedo(); }
     402    QString DeleteMapGetUndoMessage(void) { return deleteMap.GetUndoMessage(); }
     403    QString DeleteMapGetRedoMessage(void) { return deleteMap.GetRedoMessage(); }
    400404
    401405    // Reinit
    402406    void ReinitOSD(void);
  • mythtv/libs/libmythtv/tv_play.cpp

    diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp
    index 5e6945c..0cf8530 100644
    a b void TV::InitKeys(void) 
    723723            "Jump back 10x the normal amount"), ",,<");
    724724    REG_KEY("TV Editing", ACTION_BIGJUMPFWD,  QT_TRANSLATE_NOOP("MythControls",
    725725            "Jump forward 10x the normal amount"), ">,.");
     726    REG_KEY("TV Editing", "UNDO",        QT_TRANSLATE_NOOP("MythControls",
     727            "Undo"), "Ctrl+Z");
     728    REG_KEY("TV Editing", "REDO",        QT_TRANSLATE_NOOP("MythControls",
     729            "Redo"), "Ctrl+Y");
    726730
    727731    /* Teletext keys */
    728732    REG_KEY("Teletext Menu", ACTION_NEXTPAGE,    QT_TRANSLATE_NOOP("MythControls",
    void TV::ShowOSDCutpoint(PlayerContext *ctx, const QString &type) 
    89158919        if ("EDIT_CUT_POINTS" == type)
    89168920            osd->DialogAddButton(QObject::tr("Cut List Options"),
    89178921                                 "DIALOG_CUTPOINT_CUTLISTOPTIONS_0", true);
     8922        if (ctx->player->DeleteMapHasUndo())
     8923            osd->DialogAddButton(QObject::tr("Undo") + " - " +
     8924                                 ctx->player->DeleteMapGetUndoMessage(),
     8925                                 QString("DIALOG_CUTPOINT_UNDO_0"));
     8926        if (ctx->player->DeleteMapHasRedo())
     8927            osd->DialogAddButton(QObject::tr("Redo") + " - " +
     8928                                 ctx->player->DeleteMapGetRedoMessage(),
     8929                                 QString("DIALOG_CUTPOINT_REDO_0"));
    89188930    }
    89198931    else if ("CUT_LIST_OPTIONS" == type)
    89208932    {