Пример #1
0
        // Group: Functions
        // __________________________________________________________________________


        /* Function: HTMLBuildState
         *
         * Constructor.
         *
         * If createEmptyObjects is set things like <sourceFilesToRebuild> will have objects associated with them.  If it's falso,
         * they will be set to null.  Only set it to false if you're going to be creating the objects yourself since they shouldn't be
         * set to null.
         */
        public HTMLBuildState(bool createEmptyObjects = true)
        {
            if (createEmptyObjects)
            {
                sourceFilesToRebuild      = new IDObjects.NumberSet();
                sourceFilesWithContent    = new IDObjects.NumberSet();
                classFilesToRebuild       = new IDObjects.NumberSet();
                classFilesWithContent     = new IDObjects.NumberSet();
                prefixesToRebuild         = new StringSet();
                foldersToCheckForDeletion = new StringSet(Config.Manager.KeySettingsForPaths);
                usedMenuDataFiles         = new StringTable <NumberSet>();
            }
            else
            {
                sourceFilesToRebuild      = null;
                sourceFilesWithContent    = null;
                classFilesToRebuild       = null;
                classFilesWithContent     = null;
                prefixesToRebuild         = null;
                foldersToCheckForDeletion = null;
                usedMenuDataFiles         = null;
            }

            needToBuildFramePage      = false;
            needToBuildMainStyleFiles = false;
            needToBuildMenu           = false;
            needToBuildPrefixIndex    = false;
        }
Пример #2
0
        public Manager(Engine.Instance engineInstance) : base(engineInstance)
        {
            linksToResolve            = new IDObjects.NumberSet();
            newTopicIDsByEndingSymbol = new SafeDictionary <Symbols.EndingSymbol, IDObjects.NumberSet>();

            beforeFirstResolve = true;
        }
Пример #3
0
        /* Function: GetInfoOnLinksThatResolveToTopicID
         *
         * Returns aggregate information on all links that resolve to the passed topic ID.
         *
         * Parameters:
         *
         *		topicID - The topic ID to look up links for.
         *		fileIDs - The file IDs of all the links.  Will be null if none.
         *		classIDs - The class IDs of all the links.  Will be null if none.
         *
         */
        public void GetInfoOnLinksThatResolveToTopicID(int topicID, out IDObjects.NumberSet fileIDs, out IDObjects.NumberSet classIDs)
        {
            accessor.RequireAtLeast(Accessor.LockType.ReadOnly);

            fileIDs  = null;
            classIDs = null;

            using (SQLite.Query query = accessor.Connection.Query("SELECT FileID, ClassID FROM Links WHERE TargetTopicID=?", topicID))
            {
                while (query.Step())
                {
                    if (fileIDs == null)
                    {
                        fileIDs = new NumberSet();
                    }

                    fileIDs.Add(query.IntColumn(0));

                    int classID = query.IntColumn(1);

                    if (classID != 0)
                    {
                        if (classIDs == null)
                        {
                            classIDs = new NumberSet();
                        }

                        classIDs.Add(classID);
                    }
                }
            }
        }
Пример #4
0
        public void OnDeleteTopic(Topic topic, CodeDB.EventAccessor eventAccessor)
        {
            IDObjects.NumberSet parentClassIDs     = null;
            IDObjects.NumberSet parentClassFileIDs = null;

            if (topic.DefinesClass)
            {
                eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs);
            }

            lock (accessLock)
            {
                buildState.SourceFilesToRebuild.Add(topic.FileID);

                if (topic.ClassID != 0)
                {
                    buildState.ClassFilesToRebuild.Add(topic.ClassID);
                }

                if (parentClassIDs != null)
                {
                    buildState.ClassFilesToRebuild.Add(parentClassIDs);
                }
                if (parentClassFileIDs != null)
                {
                    buildState.SourceFilesToRebuild.Add(parentClassFileIDs);
                }
            }
        }
