Ticket #8901: cutlist_undo_stack_v6.patch

File cutlist_undo_stack_v6.patch, 20.8 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 2a3ea00..ebdfc37 100644
    a b AutoExpireType ProgramInfo::QueryAutoExpire(void) const 
    26872687    return kDisableAutoExpire;
    26882688}
    26892689
    2690 void ProgramInfo::QueryCutList(frm_dir_map_t &delMap) const
     2690bool ProgramInfo::QueryCutList(frm_dir_map_t &delMap, bool loadAutoSave) const
    26912691{
    2692     QueryMarkupMap(delMap, MARK_CUT_START);
    2693     QueryMarkupMap(delMap, MARK_CUT_END, true);
    2694     QueryMarkupMap(delMap, MARK_PLACEHOLDER, true);
     2692    frm_dir_map_t autosaveMap;
     2693    QueryMarkupMap(autosaveMap, MARK_TMP_CUT_START);
     2694    QueryMarkupMap(autosaveMap, MARK_TMP_CUT_END, true);
     2695    QueryMarkupMap(autosaveMap, MARK_PLACEHOLDER, true);
     2696    bool result = !autosaveMap.isEmpty();
     2697
     2698    if (loadAutoSave)
     2699    {
     2700        // Convert the temporary marks into regular marks.
     2701        delMap.clear();
     2702        frm_dir_map_t::const_iterator i = autosaveMap.constBegin();
     2703        for (; i != autosaveMap.constEnd(); ++i)
     2704        {
     2705            uint64_t frame = i.key();
     2706            MarkTypes mark = i.value();
     2707            if (mark == MARK_TMP_CUT_START)
     2708                mark = MARK_CUT_START;
     2709            else if (mark == MARK_TMP_CUT_END)
     2710                mark = MARK_CUT_END;
     2711            delMap[frame] = mark;
     2712        }
     2713    }
     2714    else
     2715    {
     2716        QueryMarkupMap(delMap, MARK_CUT_START);
     2717        QueryMarkupMap(delMap, MARK_CUT_END, true);
     2718        QueryMarkupMap(delMap, MARK_PLACEHOLDER, true);
     2719    }
     2720
     2721    return result;
    26952722}
    26962723
    2697 void ProgramInfo::SaveCutList(frm_dir_map_t &delMap) const
     2724void ProgramInfo::SaveCutList(frm_dir_map_t &delMap, bool isAutoSave) const
    26982725{
    2699     ClearMarkupMap(MARK_CUT_START);
    2700     ClearMarkupMap(MARK_CUT_END);
     2726    if (!isAutoSave)
     2727    {
     2728        ClearMarkupMap(MARK_CUT_START);
     2729        ClearMarkupMap(MARK_CUT_END);
     2730    }
    27012731    ClearMarkupMap(MARK_PLACEHOLDER);
    2702     SaveMarkupMap(delMap);
     2732    ClearMarkupMap(MARK_TMP_CUT_START);
     2733    ClearMarkupMap(MARK_TMP_CUT_END);
     2734
     2735    frm_dir_map_t tmpDelMap;
     2736    frm_dir_map_t::const_iterator i = delMap.constBegin();
     2737    for (; i != delMap.constEnd(); ++i)
     2738    {
     2739        uint64_t frame = i.key();
     2740        MarkTypes mark = i.value();
     2741        if (isAutoSave)
     2742        {
     2743            if (mark == MARK_CUT_START)
     2744                mark = MARK_TMP_CUT_START;
     2745            else if (mark == MARK_CUT_END)
     2746                mark = MARK_TMP_CUT_END;
     2747        }
     2748        tmpDelMap[frame] = mark;
     2749    }
     2750    SaveMarkupMap(tmpDelMap);
    27032751
    27042752    if (IsRecording())
    27052753    {
  • mythtv/libs/libmyth/programinfo.h

    diff --git a/mythtv/libs/libmyth/programinfo.h b/mythtv/libs/libmyth/programinfo.h
    index fb131bc..1c573d7 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 7cda7ac..3376d11 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 == "DOWN")
    2277        UpdateSeekAmount(-1, rate);
    2378    else if (action == "CLEARMAP")
    24         Clear();
     79        Clear(QObject::tr("Clear Cut List"));
    2580    else if (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) 
    582651    Clear();
    583652    m_deleteMap = map;
    584653    m_deleteMap.detach();
     654    Push(QObject::tr("Set New Cut List"));
    585655}
    586656
    587657/// Loads the given commercial break map into the deleteMap.
    void DeleteMap::LoadCommBreakMap(uint64_t total, frm_dir_map_t &map) 
    593663        Add(it.key(), it.value() == MARK_COMM_START ?
    594664                MARK_CUT_START : MARK_CUT_END);
    595665    CleanMap(total);
     666    Push(QObject::tr("Load Commskip List"));
    596667}
    597668
    598669/// Loads the delete map from the database.
    599 void DeleteMap::LoadMap(uint64_t total, PlayerContext *ctx)
     670void DeleteMap::LoadMap(uint64_t total, PlayerContext *ctx, QString undoMessage)
    600671{
    601672    if (!ctx || !ctx->playingInfo || gCoreContext->IsDatabaseIgnored())
    602673        return;
    void DeleteMap::LoadMap(uint64_t total, PlayerContext *ctx) 
    606677    ctx->playingInfo->QueryCutList(m_deleteMap);
    607678    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    608679    CleanMap(total);
     680    if (!undoMessage.isEmpty())
     681        Push(undoMessage);
     682}
     683
     684/// Returns true if an auto-save map was loaded.
     685/// Does nothing and returns false if not.
     686bool DeleteMap::LoadAutoSaveMap(uint64_t total, PlayerContext *ctx)
     687{
     688    if (!ctx || !ctx->playingInfo || gCoreContext->IsDatabaseIgnored())
     689        return false;
     690
     691    frm_dir_map_t tmpDeleteMap = m_deleteMap;
     692    Clear();
     693    ctx->LockPlayingInfo(__FILE__, __LINE__);
     694    bool result = ctx->playingInfo->QueryCutList(m_deleteMap, true);
     695    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
     696    CleanMap(total);
     697    if (result)
     698        Push(QObject::tr("Load Auto-Save Cut List"));
     699    else
     700        m_deleteMap = tmpDeleteMap;
     701
     702    return result;
    609703}
    610704
    611705/// Saves the delete map to the database.
    612 void DeleteMap::SaveMap(uint64_t total, PlayerContext *ctx)
     706void DeleteMap::SaveMap(uint64_t total, PlayerContext *ctx, bool isAutoSave)
    613707{
    614708    if (!ctx || !ctx->playingInfo || gCoreContext->IsDatabaseIgnored())
    615709        return;
    616710
     711    if (!isAutoSave)
     712    {
    617713    // Remove temporary placeholder marks
    618714    QMutableMapIterator<uint64_t, MarkTypes> it(m_deleteMap);
    619715    while (it.hasNext())
    void DeleteMap::SaveMap(uint64_t total, PlayerContext *ctx) 
    627723    }
    628724
    629725    CleanMap(total);
     726    }
    630727    ctx->LockPlayingInfo(__FILE__, __LINE__);
    631728    ctx->playingInfo->SaveMarkupFlag(MARK_UPDATED_CUT);
    632     ctx->playingInfo->SaveCutList(m_deleteMap);
     729    ctx->playingInfo->SaveCutList(m_deleteMap, isAutoSave);
    633730    ctx->UnlockPlayingInfo(__FILE__, __LINE__);
    634731}
    635732
  • 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 198e1fa..d6b6f75 100644
    a b void MythPlayer::ClearAfterSeek(bool clearvideobuffers) 
    34833483void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget,
    34843484                               bool frame_exact_seek, PlayerContext *ctx)
    34853485{
     3486    deleteMap.SetPlayerContext(ctx);
    34863487    m_tv = tv;
    34873488    parentWidget = widget;
    34883489    exactseeks   = frame_exact_seek;
    bool MythPlayer::EnableEdit(void) 
    35113512    osd->DialogQuit();
    35123513    ResetCaptions();
    35133514    osd->HideAll();
     3515
     3516    bool loadedAutoSave = deleteMap.LoadAutoSaveMap(totalFrames, player_ctx);
     3517    (void)loadedAutoSave; // XXX - should we display an OSD message?
     3518
    35143519    deleteMap.UpdateSeekAmount(0, video_frame_rate);
    35153520    deleteMap.UpdateOSD(framesPlayed, totalFrames, video_frame_rate,
    35163521                        player_ctx, osd);
    void MythPlayer::DisableEdit(bool save) 
    35283533{
    35293534    osdLock.lock();
    35303535    deleteMap.SetEditing(false, osd);
    3531     if (save)
    3532         deleteMap.SaveMap(totalFrames, player_ctx);
    3533     else
     3536    if (!save)
    35343537        deleteMap.LoadMap(totalFrames, player_ctx);
     3538    // Unconditionally save to remove temporary marks from the DB.
     3539    deleteMap.SaveMap(totalFrames, player_ctx);
    35353540    deleteMap.TrackerReset(framesPlayed, totalFrames);
    35363541    deleteMap.SetFileEditing(player_ctx, false);
    35373542    player_ctx->LockPlayingInfo(__FILE__, __LINE__);
    bool MythPlayer::HandleProgramEditorActions(QStringList &actions, 
    36283633        {
    36293634            if (IsInDelete(frame))
    36303635            {
    3631                 deleteMap.Delete(frame, totalFrames);
     3636                deleteMap.Delete(frame, totalFrames,
     3637                                 QObject::tr("Delete cut area"));
    36323638                refresh = true;
    36333639            }
    36343640        }
    36353641        else if (action == "REVERT")
    36363642        {
    3637             deleteMap.LoadMap(totalFrames, player_ctx);
     3643            deleteMap.LoadMap(totalFrames, player_ctx,
     3644                              QObject::tr("Load Cut List"));
    36383645            refresh = true;
    36393646        }
    36403647        else if (action == "REVERTEXIT")
  • mythtv/libs/libmythtv/mythplayer.h

    diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
    index b776296..8857c89 100644
    a b class MPUBLIC MythPlayer 
    412412    bool IsTemporaryMark(uint64_t frame);
    413413    bool HasTemporaryMark(void);
    414414    bool IsCutListSaved(PlayerContext *ctx) { return deleteMap.IsSaved(ctx); }
     415    bool DeleteMapHasUndo(void) { return deleteMap.HasUndo(); }
     416    bool DeleteMapHasRedo(void) { return deleteMap.HasRedo(); }
     417    QString DeleteMapGetUndoMessage(void) { return deleteMap.GetUndoMessage(); }
     418    QString DeleteMapGetRedoMessage(void) { return deleteMap.GetRedoMessage(); }
    415419
    416420    // Reinit
    417421    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 d7a381c..6765b94 100644
    a b void TV::InitKeys(void) 
    767767            "Jump back 10x the normal amount"), ",,<");
    768768    REG_KEY("TV Editing", "BIGJUMPFWD",  QT_TRANSLATE_NOOP("MythControls",
    769769            "Jump forward 10x the normal amount"), ">,.");
     770    REG_KEY("TV Editing", "UNDO",        QT_TRANSLATE_NOOP("MythControls",
     771            "Undo"), "Ctrl+Z");
     772    REG_KEY("TV Editing", "REDO",        QT_TRANSLATE_NOOP("MythControls",
     773            "Redo"), "Ctrl+Y");
    770774
    771775    /* Teletext keys */
    772776    REG_KEY("Teletext Menu", "NEXTPAGE",    QT_TRANSLATE_NOOP("MythControls",
    void TV::ShowOSDCutpoint(PlayerContext *ctx, const QString &type) 
    90859089        if ("EDIT_CUT_POINTS" == type)
    90869090            osd->DialogAddButton(QObject::tr("Cut List Options"),
    90879091                                 "DIALOG_CUTPOINT_CUTLISTOPTIONS_0", true);
     9092        if (ctx->player->DeleteMapHasUndo())
     9093            osd->DialogAddButton(QObject::tr("Undo") + " - " +
     9094                                 ctx->player->DeleteMapGetUndoMessage(),
     9095                                 QString("DIALOG_CUTPOINT_UNDO_0"));
     9096        if (ctx->player->DeleteMapHasRedo())
     9097            osd->DialogAddButton(QObject::tr("Redo") + " - " +
     9098                                 ctx->player->DeleteMapGetRedoMessage(),
     9099                                 QString("DIALOG_CUTPOINT_REDO_0"));
    90889100    }
    90899101    else if ("CUT_LIST_OPTIONS" == type)
    90909102    {