private void doMoveSlides(int index, List <SlideInfo> sortedSlides)
        {
            int actualInsertIndex = index;

            foreach (SlideInfo slideInfo in sortedSlides)
            {
                if (slideInfo.Index <= index && actualInsertIndex > 0)
                {
                    --actualInsertIndex;
                }
                slideshow.removeSlide(slideInfo.Slide);
                if (SlideRemoved != null)
                {
                    SlideRemoved.Invoke(slideInfo.Slide);
                }

                slideshow.insertSlide(actualInsertIndex, slideInfo.Slide);
                if (SlideAdded != null)
                {
                    SlideAdded.Invoke(slideInfo.Slide, actualInsertIndex);
                }
                ++actualInsertIndex;
            }
            if (SlideSelected != null)
            {
                Slide primarySelection = lastEditSlide;
                if (primarySelection == null)
                {
                    //Double check the last edit slide if the user moved a slide without actually clicking and releasing that slide will be null,
                    //in this case use the slide that was moved.
                    primarySelection = sortedSlides[0].Slide;
                }
                SlideSelected.Invoke(primarySelection, secondarySlideSelections(sortedSlides, primarySelection));
            }
        }
        public void editSlide(Slide slide)
        {
            bool openedEditContext = false;

            if (slide != lastEditSlide)
            {
                openedEditContext = openEditorContextForSlide(slide);
            }
            else
            {
                if (slideEditorContext != null)
                {
                    slideEditorContext.slideNameChanged("Slide " + (slideshow.indexOf(slide) + 1));
                }
                else
                {
                    openEditorContextForSlide(slide); //If the slide context is null the timeline editor is open, switch back to slide editing.
                    //We ignore the context open result, because we do not care about undo in this situation
                }
            }

            if (openedEditContext)
            {
                if (lastEditSlide != null && allowUndoCreation)
                {
                    undoBuffer.pushAndSkip(new TwoWayDelegateCommand <Slide, Slide>(slide, lastEditSlide, new TwoWayDelegateCommand <Slide, Slide> .Funcs()
                    {
                        ExecuteFunc = (redoItem) =>
                        {
                            //Hacky, but we cannot modify the active slide without messing up the classes that triggered this.
                            ThreadManager.invoke(new Action(delegate()
                            {
                                allowUndoCreation = false;
                                if (SlideSelected != null)
                                {
                                    SlideSelected.Invoke(redoItem, IEnumerableUtil <Slide> .EmptyIterator);
                                }
                                allowUndoCreation = true;
                            }));
                        },
                        UndoFunc = (undoItem) =>
                        {
                            //Hacky, but we cannot modify the active slide without messing up the classes that triggered this.
                            ThreadManager.invoke(new Action(delegate()
                            {
                                allowUndoCreation = false;
                                if (SlideSelected != null)
                                {
                                    SlideSelected.Invoke(undoItem, IEnumerableUtil <Slide> .EmptyIterator);
                                }
                                allowUndoCreation = true;
                            }));
                        },
                    })
                                           );
                }
                lastEditSlide = slide;
                uiCallback.CurrentDirectory = slide.UniqueName;
            }
        }
        public void moveSlides(IEnumerable <Slide> slides, int index)
        {
            List <SlideInfo> sortedSlides = new List <SlideInfo>(from slide in slides select new SlideInfo(slide, slideshow.indexOf(slide)));

            sortedSlides.Sort(SlideInfo.Sort);

            bool wasAllowingUndo = allowUndoCreation;

            allowUndoCreation = false;
            doMoveSlides(index, sortedSlides);
            allowUndoCreation = wasAllowingUndo;

            if (allowUndoCreation)
            {
                undoBuffer.pushAndSkip(new TwoWayDelegateCommand(
                                           new TwoWayDelegateCommand.Funcs()
                {
                    ExecuteFunc = () =>     //Execute
                    {
                        allowUndoCreation = false;
                        doMoveSlides(index, sortedSlides);
                        allowUndoCreation = true;
                    },
                    UndoFunc = () =>     //Undo
                    {
                        allowUndoCreation = false;
                        foreach (SlideInfo info in sortedSlides)
                        {
                            int formerIndex = slideshow.indexOf(info.Slide);
                            slideshow.removeAt(formerIndex);
                            if (SlideRemoved != null)
                            {
                                SlideRemoved.Invoke(info.Slide);
                            }
                        }
                        //Can't think of how to do this without two loops, have to compensate for other things
                        //that need to be undone or else this won't put things back, two loops makes sure
                        //all items are removed and we can just insert back to original indices.
                        foreach (SlideInfo info in sortedSlides)
                        {
                            slideshow.insertSlide(info.Index, info.Slide);
                            if (SlideAdded != null)
                            {
                                SlideAdded.Invoke(info.Slide, info.Index);
                            }
                        }
                        if (SlideSelected != null)
                        {
                            SlideSelected.Invoke(lastEditSlide, secondarySlideSelections(sortedSlides, lastEditSlide));
                        }
                        allowUndoCreation = true;
                    }
                }));
            }
        }
        public void runSlideshow(int startIndex)
        {
            if (startIndex == -1)
            {
                startIndex = 0;
            }
            AnomalousMvcContext context = slideshow.createContext(ResourceProvider, standaloneController.GUIManager, startIndex);

            context.RuntimeName = editorController.EditorContextRuntimeName;
            context.setResourceProvider(ResourceProvider);
            context.BlurAction = "Common/Blur";
            CallbackAction blurAction = new CallbackAction("Blur", blurContext =>
            {
                NavigationModel model = blurContext.getModel <NavigationModel>(Medical.SlideshowProps.BaseContextProperties.NavigationModel);
                Slide slide           = slideshow.get(model.CurrentIndex);
                if (SlideshowContextBlurred != null)
                {
                    SlideshowContextBlurred.Invoke(blurContext);
                }
                ThreadManager.invoke(new Action(() =>
                {
                    if (lastEditSlide == slide)
                    {
                        if (SlideSelected != null)
                        {
                            SlideSelected.Invoke(null, IEnumerableUtil <Slide> .EmptyIterator);
                        }
                    }
                    if (SlideSelected != null)
                    {
                        SlideSelected.Invoke(slide, IEnumerableUtil <Slide> .EmptyIterator);
                    }
                }));
            });

            context.Controllers["Common"].Actions.add(blurAction);
            if (SlideshowContextStarting != null)
            {
                SlideshowContextStarting.Invoke(context);
            }
            standaloneController.TimelineController.setResourceProvider(editorController.ResourceProvider);
            standaloneController.MvcCore.startRunningContext(context);
        }
        public void addSlide(Slide slide, int index = -1)
        {
            if (index == -1)
            {
                slideshow.addSlide(slide);
            }
            else
            {
                slideshow.insertSlide(index, slide);
            }

            if (!editorController.ResourceProvider.exists(slide.UniqueName))
            {
                editorController.ResourceProvider.createDirectory("", slide.UniqueName);
            }

            if (SlideAdded != null)
            {
                SlideAdded.Invoke(slide, index);
            }

            //Delay this till the next frame, so the rml has actually been rendererd
            ThreadManager.invoke(new Action(delegate()
            {
                if (slideEditorContext != null)
                {
                    slideEditorContext.updateThumbnail();
                }
            }));

            if (allowUndoCreation)
            {
                if (lastEditSlide == null)
                {
                    undoBuffer.pushAndSkip(new TwoWayDelegateCommand <SlideInfo>(new SlideInfo(slide, slideshow.indexOf(slide)),
                                                                                 new TwoWayDelegateCommand <SlideInfo> .Funcs()
                    {
                        ExecuteFunc = (executeSlide) =>
                        {
                            allowUndoCreation = false;
                            addSlide(executeSlide.Slide, executeSlide.Index);
                            allowUndoCreation = true;
                        },
                        UndoFunc = (undoSlide) =>
                        {
                            allowUndoCreation = false;
                            removeSlide(undoSlide.Slide);
                            allowUndoCreation = true;
                        },
                        TrimmedFunc = cleanupThumbnail,
                    }
                                                                                 ));
                }
                else
                {
                    undoBuffer.pushAndSkip(new TwoWayDelegateCommand <RemoveSlideInfo>(new RemoveSlideInfo(slide, index, lastEditSlide),
                                                                                       new TwoWayDelegateCommand <RemoveSlideInfo> .Funcs()
                    {
                        ExecuteFunc = (executeSlide) =>
                        {
                            //Hacky, but we cannot modify the active slide without messing up the classes that triggered this.
                            ThreadManager.invoke(new Action(delegate()
                            {
                                allowUndoCreation = false;
                                addSlide(executeSlide.Slide, executeSlide.Index);
                                if (SlideSelected != null)
                                {
                                    SlideSelected.Invoke(executeSlide.Slide, IEnumerableUtil <Slide> .EmptyIterator);
                                }
                                allowUndoCreation = true;
                            }));
                        },
                        UndoFunc = (undoSlide) =>
                        {
                            //Hacky, but we cannot modify the active slide without messing up the classes that triggered this.
                            ThreadManager.invoke(new Action(delegate()
                            {
                                allowUndoCreation = false;
                                if (SlideSelected != null)
                                {
                                    SlideSelected.Invoke(undoSlide.ChangeToSlide, IEnumerableUtil <Slide> .EmptyIterator);
                                }
                                removeSlide(undoSlide.Slide);
                                allowUndoCreation = true;
                            }));
                        },
                        TrimmedFunc = cleanupThumbnail
                    }));
                }
            }

            bool wasAllowingUndo = allowUndoCreation;

            allowUndoCreation = false;
            if (SlideSelected != null)
            {
                SlideSelected.Invoke(slide, IEnumerableUtil <Slide> .EmptyIterator);
            }
            allowUndoCreation = wasAllowingUndo;
        }
        public void removeSlide(Slide slide)
        {
            int slideIndex = slideshow.indexOf(slide);

            if (slideIndex != -1)
            {
                slideshow.removeAt(slideIndex);
                if (SlideRemoved != null)
                {
                    SlideRemoved.Invoke(slide);
                }

                Slide changeToSlide = null;
                if (slide == lastEditSlide)
                {
                    if (slideIndex < slideshow.Count)
                    {
                        changeToSlide = slideshow.get(slideIndex);
                    }
                    else if (slideIndex - 1 >= 0)
                    {
                        changeToSlide = slideshow.get(slideIndex - 1);
                    }
                }

                if (changeToSlide != null)
                {
                    bool wasAllowingUndo = allowUndoCreation;
                    allowUndoCreation = false;
                    if (SlideSelected != null)
                    {
                        SlideSelected.Invoke(changeToSlide, IEnumerableUtil <Slide> .EmptyIterator);
                    }
                    allowUndoCreation = wasAllowingUndo;
                }

                if (allowUndoCreation)
                {
                    if (changeToSlide == null)
                    {
                        undoBuffer.pushAndSkip(new TwoWayDelegateCommand <SlideInfo>(new SlideInfo(slide, slideIndex),
                                                                                     new TwoWayDelegateCommand <SlideInfo> .Funcs()
                        {
                            ExecuteFunc = (executeSlide) =>
                            {
                                allowUndoCreation = false;
                                removeSlide(executeSlide.Slide);
                                allowUndoCreation = true;
                            },
                            UndoFunc = (undoSlide) =>
                            {
                                allowUndoCreation = false;
                                addSlide(undoSlide.Slide, undoSlide.Index);
                                allowUndoCreation = true;
                            },
                        }
                                                                                     ));
                    }
                    else
                    {
                        undoBuffer.pushAndSkip(new TwoWayDelegateCommand <RemoveSlideInfo>(new RemoveSlideInfo(slide, slideIndex, changeToSlide),
                                                                                           new TwoWayDelegateCommand <RemoveSlideInfo> .Funcs()
                        {
                            ExecuteFunc = (executeSlide) =>
                            {
                                //Hacky, but we cannot modify the active slide without messing up the classes that triggered this.
                                ThreadManager.invoke(new Action(delegate()
                                {
                                    allowUndoCreation = false;
                                    removeSlide(executeSlide.Slide);
                                    if (SlideSelected != null)
                                    {
                                        SlideSelected.Invoke(executeSlide.ChangeToSlide, IEnumerableUtil <Slide> .EmptyIterator);
                                    }
                                    allowUndoCreation = true;
                                }));
                            },
                            UndoFunc = (undoSlide) =>
                            {
                                //Hacky, but we cannot modify the active slide without messing up the classes that triggered this.
                                ThreadManager.invoke(new Action(delegate()
                                {
                                    allowUndoCreation = false;
                                    addSlide(undoSlide.Slide, undoSlide.Index);
                                    if (SlideSelected != null)
                                    {
                                        SlideSelected.Invoke(undoSlide.Slide, IEnumerableUtil <Slide> .EmptyIterator);
                                    }
                                    allowUndoCreation = true;
                                }));
                            },
                            PoppedFrontFunc = cleanupThumbnail
                        }));
                    }
                }
            }
        }
        public void removeSlides(IEnumerable <Slide> slides, Slide primarySelection)
        {
            int slideIndex = slideshow.indexOf(primarySelection);
            List <SlideInfo> removedSlides = new List <SlideInfo>(from slide in slides select new SlideInfo(slide, slideshow.indexOf(slide)));

            if (removedSlides.Count > 0)
            {
                removedSlides.Sort(SlideInfo.Sort);

                doRemoveSlides(removedSlides);

                Slide changeToSlide = null;
                if (primarySelection == lastEditSlide)
                {
                    if (slideIndex < slideshow.Count)
                    {
                        changeToSlide = slideshow.get(slideIndex);
                    }
                    else if (slideIndex - 1 >= 0)
                    {
                        changeToSlide = slideshow.get(slideIndex - 1);
                    }
                }

                bool wasAllowingUndo = allowUndoCreation;
                allowUndoCreation = false;
                if (changeToSlide != null && SlideSelected != null)
                {
                    SlideSelected.Invoke(changeToSlide, IEnumerableUtil <Slide> .EmptyIterator);
                }
                allowUndoCreation = wasAllowingUndo;

                if (allowUndoCreation)
                {
                    undoBuffer.pushAndSkip(new TwoWayDelegateCommand(
                                               new TwoWayDelegateCommand.Funcs()
                    {
                        ExecuteFunc = () =>     //Execute
                        {
                            ThreadManager.invoke(new Action(() =>
                            {
                                allowUndoCreation = false;
                                doRemoveSlides(removedSlides);
                                if (changeToSlide != null && SlideSelected != null)
                                {
                                    SlideSelected.Invoke(changeToSlide, IEnumerableUtil <Slide> .EmptyIterator);
                                }
                                allowUndoCreation = true;
                            }));
                        },
                        UndoFunc = () =>     //Undo
                        {
                            ThreadManager.invoke(new Action(() =>
                            {
                                allowUndoCreation = false;
                                foreach (SlideInfo slide in removedSlides)
                                {
                                    slideshow.insertSlide(slide.Index, slide.Slide);
                                    if (SlideAdded != null)
                                    {
                                        SlideAdded.Invoke(slide.Slide, slide.Index);
                                    }
                                }
                                if (SlideSelected != null)
                                {
                                    SlideSelected.Invoke(primarySelection, secondarySlideSelections(removedSlides, primarySelection));
                                }
                                allowUndoCreation = true;
                            }));
                        },
                        PoppedFrontFunc = () =>
                        {
                            foreach (SlideInfo slideInfo in removedSlides)
                            {
                                cleanupThumbnail(slideInfo);
                            }
                        }
                    }));
                }
            }
        }