Пример #5
0
        /* Function: GetChildList
         */
        protected List <Topic> GetChildList()
        {
            // First find all the class parent links that resolve to this one and collect the class IDs.

            IDObjects.NumberSet childClassIDs = null;

            if (links != null)
            {
                foreach (var link in links)
                {
                    if (link.Type == LinkType.ClassParent && link.TargetClassID == topic.ClassID)
                    {
                        if (childClassIDs == null)
                        {
                            childClassIDs = new IDObjects.NumberSet();
                        }

                        childClassIDs.Add(link.ClassID);
                    }
                }
            }

            if (childClassIDs == null)
            {
                return(null);
            }


            // Now find the topics that define those classes.

            List <Topic> childTopics = new List <Topic>();

            foreach (var linkTarget in linkTargets)
            {
                if (linkTarget.DefinesClass && childClassIDs.Contains(linkTarget.ClassID))
                {
                    childTopics.Add(linkTarget);
                    childClassIDs.Remove(linkTarget.ClassID);
                }
            }

            if (childTopics.Count == 0)
            {
                return(null);
            }


            // Now sort the child topics by symbol.

            bool caseSensitive = EngineInstance.Languages.FromID(topic.LanguageID).CaseSensitive;

            childTopics.Sort(
                delegate(Topic a, Topic b)
            {
                return(a.Symbol.CompareTo(b.Symbol, !caseSensitive));
            }
                );

            return(childTopics);
        }
Пример #6
0
        /* Function: PickNewImageFiles
         * Returns the IDs for a batch of new image files and their shared lowercase file name, or false if there aren't any.  This allows you to
         * process new image files that could potentially serve as better definitions to existing links.
         */
        public bool PickNewImageFiles(out IDObjects.NumberSet imageFileIDs, out string lcFileName)
        {
            lock (accessLock)
            {
                if (newImageFileIDsByLCFileName.Count == 0)
                {
                    imageFileIDs = null;
                    lcFileName   = null;
                    return(false);
                }
                else
                {
                    // Once links might be resolved we can't allow this optimization anymore.  See the variable's documentation for
                    // the explanation.
                    allLinksAreNew = false;

                    var enumerator = newImageFileIDsByLCFileName.GetEnumerator();
                    enumerator.MoveNext();                      // It's not positioned on the first element by default.

                    lcFileName   = enumerator.Current.Key;
                    imageFileIDs = enumerator.Current.Value;

                    newImageFileIDsByLCFileName.Remove(lcFileName);

                    return(true);
                }
            }
        }
Пример #7
0
        /* Function: DeleteTopic
         */
        public void DeleteTopic(Topic topic, IDObjects.NumberSet linksAffected)
        {
            lock (accessLock)
            {
                // Reresolve affected links

                linksToResolve.Add(linksAffected);


                // Remove topic from newTopicIDsByEndingSymbol

                var endingSymbol = topic.Symbol.EndingSymbol;
                var newTopicIDs  = newTopicIDsByEndingSymbol[endingSymbol];

                if (newTopicIDs != null)
                {
                    newTopicIDs.Remove(topic.TopicID);

                    if (newTopicIDs.IsEmpty)
                    {
                        newTopicIDsByEndingSymbol.Remove(endingSymbol);
                    }
                }
            }
        }
Пример #8
0
        // Group: CodeDB.IChangeWatcher Functions
        // __________________________________________________________________________


        public void OnAddTopic(Topic topic, CodeDB.EventAccessor eventAccessor)
        {
            // If this topic defines a class, it's possible it's now the best definition and thus we have to update the class prototypes
            // of all its parents.  We don't have to worry about updating children because that will be taken care of by OnLinkChange
            // since there would be a class parent link pointing to it.

            IDObjects.NumberSet parentClassIDs     = null;
            IDObjects.NumberSet parentClassFileIDs = null;

            if (topic.DefinesClass)
            {
                eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs);
            }

            lock (accessLock)
            {
                buildState.SourceFilesToRebuild.Add(topic.FileID);

                if (topic.ClassID != 0)
                {
                    buildState.ClassFilesToRebuild.Add(topic.ClassID);
                }

                if (parentClassIDs != null)
                {
                    buildState.ClassFilesToRebuild.Add(parentClassIDs);
                }
                if (parentClassFileIDs != null)
                {
                    buildState.SourceFilesToRebuild.Add(parentClassFileIDs);
                }
            }
        }
