예제 #1
0
            public SubfolderBranchFinder(
                IElement parent,
                ElemCreationFlags options)
            {
                _parent = parent;

                _maxChildren = Core.SM.UI.ElementWdw.LimitChildrenCount;
                _subFolders  = parent.Children
                               .Choose(TryMatchSubfolder)
                               .ToList();

                _it = options.HasFlag(ElemCreationFlags.ReuseSubFolders)
          ? 1
          : Math.Max(1, _subFolders.Count);

                //while (newElemCount > 0)
                //{
                //  SubfolderData data;

                //  if (i < _subFolders.Count)
                //  {
                //    var (child, sfNo) = _subFolders[i];

                //    data = new SubfolderData(child.Id, sfNo, _maxChildren - child.ChildrenCount);
                //  }

                //  else
                //  {
                //    data = new SubfolderData(null, ++folderCount, _maxChildren);
                //  }

                //  newElemCount -= data.SlotsLeft;
                //  _data.Add(data);
                //}
            }
예제 #2
0
        private int FindDestinationBranch(IElement parent,
                                          ElemCreationFlags options)
        {
            if (options.HasFlag(ElemCreationFlags.CreateSubfolders) == false)
            {
                return(CanAddElement(parent, options) ? parent.Id : -1);
            }

            var regExSubfolders = new Regex($"\\[([0-9]+)\\] {Regex.Escape(parent.Title)}");

            var subFolders = parent.Children
                             .Select(child => (child, regExSubfolders.Match(child.Title)))
                             .Where(p => p.Item2.Success)
                             .ToList();

            if (subFolders.Any() == false)
            {
                return(CreateAutoSubfolders(parent, 1));
            }

            var subFolder = subFolders.MaxBy(p => int.Parse(p.Item2.Groups[1].Value))
                            .First();

            if (subFolder.child == null || CanAddElement(subFolder.child, ElemCreationFlags.None) == false)
            {
                return(CreateAutoSubfolders(
                           parent,
                           subFolder.child == null
            ? 1
            : int.Parse(subFolder.Item2.Groups[1].Value) + 1
                           ));
            }

            return(subFolder.child.Id);
        }
예제 #3
0
        //
        //

        private bool CanAddElement(IElement parent,
                                   ElemCreationFlags options)
        {
            if (options.HasFlag(ElemCreationFlags.ForceCreate))
            {
                return(true);
            }

            return(parent.ChildrenCount < Core.SMA.CollectionConfig.ChildrenPerBranch);
        }
        //
        //

        private bool CanAddElement(IElement parent,
                                   ElemCreationFlags options)
        {
            if (options.HasFlag(ElemCreationFlags.ForceCreate))
            {
                return(true);
            }

            return(parent.ChildrenCount < Core.SM.UI.ElementWdw.LimitChildrenCount);
        }
예제 #5
0
        private async Task <List <ElemCreationResult> > AddInternalAsync(
            ElemCreationFlags options,
            ElementBuilder[]  builders)
        {
            if (builders == null || builders.Length == 0)
            {
                return(null);
            }

            var inSMUpdateLockMode  = false;
            var inSMAUpdateLockMode = false;
            var singleMode          = builders.Length == 1;

            var results = new List <ElemCreationResult>(
                builders.Select(
                    b => new ElemCreationResult(ElemCreationResultCodes.ErrorUnknown, b))
                );

            try
            {
                int restoreElementId = Core.SM.UI.ElementWdw.CurrentElementId;
                int restoreHookId    = Core.SM.UI.ElementWdw.CurrentHookId;

                //
                // Enter critical section

                _addMutex.WaitOne();

                //
                // Suspend element changed monitoring

                inSMAUpdateLockMode = Core.SM.UI.ElementWdw.EnterSMAUpdateLock();

                //
                // Focus

                // toDispose.Add(new FocusSnapshot(true)); // TODO: Only if inserting 1 element

                //
                // Regroup by parent id to optimize remote calls

                var resultsByParent = results.GroupBy(k => k.Builder.ParentId);

                //
                // Freeze element window if we want to insert the element without displaying it immediately

                if (singleMode == false || builders[0].ShouldDisplay == false)
                {
                    inSMUpdateLockMode = Core.SM.UI.ElementWdw.EnterSMUpdateLock(); // TODO: Pass in EnterUpdateLock
                }
                foreach (var rpGroup in resultsByParent)
                {
                    using var h = new HookSnapshot();

                    var parent = rpGroup.Key.HasValue ? this[rpGroup.Key.Value] : this[restoreHookId];

                    var branchFinder = options.HasFlag(ElemCreationFlags.CreateSubfolders)
            ? (IDestinationBranchFinder) new SubfolderBranchFinder(parent, options)
            : (IDestinationBranchFinder) new ConstantBranchFinder(parent);

                    await AddInternalAsync(rpGroup.ToList(), branchFinder).ConfigureAwait(false);
                }

                //
                // Display original element, and unfreeze window -- or simply resume element changed monitoring

                if (inSMUpdateLockMode)
                {
                    inSMUpdateLockMode = Core.SM.UI.ElementWdw.QuitSMUpdateLock() == false;

                    Core.SM.UI.ElementWdw.GoToElement(restoreElementId);
                }

                inSMAUpdateLockMode = Core.SM.UI.ElementWdw.QuitSMAUpdateLock(inSMUpdateLockMode);

                return(results);
            }
            catch (Exception ex)
            {
                LogTo.Error(ex, "An exception was thrown while creating a new element in SM.");
                return(results);
            }
            finally
            {
                //
                // Unlock SM if necessary

                if (inSMUpdateLockMode)
                {
                    try
                    {
                        Core.SM.UI.ElementWdw.QuitSMUpdateLock();
                    }
                    catch (Exception ex)
                    {
                        LogTo.Warning(ex, "Failed to exit SM Update Lock.");
                        MessageBox.Show($@"Failed to exit SuperMemo UI update lock.
You might have to restart SuperMemo.

Exception: {ex}",
                                        "Critical error");
                    }
                }

                //
                // Unlock element changed monitoring if necessary

                if (inSMAUpdateLockMode)
                {
                    Core.SM.UI.ElementWdw.QuitSMAUpdateLock();
                }

                //
                // Exit Critical section

                _addMutex.ReleaseMutex();
            }
        }