Пример #9
0
        public void OnDeleteFile(File file)
        {
            if (file.Type == FileType.Image)
            {
                // We need to get the image links affected by this

                CodeDB.Accessor accessor = EngineInstance.CodeDB.GetAccessor();

                try
                {
                    accessor.GetReadOnlyLock();
                    IDObjects.NumberSet linksAffected = accessor.GetImageLinkIDsByTarget(file.ID, Delegates.NeverCancel);
                    accessor.ReleaseLock();

                    unprocessedChanges.DeleteImageFile((ImageFile)file, linksAffected);
                }
                finally
                {
                    if (accessor.HasLock)
                    {
                        accessor.ReleaseLock();
                    }

                    accessor.Dispose();
                }
            }
        }
Пример #10
0
        public void OnDeleteTopic(Topic topic, IDObjects.NumberSet linksAffected, CodeDB.EventAccessor eventAccessor)
        {
            // We'll wait for OnChangeLinkTarget to handle linksAffected

            IDObjects.NumberSet parentClassIDs     = null;
            IDObjects.NumberSet parentClassFileIDs = null;

            if (topic.DefinesClass)
            {
                eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs);
            }

            lock (accessLock)
            {
                buildState.SourceFilesToRebuild.Add(topic.FileID);

                if (topic.ClassID != 0)
                {
                    buildState.ClassFilesToRebuild.Add(topic.ClassID);
                }

                if (parentClassIDs != null)
                {
                    buildState.ClassFilesToRebuild.Add(parentClassIDs);
                }
                if (parentClassFileIDs != null)
                {
                    buildState.SourceFilesToRebuild.Add(parentClassFileIDs);
                }
            }
        }
Пример #11
0
        /* Function: PickNewTopics
         * Returns the IDs for a batch of new topics and their shared ending symbol, or false if there aren't any.  This allows you to process
         * new topics that could potentially serve as better definitions to existing links.
         */
        public bool PickNewTopics(out IDObjects.NumberSet topicIDs, out EndingSymbol endingSymbol)
        {
            lock (accessLock)
            {
                if (newTopicIDsByEndingSymbol.Count == 0)
                {
                    topicIDs     = null;
                    endingSymbol = default(EndingSymbol);
                    return(false);
                }
                else
                {
                    // Once links might be resolved we can't allow this optimization anymore.  See the variable's documentation for
                    // the explanation.
                    ignoreNewTopics = false;

                    var enumerator = newTopicIDsByEndingSymbol.GetEnumerator();
                    enumerator.MoveNext();                      // It's not positioned on the first element by default.

                    endingSymbol = enumerator.Current.Key;
                    topicIDs     = enumerator.Current.Value;

                    newTopicIDsByEndingSymbol.Remove(endingSymbol);

                    return(true);
                }
            }
        }
Пример #12
0
        // Group: Functions
        // __________________________________________________________________________


        /* Function: UnprocessedChanges
         */
        public UnprocessedChanges()
        {
            newOrChangedFileIDs = new IDObjects.NumberSet();
            deletedFileIDs      = new IDObjects.NumberSet();

            accessLock = new object();
        }
Пример #13
0
        // Group: Misc Functions
        // __________________________________________________________________________


        /* Function: Cleanup
         * Cleans up the module's internal data when everything is up to date.  This will remove any successfully processed
         * deleted files, after which they can no longer be found with <FromID()> and their IDs may be reassigned.  You can
         * pass a <CancelDelegate> to interrupt the process if necessary.
         */
        public void Cleanup(CancelDelegate cancelDelegate)
        {
            lock (accessLock)
            {
                IDObjects.NumberSet toDelete = new IDObjects.NumberSet();

                foreach (File file in files)
                {
                    if (cancelDelegate())
                    {
                        return;
                    }

                    if (file.Status == FileFlags.Deleted)
                    {
                        toDelete.Add(file.ID);
                    }
                }

                foreach (int id in toDelete)
                {
                    if (cancelDelegate())
                    {
                        return;
                    }

                    files.Remove(id);
                }
            }
        }
Пример #14
0
        // Group: Functions
        // __________________________________________________________________________


        /* Function: Manager
         *
         * Creates a new IDObject manager.
         *
         * Parameters:
         *
         *		keySettings - The <KeySettings> that should apply when referencing objects by name.
         *
         *		sparse - If false, it assumes the manager will be handling objects with low and mostly consecutive ID numbers.
         *					This allows it to store them in an array where the index maps directly to the ID number, which is very
         *					fast.  However, if there are going to be large gaps in the IDs stored this will waste a lot of memory.
         *
         *					If true, it assumes the manager will be handling objects with high and/or non-consecutive ID numbers
         *					with large gaps between the values.  This means it will store them in a sorted array and use a binary
         *					search for lookups and insertions.  This is slower but more memory efficient.
         */
        public Manager(KeySettings keySettings, bool sparse)
        {
            usedIDs       = new IDObjects.NumberSet();
            objectsByID   = new List <IDObjectType>();
            objectsByName = new StringTable <IDObjectType>(keySettings);
            this.sparse   = sparse;
        }
Пример #15
0
        public void OnDeleteTopic(Topic topic, IDObjects.NumberSet linksAffected, CodeDB.EventAccessor eventAccessor)
        {
            // We'll wait for OnChangeLinkTarget to handle linksAffected

            IDObjects.NumberSet parentClassIDs     = null;
            IDObjects.NumberSet parentClassFileIDs = null;

            if (topic.DefinesClass)
            {
                eventAccessor.GetInfoOnClassParents(topic.ClassID, out parentClassIDs, out parentClassFileIDs);
            }

            unprocessedChanges.Lock();
            try
            {
                unprocessedChanges.AddSourceFile(topic.FileID);

                if (topic.ClassID != 0)
                {
                    unprocessedChanges.AddClass(topic.ClassID);
                }

                if (parentClassIDs != null)
                {
                    unprocessedChanges.AddClasses(parentClassIDs);
                }
                if (parentClassFileIDs != null)
                {
                    unprocessedChanges.AddSourceFiles(parentClassFileIDs);
                }
            }
            finally
            { unprocessedChanges.Unlock(); }
        }
Пример #16
0
        /* Function: DeleteImageFile
         */
        public void DeleteImageFile(ImageFile imageFile, IDObjects.NumberSet linksAffected)
        {
            lock (accessLock)
            {
                // Reresolve affected links

                imageLinksToResolve.Add(linksAffected);


                // Remove topic from newImageFileIDsByLCFileName

                string lcFileName      = imageFile.FileName.NameWithoutPath.ToLower();
                var    newImageFileIDs = newImageFileIDsByLCFileName[lcFileName];

                if (newImageFileIDs != null)
                {
                    newImageFileIDs.Remove(imageFile.ID);

                    if (newImageFileIDs.IsEmpty)
                    {
                        newImageFileIDsByLCFileName.Remove(lcFileName);
                    }
                }
            }
        }
Пример #17
0
        public void OnDeleteTopic(Topic topic, IDObjects.NumberSet linksAffected, EventAccessor eventAccessor)
        {
            Monitor.Enter(linksToResolve);

            try
            { linksToResolve.Add(linksAffected); }
            finally
            { Monitor.Exit(linksToResolve); }


            // Check newTopicIDsByEndingSymbol just in case.  We don't want to leave any references to a deleted topic.

            Monitor.Enter(newTopicIDsByEndingSymbol);

            try
            {
                IDObjects.NumberSet newTopicIDs = newTopicIDsByEndingSymbol[topic.Symbol.EndingSymbol];

                if (newTopicIDs != null)
                {
                    newTopicIDs.Remove(topic.TopicID);
                }
            }
            finally
            { Monitor.Exit(newTopicIDsByEndingSymbol); }
        }
Пример #18
0
        // Group: CodeDB.IChangeWatcher Functions
        // __________________________________________________________________________


        public void OnAddTopic(Topic topic, EventAccessor eventAccessor)
        {
            Monitor.Enter(newTopicIDsByEndingSymbol);

            try
            {
                if (beforeFirstResolve && EngineInstance.Config.ReparseEverything)
                {
                    // We don't need to track newTopicIDsByEndingSymbol in this case because the entire output will
                    // be reparsed and every link will be re-added.  Thus every link will be on linksToResolve and we don't
                    // need to worry about new topics causing existing links to need to be reresolved.
                }
                else
                {
                    IDObjects.NumberSet newTopicIDs = newTopicIDsByEndingSymbol[topic.Symbol.EndingSymbol];

                    if (newTopicIDs == null)
                    {
                        newTopicIDs = new IDObjects.NumberSet();
                        newTopicIDsByEndingSymbol.Add(topic.Symbol.EndingSymbol, newTopicIDs);
                    }

                    newTopicIDs.Add(topic.TopicID);
                }
            }
            finally
            {
                Monitor.Exit(newTopicIDsByEndingSymbol);
            }
        }
Пример #19
0
 /* Function: FinalizeNewImageFiles
  * Finalizes processing of a set of new image files and their shared lowercase file name.
  */
 protected void FinalizeNewImageFiles(IDObjects.NumberSet imageFileIDs, string lcFileName)
 {
     lock (accessLock)
         {
         // DEPENDENCY: Make sure all changes to changesBeingProcessed match the system used in UnprocessedChanges.Count
         changesBeingProcessed -= imageFileIDs.Count;
         }
 }
Пример #20
0
 /* Function: FinalizeNewTopics
  * Finalizes processing of a set of new topics and their shared ending symbol.
  */
 protected void FinalizeNewTopics(IDObjects.NumberSet topicIDs, EndingSymbol endingSymbol)
 {
     lock (accessLock)
     {
         // DEPENDENCY: Make sure all changes to changesBeingProcessed match the system used in UnprocessedChanges.Count
         changesBeingProcessed -= topicIDs.Count;
     }
 }
Пример #21
0
 public void AddChangedFiles(IDObjects.NumberSet fileIDs)
 {
     lock (accessLock)
     {
         deletedFileIDs.Remove(fileIDs);
         newOrChangedFileIDs.Add(fileIDs);
     }
 }
Пример #22
0
        // Group: Initialization and Configuration Functions
        // __________________________________________________________________________


        /* Function: Processor
         */
        public Processor(Engine.Instance engineInstance) : base(engineInstance)
        {
            unprocessedChangedFileIDs = new IDObjects.NumberSet();
            unprocessedDeletedFileIDs = new IDObjects.NumberSet();
            claimedFileIDs            = new IDObjects.NumberSet();

            accessLock = new object();
        }
Пример #23
0
        // Group: Functions
        // __________________________________________________________________________


        /* Function: UnprocessedChanges
         */
        public UnprocessedChanges(bool reparsingEverything = false)
        {
            linksToResolve            = new IDObjects.NumberSet();
            newTopicIDsByEndingSymbol = new SafeDictionary <Symbols.EndingSymbol, IDObjects.NumberSet>();

            // If we're reparsing everything we can ignore new topics.  See the variable's documentation for the explanation.
            ignoreNewTopics = reparsingEverything;

            accessLock = new object();
        }
Пример #24
0
        /* Function: Add
         * Adds a new value to the table.
         */
        public void Add(ObjectType key, int value)
        {
            IDObjects.NumberSet numberSet = this[key];

            if (numberSet == null)
            {
                numberSet = new IDObjects.NumberSet();
                this[key] = numberSet;
            }

            numberSet.Add(value);
        }
Пример #25
0
        // Group: Initialization and Configuration Functions
        // __________________________________________________________________________


        /* Function: Manager
         */
        public Manager(Engine.Instance engineInstance) : base(engineInstance)
        {
            fileSources = new List <FileSource>();
            filters     = new List <Filter>();

            files = new IDObjects.Manager <File>(Config.Manager.KeySettingsForPaths, false);
            filesAddedSinceStart = new IDObjects.NumberSet();
            unprocessedChanges   = new UnprocessedChanges();

            accessLock     = new object();
            changeWatchers = new List <IChangeWatcher>();
        }
Пример #26
0
        public void OnAddLink(Link link, CodeDB.EventAccessor eventAccessor)
        {
            // If a class parent link was added we have to rebuild all source files that define that class as the class prototype
            // may have changed.
            IDObjects.NumberSet filesThatDefineClass = null;

            if (link.Type == LinkType.ClassParent)
            {
                filesThatDefineClass = eventAccessor.GetFileIDsThatDefineClassID(link.ClassID);

                // If it's resolved we have to rebuild all source files that define the target as well so its children get updated.
                if (link.TargetClassID != 0)
                {
                    IDObjects.NumberSet filesThatDefineTarget = eventAccessor.GetFileIDsThatDefineClassID(link.TargetClassID);

                    if (filesThatDefineClass == null)
                    {
                        filesThatDefineClass = filesThatDefineTarget;
                    }
                    else if (filesThatDefineTarget != null)
                    {
                        filesThatDefineClass.Add(filesThatDefineTarget);
                    }
                }
            }

            unprocessedChanges.Lock();
            try
            {
                // Even if it's not a class parent link we still need to rebuild the source and class files that contain it.  We can't
                // rely on the topic events picking it up because it's possible to change links without changing topics.  How?  By
                // changing a using statement, which causes all the links to change.
                unprocessedChanges.AddSourceFile(link.FileID);

                if (link.ClassID != 0)
                {
                    unprocessedChanges.AddClass(link.ClassID);
                }

                if (link.Type == LinkType.ClassParent && link.TargetClassID != 0)
                {
                    unprocessedChanges.AddClass(link.TargetClassID);
                }

                if (filesThatDefineClass != null)
                {
                    unprocessedChanges.AddSourceFiles(filesThatDefineClass);
                }
            }
            finally
            { unprocessedChanges.Unlock(); }
        }
Пример #27
0
        /* Function: LowestAvailable
         * The lowest unused number available for the passed key, starting at one.
         */
        public int LowestAvailable(ObjectType key)
        {
            IDObjects.NumberSet numberSet = this[key];

            if (numberSet == null)
            {
                return(1);
            }
            else
            {
                return(numberSet.LowestAvailable);
            }
        }
Пример #28
0
 /* Function: PickNewImageFiles
  * Returns the IDs for a batch of new image files and their shared lowercase file name, or false if there aren't any.  This allows
  * you to process new images that could potentially serve as better definitions to existing links.  You must pass the values
  * to <FinalizeNewImageFiles()> after resolving them.
  */
 protected bool PickNewImageFiles(out IDObjects.NumberSet imageFileIDs, out string lcFileName)
 {
     lock (accessLock)
         {
         if (Manager.UnprocessedChanges.PickNewImageFiles(out imageFileIDs, out lcFileName))
             {
             // DEPENDENCY: Make sure all changes to changesBeingProcessed match the system used in UnprocessedChanges.Count
             changesBeingProcessed += imageFileIDs.Count;
             return true;
             }
         else
             {  return false;  }
         }
 }
Пример #29
0
 /* Function: PickNewTopics
  * Returns the IDs for a batch of new topics and their shared ending symbol, or false if there aren't any.  This allows
  * you to process new topics that could potentially serve as better definitions to existing links.  You must pass the values
  * to <FinalizeNewTopics()> after resolving them.
  */
 protected bool PickNewTopics(out IDObjects.NumberSet topicIDs, out EndingSymbol endingSymbol)
 {
     lock (accessLock)
         {
         if (Manager.UnprocessedChanges.PickNewTopics(out topicIDs, out endingSymbol))
             {
             // DEPENDENCY: Make sure all changes to changesBeingProcessed match the system used in UnprocessedChanges.Count
             changesBeingProcessed += topicIDs.Count;
             return true;
             }
         else
             {  return false;  }
         }
 }
Пример #30
0
        // Group: Functions
        // __________________________________________________________________________


        /* Function: Manager
         */
        public Manager(Engine.Instance engineInstance) : base(engineInstance)
        {
            connection   = null;
            databaseLock = new Lock();

            usedTopicIDs   = new IDObjects.NumberSet();
            usedLinkIDs    = new IDObjects.NumberSet();
            usedClassIDs   = new IDObjects.NumberSet();
            usedContextIDs = new IDObjects.NumberSet();

            classIDReferenceChangeCache   = new ReferenceChangeCache();
            contextIDReferenceChangeCache = new ReferenceChangeCache();

            changeWatchers = new List <IChangeWatcher>();
        }