From 46cc0a7462f3cae4bdb6127abcdf43467b7ffd82 Mon Sep 17 00:00:00 2001 From: "kashin.aleksandr" Date: Wed, 18 Dec 2024 23:03:45 +0500 Subject: [PATCH 1/4] =?UTF-8?q?=D0=A7=D0=B5=D1=80=D0=BD=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TagCloud/App.cs | 37 +++++++++++++ TagCloud/Client/ConsoleClient.cs | 51 +++++++++++++++++ TagCloud/Client/GuiClient.cs | 16 ++++++ TagCloud/Client/IClient.cs | 6 ++ TagCloud/CloudPainter/CloudPainter.cs | 37 +++++++++++++ TagCloud/CloudPainter/ICloudPainter.cs | 8 +++ TagCloud/Program.cs | 36 ++++++++++++ TagCloud/Settings/ISettingsProvider.cs | 7 +++ TagCloud/Settings/Settings.cs | 10 ++++ TagCloud/Settings/SettingsProvider.cs | 12 ++++ TagCloud/TagCloud.csproj | 22 ++++++++ .../Circular/CircularCloudLayouter.cs | 52 ++++++++++++++++++ .../CircularCloudLayouterExtensions.cs | 19 +++++++ .../TagPositioner/Circular/ICloudLayouter.cs | 8 +++ TagCloud/TagPositioner/ITagPositioner.cs | 8 +++ TagCloud/TagPositioner/TagPositioner.cs | 43 +++++++++++++++ TagCloud/WordCounter/IWordCounter.cs | 6 ++ TagCloud/WordCounter/Tag.cs | 10 ++++ TagCloud/WordCounter/WordCounter.cs | 12 ++++ .../DefaultBoringWordProvider.cs | 9 +++ .../WordsProcessing/IBoringWordProvider.cs | 6 ++ TagCloud/WordsProcessing/IWordPreprocessor.cs | 6 ++ TagCloud/WordsProcessing/WordPreprocessor.cs | 25 +++++++++ TagCloud/WordsReader/IWordsReader.cs | 6 ++ TagCloud/WordsReader/TxtWordsReader.cs | 16 ++++++ TagCloud/result.png | Bin 0 -> 6632 bytes TagCloud/words.txt | 11 ++++ di.sln | 6 ++ 28 files changed, 485 insertions(+) create mode 100644 TagCloud/App.cs create mode 100644 TagCloud/Client/ConsoleClient.cs create mode 100644 TagCloud/Client/GuiClient.cs create mode 100644 TagCloud/Client/IClient.cs create mode 100644 TagCloud/CloudPainter/CloudPainter.cs create mode 100644 TagCloud/CloudPainter/ICloudPainter.cs create mode 100644 TagCloud/Program.cs create mode 100644 TagCloud/Settings/ISettingsProvider.cs create mode 100644 TagCloud/Settings/Settings.cs create mode 100644 TagCloud/Settings/SettingsProvider.cs create mode 100644 TagCloud/TagCloud.csproj create mode 100644 TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs create mode 100644 TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs create mode 100644 TagCloud/TagPositioner/Circular/ICloudLayouter.cs create mode 100644 TagCloud/TagPositioner/ITagPositioner.cs create mode 100644 TagCloud/TagPositioner/TagPositioner.cs create mode 100644 TagCloud/WordCounter/IWordCounter.cs create mode 100644 TagCloud/WordCounter/Tag.cs create mode 100644 TagCloud/WordCounter/WordCounter.cs create mode 100644 TagCloud/WordsProcessing/DefaultBoringWordProvider.cs create mode 100644 TagCloud/WordsProcessing/IBoringWordProvider.cs create mode 100644 TagCloud/WordsProcessing/IWordPreprocessor.cs create mode 100644 TagCloud/WordsProcessing/WordPreprocessor.cs create mode 100644 TagCloud/WordsReader/IWordsReader.cs create mode 100644 TagCloud/WordsReader/TxtWordsReader.cs create mode 100644 TagCloud/result.png create mode 100644 TagCloud/words.txt diff --git a/TagCloud/App.cs b/TagCloud/App.cs new file mode 100644 index 00000000..e6723f0b --- /dev/null +++ b/TagCloud/App.cs @@ -0,0 +1,37 @@ +using System.Drawing; +using TagCloud.CloudPainter; +using TagCloud.Settings; +using TagCloud.TagPositioner; +using TagCloud.TagPositioner.Circular; +using TagCloud.WordCounter; +using TagCloud.WordsProcessing; +using TagCloud.WordsReader; + +namespace TagCloud; + +public class App +{ + private readonly IWordPreprocessor _wordPreprocessor; + private readonly IWordCounter _wordCounter; + private readonly ICloudPainter _cloudPainter; + private readonly ITagPositioner _tagPositioner; + + public App(IWordPreprocessor wordPreprocessor, + IWordCounter wordCounter, + ICloudPainter cloudPainter, + ITagPositioner tagPositioner) + { + _wordPreprocessor = wordPreprocessor; + _wordCounter = wordCounter; + _cloudPainter = cloudPainter; + _tagPositioner = tagPositioner; + } + + public void Run() + { + var words = _wordPreprocessor.Process().ToArray(); + var tags = _wordCounter.CalculateWordCount(words); + tags = _tagPositioner.Position(tags); + _cloudPainter.Paint(tags); + } +} \ No newline at end of file diff --git a/TagCloud/Client/ConsoleClient.cs b/TagCloud/Client/ConsoleClient.cs new file mode 100644 index 00000000..785c506e --- /dev/null +++ b/TagCloud/Client/ConsoleClient.cs @@ -0,0 +1,51 @@ +using CommandLine; +using TagCloud.Settings; + +namespace TagCloud.Client; + +public class ConsoleClient : IClient +{ + private readonly App _app; + private readonly ISettingsProvider _settingsProvider; + + public ConsoleClient(App app, ISettingsProvider settingsProvider) + { + _app = app; + _settingsProvider = settingsProvider; + } + public void Run() + { + Console.WriteLine("This is console Application."); + + var args = Environment.GetCommandLineArgs(); + + //TODO:Получать аргументы из командной строки: + // 1. Ширина + // 2. Высота + // 3. Путь к файлу со словами + // 4. Путь к папке сохранения результат + // 5. Путь к файлу со "скучными словами". + // 6. Алгоритм построения облака + // 6.1 Алгоритм расцветки? + // 6.2 Алгоритм построения? + + //TODO: Задавать размер шрифта - минимум и максимум. Чем чаще встречается слово - тем больше шрифт. + var settings = _settingsProvider.GetSettings(); + settings.SourcePath = "words.txt"; + settings.SavePath = "..\\..\\..\\result.png"; + settings.Width = 800; + settings.Height = 800; + settings.FontFamily = "Consolas"; + + _settingsProvider.SetSettings(settings); + + Parser.Default.ParseArguments(args) + .WithParsed(settings => + { + + + }); + + _app.Run(); + } +} \ No newline at end of file diff --git a/TagCloud/Client/GuiClient.cs b/TagCloud/Client/GuiClient.cs new file mode 100644 index 00000000..d1cdcefd --- /dev/null +++ b/TagCloud/Client/GuiClient.cs @@ -0,0 +1,16 @@ +namespace TagCloud.Client; + +public class GuiClient : IClient +{ + private readonly App _app; + + public GuiClient(App app) + { + _app = app; + } + public void Run() + { + Console.WriteLine("This is GUI Application"); + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/TagCloud/Client/IClient.cs b/TagCloud/Client/IClient.cs new file mode 100644 index 00000000..7976ff2d --- /dev/null +++ b/TagCloud/Client/IClient.cs @@ -0,0 +1,6 @@ +namespace TagCloud.Client; + +public interface IClient +{ + void Run(); +} \ No newline at end of file diff --git a/TagCloud/CloudPainter/CloudPainter.cs b/TagCloud/CloudPainter/CloudPainter.cs new file mode 100644 index 00000000..582ecfce --- /dev/null +++ b/TagCloud/CloudPainter/CloudPainter.cs @@ -0,0 +1,37 @@ +using System.Drawing; +using TagCloud.Settings; +using TagCloud.WordCounter; + +namespace TagCloud.CloudPainter; + +public class CloudPainter : ICloudPainter +{ + private ISettingsProvider _settingsProvider; + + public CloudPainter(ISettingsProvider settingsProvider) + { + _settingsProvider = settingsProvider; + } + + public void Paint(List tags) + { + var settings = _settingsProvider.GetSettings(); + + using var bitmap = new Bitmap(settings.Width, settings.Height); + using var graphics = Graphics.FromImage(bitmap); + graphics.Clear(Color.White); + var fontFamily = new FontFamily(settings.FontFamily); + + var random = new Random(); + foreach (var tag in tags) + { + var fontSize = 20; + var font = new Font(fontFamily, fontSize); + var color = Color.FromArgb(random.Next(100, 256), random.Next(100, 256), random.Next(100, 256)); + using var brush = new SolidBrush(color); + graphics.DrawString(tag.Word, font, brush, tag.Location); + } + + bitmap.Save(settings.SavePath, System.Drawing.Imaging.ImageFormat.Png); + } +} \ No newline at end of file diff --git a/TagCloud/CloudPainter/ICloudPainter.cs b/TagCloud/CloudPainter/ICloudPainter.cs new file mode 100644 index 00000000..4335930a --- /dev/null +++ b/TagCloud/CloudPainter/ICloudPainter.cs @@ -0,0 +1,8 @@ +using TagCloud.WordCounter; + +namespace TagCloud.CloudPainter; + +public interface ICloudPainter +{ + void Paint(List tags); +} \ No newline at end of file diff --git a/TagCloud/Program.cs b/TagCloud/Program.cs new file mode 100644 index 00000000..775e98c6 --- /dev/null +++ b/TagCloud/Program.cs @@ -0,0 +1,36 @@ +using Autofac; +using TagCloud.Client; +using TagCloud.CloudPainter; +using TagCloud.Settings; +using TagCloud.TagPositioner; +using TagCloud.TagPositioner.Circular; +using TagCloud.WordCounter; +using TagCloud.WordsProcessing; +using TagCloud.WordsReader; + +namespace TagCloud; + +class Program +{ + static void Main() + { + var builder = new ContainerBuilder(); + + builder.RegisterType(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As(); + + var container = builder.Build(); + + var app = container.Resolve(); + + app.Run(); + } +} \ No newline at end of file diff --git a/TagCloud/Settings/ISettingsProvider.cs b/TagCloud/Settings/ISettingsProvider.cs new file mode 100644 index 00000000..4b47f9cc --- /dev/null +++ b/TagCloud/Settings/ISettingsProvider.cs @@ -0,0 +1,7 @@ +namespace TagCloud.Settings; + +public interface ISettingsProvider +{ + Settings GetSettings(); + void SetSettings(Settings settings); +} \ No newline at end of file diff --git a/TagCloud/Settings/Settings.cs b/TagCloud/Settings/Settings.cs new file mode 100644 index 00000000..846d27f0 --- /dev/null +++ b/TagCloud/Settings/Settings.cs @@ -0,0 +1,10 @@ +namespace TagCloud.Settings; + +public class Settings +{ + public string SourcePath { get; set; } + public int Width { get; set; } + public int Height { get; set; } + public string FontFamily { get; set; } + public string SavePath { get; set; } +} \ No newline at end of file diff --git a/TagCloud/Settings/SettingsProvider.cs b/TagCloud/Settings/SettingsProvider.cs new file mode 100644 index 00000000..1957cdc2 --- /dev/null +++ b/TagCloud/Settings/SettingsProvider.cs @@ -0,0 +1,12 @@ +namespace TagCloud.Settings; + +public class SettingsProvider : ISettingsProvider +{ + private Settings _settings = new(); + + public Settings GetSettings() => + _settings; + + public void SetSettings(Settings settings) => + _settings = settings; +} \ No newline at end of file diff --git a/TagCloud/TagCloud.csproj b/TagCloud/TagCloud.csproj new file mode 100644 index 00000000..4557966b --- /dev/null +++ b/TagCloud/TagCloud.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + Always + + + + diff --git a/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs b/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs new file mode 100644 index 00000000..bc15a20c --- /dev/null +++ b/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs @@ -0,0 +1,52 @@ +using System.Drawing; +using TagCloud.Settings; + +namespace TagCloud.TagPositioner.Circular; + +public class CircularCloudLayouter : ICloudLayouter +{ + private readonly ISettingsProvider _settingsProvider; + private Point center; + private double angle; + private const double SpiralStep = 0.2; + private double angleStep = 0.01; + + public CircularCloudLayouter(ISettingsProvider settingsProvider) + { + _settingsProvider = settingsProvider; + + } + + public Rectangle PutNextRectangle(Size rectangleSize, ICollection rectangles) + { + center = new Point(_settingsProvider.GetSettings().Width /2 , _settingsProvider.GetSettings().Height /2); + Rectangle newRectangle; + if (!rectangles.Any()) + { + var rectangle = new Rectangle(center, rectangleSize); + rectangles.Add(rectangle); + return rectangle; + } + + do + { + var location = GetLocation(rectangleSize); + newRectangle = new Rectangle(location, rectangleSize); + } + while (rectangles.IsIntersecting(newRectangle)); + + rectangles.Add(newRectangle); + + return newRectangle; + } + + private Point GetLocation(Size rectangleSize) + { + var radius = SpiralStep * angle; + var x = (int)(center.X + radius * Math.Cos(angle) - rectangleSize.Width / 2); + var y = (int)(center.Y + radius * Math.Sin(angle) - rectangleSize.Height / 2); + angle += angleStep; + + return new Point(x, y); + } +} \ No newline at end of file diff --git a/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs b/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs new file mode 100644 index 00000000..a86b6a1b --- /dev/null +++ b/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs @@ -0,0 +1,19 @@ +using System.Drawing; + +namespace TagCloud.TagPositioner.Circular; + +public static class CircularCloudLayouterExtensions +{ + public static Size GetBoundaryBox(this IList rectangles) + { + var minX = rectangles.Min(r => r.Left); + var minY = rectangles.Min(r => r.Top); + var maxX = rectangles.Max(r => r.Right); + var maxY = rectangles.Max(r => r.Bottom); + + return new Size(maxX - minX, maxY - minY); + } + + public static bool IsIntersecting(this IEnumerable rectangles, Rectangle rectangle) + => rectangles.Any(existingRectangle => existingRectangle.IntersectsWith(rectangle)); +} \ No newline at end of file diff --git a/TagCloud/TagPositioner/Circular/ICloudLayouter.cs b/TagCloud/TagPositioner/Circular/ICloudLayouter.cs new file mode 100644 index 00000000..9d27e674 --- /dev/null +++ b/TagCloud/TagPositioner/Circular/ICloudLayouter.cs @@ -0,0 +1,8 @@ +using System.Drawing; + +namespace TagCloud.TagPositioner.Circular; + +public interface ICloudLayouter +{ + Rectangle PutNextRectangle(Size rectangleSize, ICollection rectangles); +} \ No newline at end of file diff --git a/TagCloud/TagPositioner/ITagPositioner.cs b/TagCloud/TagPositioner/ITagPositioner.cs new file mode 100644 index 00000000..d859ff00 --- /dev/null +++ b/TagCloud/TagPositioner/ITagPositioner.cs @@ -0,0 +1,8 @@ +using TagCloud.WordCounter; + +namespace TagCloud.TagPositioner; + +public interface ITagPositioner +{ + List Position(List tags); +} \ No newline at end of file diff --git a/TagCloud/TagPositioner/TagPositioner.cs b/TagCloud/TagPositioner/TagPositioner.cs new file mode 100644 index 00000000..4d7943b2 --- /dev/null +++ b/TagCloud/TagPositioner/TagPositioner.cs @@ -0,0 +1,43 @@ +using System.Drawing; +using TagCloud.Settings; +using TagCloud.TagPositioner.Circular; +using TagCloud.WordCounter; + +namespace TagCloud.TagPositioner; + +public class TagPositioner : ITagPositioner +{ + private readonly ICloudLayouter _cloudLayouter; + private readonly ISettingsProvider _settingsProvider; + + public TagPositioner(ICloudLayouter cloudLayouter, ISettingsProvider settingsProvider) + { + _cloudLayouter = cloudLayouter; + _settingsProvider = settingsProvider; + } + public List Position(List tags) + { + var settings = _settingsProvider.GetSettings(); + var size = new Size(settings.Width, settings.Height); + var center = new Point(size.Width / 2, size.Height / 2); + var bitmap = new Bitmap(size.Width, size.Height); + var graphics = Graphics.FromImage(bitmap); + + var fontFamily = new FontFamily(settings.FontFamily); + var rectangels = new List(); + + foreach (var tag in tags) + { + var fontSize = 20; + var font = new Font(fontFamily, fontSize); + + var textSize = graphics.MeasureString(tag.Word, font); + var res = _cloudLayouter.PutNextRectangle(new Size((int)textSize.Width, (int)textSize.Height), rectangels); + tag.Location = new Point(res.X, res.Y); + } + + graphics.Dispose(); + + return tags; + } +} \ No newline at end of file diff --git a/TagCloud/WordCounter/IWordCounter.cs b/TagCloud/WordCounter/IWordCounter.cs new file mode 100644 index 00000000..f38125c9 --- /dev/null +++ b/TagCloud/WordCounter/IWordCounter.cs @@ -0,0 +1,6 @@ +namespace TagCloud.WordCounter; + +public interface IWordCounter +{ + List CalculateWordCount(IEnumerable words); +} \ No newline at end of file diff --git a/TagCloud/WordCounter/Tag.cs b/TagCloud/WordCounter/Tag.cs new file mode 100644 index 00000000..c47ec503 --- /dev/null +++ b/TagCloud/WordCounter/Tag.cs @@ -0,0 +1,10 @@ +using System.Drawing; + +namespace TagCloud.WordCounter; + +public class Tag +{ + public string Word { get; set; } = string.Empty; + public int Count { get; set; } + public Point Location { get; set; } +} \ No newline at end of file diff --git a/TagCloud/WordCounter/WordCounter.cs b/TagCloud/WordCounter/WordCounter.cs new file mode 100644 index 00000000..cf927540 --- /dev/null +++ b/TagCloud/WordCounter/WordCounter.cs @@ -0,0 +1,12 @@ +namespace TagCloud.WordCounter; + +public class WordCounter : IWordCounter +{ + public List CalculateWordCount(IEnumerable words) + { + //TODO: Добавить нормализацию или алгоритм нормализации. + return words.GroupBy(x => x) + .Select(x => new Tag(){ Word = x.Key, Count = x.Count() }) + .ToList(); + } +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/DefaultBoringWordProvider.cs b/TagCloud/WordsProcessing/DefaultBoringWordProvider.cs new file mode 100644 index 00000000..fdfcf578 --- /dev/null +++ b/TagCloud/WordsProcessing/DefaultBoringWordProvider.cs @@ -0,0 +1,9 @@ +namespace TagCloud.WordsProcessing; + +public class DefaultBoringWordProvider : IBoringWordProvider +{ + public string[] GetBoringWords() + { + return ["в", "на"]; + } +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/IBoringWordProvider.cs b/TagCloud/WordsProcessing/IBoringWordProvider.cs new file mode 100644 index 00000000..27fbec7d --- /dev/null +++ b/TagCloud/WordsProcessing/IBoringWordProvider.cs @@ -0,0 +1,6 @@ +namespace TagCloud.WordsProcessing; + +public interface IBoringWordProvider +{ + string[] GetBoringWords(); +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/IWordPreprocessor.cs b/TagCloud/WordsProcessing/IWordPreprocessor.cs new file mode 100644 index 00000000..2ad932c7 --- /dev/null +++ b/TagCloud/WordsProcessing/IWordPreprocessor.cs @@ -0,0 +1,6 @@ +namespace TagCloud.WordsProcessing; + +public interface IWordPreprocessor +{ + IEnumerable Process(); +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/WordPreprocessor.cs b/TagCloud/WordsProcessing/WordPreprocessor.cs new file mode 100644 index 00000000..73a378e8 --- /dev/null +++ b/TagCloud/WordsProcessing/WordPreprocessor.cs @@ -0,0 +1,25 @@ +using TagCloud.Settings; +using TagCloud.WordsReader; + +namespace TagCloud.WordsProcessing; + +public class WordPreprocessor : IWordPreprocessor +{ + private readonly IBoringWordProvider _boringWordProvider; + private readonly IWordsReader _wordsReader; + private readonly ISettingsProvider _settingsProvider; + + public WordPreprocessor(IBoringWordProvider boringWordProvider, IWordsReader wordsReader, ISettingsProvider settingsProvider) + { + _boringWordProvider = boringWordProvider; + _wordsReader = wordsReader; + _settingsProvider = settingsProvider; + } + public IEnumerable Process() + { + var strings = _wordsReader.Read(_settingsProvider.GetSettings().SourcePath); + return strings + .Select(x => x.ToLower()) + .Where(x => !_boringWordProvider.GetBoringWords().Contains(x)); + } +} \ No newline at end of file diff --git a/TagCloud/WordsReader/IWordsReader.cs b/TagCloud/WordsReader/IWordsReader.cs new file mode 100644 index 00000000..605b0e79 --- /dev/null +++ b/TagCloud/WordsReader/IWordsReader.cs @@ -0,0 +1,6 @@ +namespace TagCloud.WordsReader; + +public interface IWordsReader +{ + string[] Read(string path); +} \ No newline at end of file diff --git a/TagCloud/WordsReader/TxtWordsReader.cs b/TagCloud/WordsReader/TxtWordsReader.cs new file mode 100644 index 00000000..55cd36f3 --- /dev/null +++ b/TagCloud/WordsReader/TxtWordsReader.cs @@ -0,0 +1,16 @@ +namespace TagCloud.WordsReader; + +public class TxtWordsReader : IWordsReader +{ + public string[] Read(string path) + { + try + { + return File.ReadLines(path).ToArray(); + } + catch (Exception e) + { + throw new Exception($"Во время чтения файла {path} произошла ошибка.", e); + } + } +} \ No newline at end of file diff --git a/TagCloud/result.png b/TagCloud/result.png new file mode 100644 index 0000000000000000000000000000000000000000..991f3a027ac43c9dd864fbb4d073cd15ab997d6d GIT binary patch literal 6632 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 Date: Wed, 25 Dec 2024 10:37:53 +0500 Subject: [PATCH 2/4] =?UTF-8?q?=D0=A7=D0=B8=D1=81=D1=82=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D1=8F=20=D1=80=D0=B5=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86=D0=B8?= =?UTF-8?q?=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConsoleClient/ConsoleClient.cs | 16 ++ ConsoleClient/ConsoleClient.csproj | 19 ++ ConsoleClient/Program.cs | 21 ++ ConsoleClient/Settings/ConsoleSettings.cs | 33 +++ .../Settings/ConsoleSettingsManager.cs | 29 +++ ConsoleClient/Settings/ISettingsManager.cs | 6 + GuiClient/Forms/MainForm.cs | 202 ++++++++++++++++++ GuiClient/Forms/ResultForm.cs | 49 +++++ GuiClient/GuiClient.cs | 17 ++ GuiClient/GuiClient.csproj | 19 ++ GuiClient/Program.cs | 22 ++ TagCloud/App.cs | 36 +--- TagCloud/Client/ConsoleClient.cs | 51 ----- TagCloud/Client/GuiClient.cs | 16 -- TagCloud/CloudPainter/CloudPainter.cs | 26 +-- TagCloud/CloudPainter/ICloudPainter.cs | 2 +- TagCloud/Settings/AppSettings.cs | 8 + TagCloud/Settings/AppSettingsProvider.cs | 6 + TagCloud/Settings/IAppSettingsProvider.cs | 6 + TagCloud/Settings/IImageSettingsProvider.cs | 6 + TagCloud/Settings/ISettingsProvider.cs | 7 - TagCloud/Settings/ImageSettings.cs | 11 + TagCloud/Settings/ImageSettingsProvider.cs | 6 + TagCloud/Settings/Settings.cs | 10 - TagCloud/Settings/SettingsProvider.cs | 12 -- TagCloud/TagCloud.csproj | 16 +- TagCloud/{Program.cs => TagCloudModule.cs} | 21 +- .../Circular/CircularCloudLayouter.cs | 35 ++- .../CircularCloudLayouterExtensions.cs | 10 - TagCloud/TagPositioner/TagPositioner.cs | 28 +-- TagCloud/WordCounter/ITagCreator.cs | 6 + TagCloud/WordCounter/IWordCounter.cs | 6 - TagCloud/WordCounter/Tag.cs | 1 + TagCloud/WordCounter/TagCreator.cs | 30 +++ TagCloud/WordCounter/WordCounter.cs | 12 -- TagCloud/WordCounter/WordCounterExtensions.cs | 9 + .../DefaultBoringWordProvider.cs | 9 - .../FIleBoringWordsProvider.cs | 13 ++ .../WordsProcessing/IBoringWordProvider.cs | 6 - .../WordsProcessing/IBoringWordsProvider.cs | 6 + TagCloud/WordsProcessing/IWordPreprocessor.cs | 2 +- TagCloud/WordsProcessing/WordPreprocessor.cs | 25 +-- TagCloud/result.png | Bin 6632 -> 0 bytes TagCloudTests/BaseTest.cs | 32 +++ TagCloudTests/FileBoringWordsProviderTests.cs | 21 ++ TagCloudTests/Samples/BoringWords.txt | 82 +++++++ .../Samples/SampleWords.txt | 0 TagCloudTests/TagCloudTest.cs | 48 +++++ TagCloudTests/TagCloudTests.csproj | 39 ++++ TagCloudTests/TagCreatorTests.cs | 47 ++++ TagCloudTests/TestConstants.cs | 7 + TagCloudTests/TxtWordsReaderTests.cs | 28 +++ TagCloudTests/WordPreprocessorTests.cs | 49 +++++ TagCloudTests/test.png | Bin 0 -> 4449 bytes di.sln | 18 ++ 55 files changed, 977 insertions(+), 265 deletions(-) create mode 100644 ConsoleClient/ConsoleClient.cs create mode 100644 ConsoleClient/ConsoleClient.csproj create mode 100644 ConsoleClient/Program.cs create mode 100644 ConsoleClient/Settings/ConsoleSettings.cs create mode 100644 ConsoleClient/Settings/ConsoleSettingsManager.cs create mode 100644 ConsoleClient/Settings/ISettingsManager.cs create mode 100644 GuiClient/Forms/MainForm.cs create mode 100644 GuiClient/Forms/ResultForm.cs create mode 100644 GuiClient/GuiClient.cs create mode 100644 GuiClient/GuiClient.csproj create mode 100644 GuiClient/Program.cs delete mode 100644 TagCloud/Client/ConsoleClient.cs delete mode 100644 TagCloud/Client/GuiClient.cs create mode 100644 TagCloud/Settings/AppSettings.cs create mode 100644 TagCloud/Settings/AppSettingsProvider.cs create mode 100644 TagCloud/Settings/IAppSettingsProvider.cs create mode 100644 TagCloud/Settings/IImageSettingsProvider.cs delete mode 100644 TagCloud/Settings/ISettingsProvider.cs create mode 100644 TagCloud/Settings/ImageSettings.cs create mode 100644 TagCloud/Settings/ImageSettingsProvider.cs delete mode 100644 TagCloud/Settings/Settings.cs delete mode 100644 TagCloud/Settings/SettingsProvider.cs rename TagCloud/{Program.cs => TagCloudModule.cs} (57%) create mode 100644 TagCloud/WordCounter/ITagCreator.cs delete mode 100644 TagCloud/WordCounter/IWordCounter.cs create mode 100644 TagCloud/WordCounter/TagCreator.cs delete mode 100644 TagCloud/WordCounter/WordCounter.cs create mode 100644 TagCloud/WordCounter/WordCounterExtensions.cs delete mode 100644 TagCloud/WordsProcessing/DefaultBoringWordProvider.cs create mode 100644 TagCloud/WordsProcessing/FIleBoringWordsProvider.cs delete mode 100644 TagCloud/WordsProcessing/IBoringWordProvider.cs create mode 100644 TagCloud/WordsProcessing/IBoringWordsProvider.cs delete mode 100644 TagCloud/result.png create mode 100644 TagCloudTests/BaseTest.cs create mode 100644 TagCloudTests/FileBoringWordsProviderTests.cs create mode 100644 TagCloudTests/Samples/BoringWords.txt rename TagCloud/words.txt => TagCloudTests/Samples/SampleWords.txt (100%) create mode 100644 TagCloudTests/TagCloudTest.cs create mode 100644 TagCloudTests/TagCloudTests.csproj create mode 100644 TagCloudTests/TagCreatorTests.cs create mode 100644 TagCloudTests/TestConstants.cs create mode 100644 TagCloudTests/TxtWordsReaderTests.cs create mode 100644 TagCloudTests/WordPreprocessorTests.cs create mode 100644 TagCloudTests/test.png diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs new file mode 100644 index 00000000..3b1d4d19 --- /dev/null +++ b/ConsoleClient/ConsoleClient.cs @@ -0,0 +1,16 @@ +using CommandLine; +using ConsoleClient.Settings; +using TagCloud; +using TagCloud.Client; + +namespace ConsoleClient; + +public class ConsoleClient(App app, ISettingsManager settingsManager) : IClient +{ + public void Run() + { + Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) + .WithParsed(settingsManager.Set); + app.Run(); + } +} \ No newline at end of file diff --git a/ConsoleClient/ConsoleClient.csproj b/ConsoleClient/ConsoleClient.csproj new file mode 100644 index 00000000..aea59c26 --- /dev/null +++ b/ConsoleClient/ConsoleClient.csproj @@ -0,0 +1,19 @@ + + + + Exe + net8.0 + enable + enable + + + + + + + + + + + + diff --git a/ConsoleClient/Program.cs b/ConsoleClient/Program.cs new file mode 100644 index 00000000..6972d81a --- /dev/null +++ b/ConsoleClient/Program.cs @@ -0,0 +1,21 @@ +using Autofac; +using ConsoleClient.Settings; +using TagCloud; +using TagCloud.Client; + +namespace ConsoleClient; + +class Program +{ + static void Main() + { + var builder = new ContainerBuilder(); + builder.RegisterModule(new TagCloudModule()); + builder.RegisterType().As(); + builder.RegisterType().As(); + var container = builder.Build(); + var app = container.Resolve(); + + app.Run(); + } +} \ No newline at end of file diff --git a/ConsoleClient/Settings/ConsoleSettings.cs b/ConsoleClient/Settings/ConsoleSettings.cs new file mode 100644 index 00000000..d1b0fb19 --- /dev/null +++ b/ConsoleClient/Settings/ConsoleSettings.cs @@ -0,0 +1,33 @@ +using CommandLine; + +namespace ConsoleClient.Settings; + +public class ConsoleSettings +{ + [Option('w', "wight", Default = 800, HelpText = "Ширина изображения.")] + public int Width { get; set; } + + [Option('h', "height", Default = 800, HelpText = "Высота изображения.")] + public int Height { get; set; } + + [Option('b', "background", Default = "white", HelpText = "Цвет фона.")] + public string BackgroundColor { get; set; } = string.Empty; + + [Option('f', "font", Default = "arial", HelpText = "Шрифт.")] + public string FontFamily { get; set; } = string.Empty; + + [Option('p', "path", Default = "words.txt", HelpText = "Путь до источника слов.")] + public string SourcePath { get; set; } = string.Empty; + + [Option('o', "output", Default = "output.png", HelpText = "Путь сохранения результата.")] + public string SavePath { get; set; } = string.Empty; + + [Option("boringWords", HelpText = "Путь до списка скучный слов.")] + public string BoringWordsPath { get; set; } = string.Empty; + + [Option("minFont", Default = 15, HelpText = "Минимальный шрифт.")] + public int FontSizeMin { get; set; } + + [Option("maxFont", Default = 40, HelpText = "Максимальный шрифт.")] + public int FontSizeMax { get; set; } +} \ No newline at end of file diff --git a/ConsoleClient/Settings/ConsoleSettingsManager.cs b/ConsoleClient/Settings/ConsoleSettingsManager.cs new file mode 100644 index 00000000..8d6d3c7e --- /dev/null +++ b/ConsoleClient/Settings/ConsoleSettingsManager.cs @@ -0,0 +1,29 @@ +using TagCloud.Settings; + +namespace ConsoleClient.Settings; + +public class ConsoleSettingsManager( + IImageSettingsProvider imageSettingsProvider, + IAppSettingsProvider appSettingsProvider) + : ISettingsManager +{ + public void Set(ConsoleSettings settings) + { + imageSettingsProvider.ImageSettings = new ImageSettings + { + Width = settings.Width, + Height = settings.Height, + BackgroundColor = settings.BackgroundColor, + FontFamily = settings.FontFamily, + FontSizeMax = settings.FontSizeMax, + FontSizeMin = settings.FontSizeMin, + }; + + appSettingsProvider.AppSettings = new AppSettings + { + SourcePath = settings.SourcePath, + SavePath = settings.SavePath, + BoringWordsPath = settings.BoringWordsPath + }; + } +} \ No newline at end of file diff --git a/ConsoleClient/Settings/ISettingsManager.cs b/ConsoleClient/Settings/ISettingsManager.cs new file mode 100644 index 00000000..a41dc035 --- /dev/null +++ b/ConsoleClient/Settings/ISettingsManager.cs @@ -0,0 +1,6 @@ +namespace ConsoleClient.Settings; + +public interface ISettingsManager +{ + void Set(ConsoleSettings settings); +} \ No newline at end of file diff --git a/GuiClient/Forms/MainForm.cs b/GuiClient/Forms/MainForm.cs new file mode 100644 index 00000000..c45e443b --- /dev/null +++ b/GuiClient/Forms/MainForm.cs @@ -0,0 +1,202 @@ +using Autofac; +using TagCloud.Settings; + +namespace GuiClient.Forms; + +public class MainForm : Form +{ + private readonly ILifetimeScope _lifetimeScope; + + private NumericUpDown? _widthInput; + private NumericUpDown? _heightInput; + private Button? _colorButton; + private TextBox? _sourceFilePathInput; + private TextBox? _boringWordsPathFileInput; + private Button? _browseSourceFileButton; + private Button? _browseBoringWordsPathFileButton; + private Button? _fontButton; + private NumericUpDown? _minFontSizeInput; + private NumericUpDown? _maxFontSizeInput; + private Button? _generateButton; + private Color _selectedColor = Color.White; + private Font _selectedFont = new("Arial", 10); + + private const int LabelX = 20; + private const int InputX = 130; + private string _sourceFilePath = string.Empty; + private string _boringWordsFilePath = string.Empty; + + public MainForm(ILifetimeScope lifetimeScope) + { + _lifetimeScope = lifetimeScope; + InitForm(); + AddWidthHeightControl(); + AddColorControl(); + AddSourceFilePathSelector(); + AddBoringWordsFilePathSelector(); + AddFontSelector(); + AddMinMaxFontSizeControls(); + AddGenerateButton(); + } + + private void InitForm() + { + Text = "Tag Cloud"; + Size = new Size(480, 420); + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + StartPosition = FormStartPosition.CenterScreen; + } + + private void AddWidthHeightControl() + { + var widthLabel = new Label { Text = "Ширина:", Location = new Point(LabelX, 20), AutoSize = true }; + _widthInput = new NumericUpDown + { Location = new Point(InputX, 20), Minimum = 100, Maximum = 1920, Value = 400 }; + + var heightLabel = new Label { Text = "Высота:", Location = new Point(LabelX, 60), AutoSize = true }; + _heightInput = new NumericUpDown + { Location = new Point(InputX, 60), Minimum = 100, Maximum = 1080, Value = 300 }; + + Controls.Add(widthLabel); + Controls.Add(_widthInput); + Controls.Add(heightLabel); + Controls.Add(_heightInput); + } + + private void AddColorControl() + { + var colorLabel = new Label { Text = "Цвет:", Location = new Point(LabelX, 100), AutoSize = true }; + _colorButton = new Button { Text = "Выбрать цвет", Location = new Point(250, 100) }; + var colorPicture = new PictureBox + { + Location = new Point(InputX, 100), + Width = 100, + Height = 20, + BackColor = _selectedColor + }; + + _colorButton.Click += (_, _) => + { + using var colorDialog = new ColorDialog(); + if (colorDialog.ShowDialog() == DialogResult.OK) + { + _selectedColor = colorDialog.Color; + colorPicture.BackColor = colorDialog.Color; + } + }; + + Controls.Add(colorLabel); + Controls.Add(_colorButton); + Controls.Add(colorPicture); + } + + private void AddSourceFilePathSelector() + { + var sourceFilePathLabel = new Label { Text = "Источник:", Location = new Point(LabelX, 140), AutoSize = true }; + _sourceFilePathInput = new TextBox { Location = new Point(InputX, 140), Width = 200 }; + _browseSourceFileButton = new Button { Text = "Обзор...", Location = new Point(360, 140) }; + _browseSourceFileButton.Click += (_, _) => + { + using var openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = "Text Files (*.txt)|*.txt;"; + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + _sourceFilePathInput.Text = openFileDialog.FileName; + _sourceFilePath = openFileDialog.FileName; + } + }; + + Controls.Add(sourceFilePathLabel); + Controls.Add(_sourceFilePathInput); + Controls.Add(_browseSourceFileButton); + } + + private void AddBoringWordsFilePathSelector() + { + var additionalFilePathLabel = new Label + { Text = "Скучные слова:", Location = new Point(LabelX, 180), AutoSize = true }; + _boringWordsPathFileInput = new TextBox { Location = new Point(InputX, 180), Width = 200 }; + _browseBoringWordsPathFileButton = new Button { Text = "Обзор...", Location = new Point(360, 180) }; + _browseBoringWordsPathFileButton.Click += (_, _) => + { + using var openFileDialog = new OpenFileDialog(); + openFileDialog.Filter = "Text Files (*.txt)|*.txt"; + if (openFileDialog.ShowDialog() == DialogResult.OK) + { + _boringWordsPathFileInput.Text = openFileDialog.FileName; + _boringWordsFilePath = openFileDialog.FileName; + } + }; + Controls.Add(additionalFilePathLabel); + Controls.Add(_boringWordsPathFileInput); + Controls.Add(_browseBoringWordsPathFileButton); + } + + private void AddFontSelector() + { + var fontLabel = new Label { Text = "Шрифт:", Location = new Point(LabelX, 220), AutoSize = true }; + _fontButton = new Button { Text = "Выбрать шрифт", Location = new Point(InputX, 220) }; + _fontButton.Click += (_, _) => + { + using var fontDialog = new FontDialog(); + if (fontDialog.ShowDialog() == DialogResult.OK) + { + _selectedFont = fontDialog.Font; + } + }; + + Controls.Add(fontLabel); + Controls.Add(_fontButton); + } + + private void AddMinMaxFontSizeControls() + { + var minFontSizeLabel = new Label { Text = "Мин. шрифт:", Location = new Point(LabelX, 260), AutoSize = true }; + _minFontSizeInput = new NumericUpDown + { Location = new Point(InputX, 260), Minimum = 8, Maximum = 72, Value = 8 }; + + var maxFontSizeLabel = new Label { Text = "Макс. шрифт:", Location = new Point(LabelX, 300), AutoSize = true }; + _maxFontSizeInput = new NumericUpDown + { Location = new Point(InputX, 300), Minimum = 8, Maximum = 72, Value = 24 }; + + Controls.Add(minFontSizeLabel); + Controls.Add(_minFontSizeInput); + Controls.Add(maxFontSizeLabel); + Controls.Add(_maxFontSizeInput); + } + + private void AddGenerateButton() + { + _generateButton = new Button { Text = "Сгенерировать", Location = new Point(200, 340), AutoSize = true }; + _generateButton.Click += GenerateButton_Click!; + + Controls.Add(_generateButton); + } + + private void GenerateButton_Click(object sender, EventArgs e) + { + _lifetimeScope.Resolve() + .ImageSettings = new ImageSettings + { + Width = (int)_widthInput!.Value, + Height = (int)_heightInput!.Value, + BackgroundColor = _selectedColor.Name, + FontFamily = _selectedFont.FontFamily.Name, + FontSizeMax = (int)_minFontSizeInput!.Value, + FontSizeMin = (int)_maxFontSizeInput!.Value + }; + _lifetimeScope.Resolve() + .AppSettings = new AppSettings + { + SourcePath = _sourceFilePath, + BoringWordsPath = _boringWordsFilePath, + SavePath = "output.png" + }; + + var resultForm = new ResultForm(_lifetimeScope, this); + resultForm.Show(); + Hide(); + } +} \ No newline at end of file diff --git a/GuiClient/Forms/ResultForm.cs b/GuiClient/Forms/ResultForm.cs new file mode 100644 index 00000000..b17e82c6 --- /dev/null +++ b/GuiClient/Forms/ResultForm.cs @@ -0,0 +1,49 @@ +using Autofac; +using TagCloud; +using TagCloud.Settings; + +namespace GuiClient.Forms; + +public class ResultForm : Form +{ + private readonly ILifetimeScope _lifetimeScope; + + public ResultForm(ILifetimeScope lifetimeScope, Form mainForm) + { + _lifetimeScope = lifetimeScope; + + using var scope = _lifetimeScope.BeginLifetimeScope(); + var imageSettingsProvider = scope.Resolve(); + + Text = "Результат"; + Size = new Size(imageSettingsProvider.ImageSettings.Width, imageSettingsProvider.ImageSettings.Height + 70); + FormBorderStyle = FormBorderStyle.FixedDialog; + MaximizeBox = false; + MinimizeBox = false; + StartPosition = FormStartPosition.CenterScreen; + + var regenerateButton = new Button { Text = "Сгенерировать заново", Dock = DockStyle.Bottom, }; + regenerateButton.Click += (_, _) => + { + mainForm.Show(); + Close(); + }; + + ShowCloudImage(); + Controls.Add(regenerateButton); + } + + private void ShowCloudImage() + { + _lifetimeScope.Resolve().Run(); + var appSettingsProvider = _lifetimeScope.Resolve(); + var picture = new PictureBox + { + SizeMode = PictureBoxSizeMode.AutoSize, + ImageLocation = appSettingsProvider.AppSettings.SavePath, + Dock = DockStyle.Top, + }; + picture.Load(); + Controls.Add(picture); + } +} \ No newline at end of file diff --git a/GuiClient/GuiClient.cs b/GuiClient/GuiClient.cs new file mode 100644 index 00000000..652f88b8 --- /dev/null +++ b/GuiClient/GuiClient.cs @@ -0,0 +1,17 @@ +using Autofac; +using GuiClient.Forms; +using TagCloud.Client; + +namespace GuiClient; + +public class GuiClient(ILifetimeScope lifetimeScope) : IClient +{ + public void Run() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + + var mainForm = lifetimeScope.Resolve(); + Application.Run(mainForm); + } +} \ No newline at end of file diff --git a/GuiClient/GuiClient.csproj b/GuiClient/GuiClient.csproj new file mode 100644 index 00000000..d0efe09f --- /dev/null +++ b/GuiClient/GuiClient.csproj @@ -0,0 +1,19 @@ + + + + WinExe + net8.0-windows + enable + true + enable + + + + + + + + + + + \ No newline at end of file diff --git a/GuiClient/Program.cs b/GuiClient/Program.cs new file mode 100644 index 00000000..bd69775b --- /dev/null +++ b/GuiClient/Program.cs @@ -0,0 +1,22 @@ +using Autofac; +using GuiClient.Forms; +using TagCloud; +using TagCloud.Client; + +namespace GuiClient; + +static class Program +{ + [STAThread] + static void Main() + { + var builder = new ContainerBuilder(); + builder.RegisterModule(new TagCloudModule()); + builder.RegisterType().As(); + builder.RegisterType().InstancePerDependency(); + var container = builder.Build(); + + var client = container.Resolve(); + client.Run(); + } +} \ No newline at end of file diff --git a/TagCloud/App.cs b/TagCloud/App.cs index e6723f0b..158d87b9 100644 --- a/TagCloud/App.cs +++ b/TagCloud/App.cs @@ -1,37 +1,21 @@ -using System.Drawing; -using TagCloud.CloudPainter; -using TagCloud.Settings; +using TagCloud.CloudPainter; using TagCloud.TagPositioner; -using TagCloud.TagPositioner.Circular; using TagCloud.WordCounter; using TagCloud.WordsProcessing; -using TagCloud.WordsReader; namespace TagCloud; -public class App +public class App( + IWordPreprocessor wordPreprocessor, + ITagCreator tagCreator, + ICloudPainter cloudPainter, + ITagPositioner tagPositioner) { - private readonly IWordPreprocessor _wordPreprocessor; - private readonly IWordCounter _wordCounter; - private readonly ICloudPainter _cloudPainter; - private readonly ITagPositioner _tagPositioner; - - public App(IWordPreprocessor wordPreprocessor, - IWordCounter wordCounter, - ICloudPainter cloudPainter, - ITagPositioner tagPositioner) - { - _wordPreprocessor = wordPreprocessor; - _wordCounter = wordCounter; - _cloudPainter = cloudPainter; - _tagPositioner = tagPositioner; - } - public void Run() { - var words = _wordPreprocessor.Process().ToArray(); - var tags = _wordCounter.CalculateWordCount(words); - tags = _tagPositioner.Position(tags); - _cloudPainter.Paint(tags); + var words = wordPreprocessor.Process().ToArray(); + var tags = tagCreator.CreateTags(words); + tags = tagPositioner.Position(tags); + cloudPainter.Paint(tags.ToArray()); } } \ No newline at end of file diff --git a/TagCloud/Client/ConsoleClient.cs b/TagCloud/Client/ConsoleClient.cs deleted file mode 100644 index 785c506e..00000000 --- a/TagCloud/Client/ConsoleClient.cs +++ /dev/null @@ -1,51 +0,0 @@ -using CommandLine; -using TagCloud.Settings; - -namespace TagCloud.Client; - -public class ConsoleClient : IClient -{ - private readonly App _app; - private readonly ISettingsProvider _settingsProvider; - - public ConsoleClient(App app, ISettingsProvider settingsProvider) - { - _app = app; - _settingsProvider = settingsProvider; - } - public void Run() - { - Console.WriteLine("This is console Application."); - - var args = Environment.GetCommandLineArgs(); - - //TODO:Получать аргументы из командной строки: - // 1. Ширина - // 2. Высота - // 3. Путь к файлу со словами - // 4. Путь к папке сохранения результат - // 5. Путь к файлу со "скучными словами". - // 6. Алгоритм построения облака - // 6.1 Алгоритм расцветки? - // 6.2 Алгоритм построения? - - //TODO: Задавать размер шрифта - минимум и максимум. Чем чаще встречается слово - тем больше шрифт. - var settings = _settingsProvider.GetSettings(); - settings.SourcePath = "words.txt"; - settings.SavePath = "..\\..\\..\\result.png"; - settings.Width = 800; - settings.Height = 800; - settings.FontFamily = "Consolas"; - - _settingsProvider.SetSettings(settings); - - Parser.Default.ParseArguments(args) - .WithParsed(settings => - { - - - }); - - _app.Run(); - } -} \ No newline at end of file diff --git a/TagCloud/Client/GuiClient.cs b/TagCloud/Client/GuiClient.cs deleted file mode 100644 index d1cdcefd..00000000 --- a/TagCloud/Client/GuiClient.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace TagCloud.Client; - -public class GuiClient : IClient -{ - private readonly App _app; - - public GuiClient(App app) - { - _app = app; - } - public void Run() - { - Console.WriteLine("This is GUI Application"); - throw new NotImplementedException(); - } -} \ No newline at end of file diff --git a/TagCloud/CloudPainter/CloudPainter.cs b/TagCloud/CloudPainter/CloudPainter.cs index 582ecfce..568934ae 100644 --- a/TagCloud/CloudPainter/CloudPainter.cs +++ b/TagCloud/CloudPainter/CloudPainter.cs @@ -4,34 +4,26 @@ namespace TagCloud.CloudPainter; -public class CloudPainter : ICloudPainter +public class CloudPainter(IImageSettingsProvider imageSettingsProvider, IAppSettingsProvider appSettingsProvider) + : ICloudPainter { - private ISettingsProvider _settingsProvider; - - public CloudPainter(ISettingsProvider settingsProvider) + public void Paint(Tag[] tags) { - _settingsProvider = settingsProvider; - } - - public void Paint(List tags) - { - var settings = _settingsProvider.GetSettings(); - - using var bitmap = new Bitmap(settings.Width, settings.Height); + using var bitmap = new Bitmap(imageSettingsProvider.ImageSettings.Width, + imageSettingsProvider.ImageSettings.Height); using var graphics = Graphics.FromImage(bitmap); - graphics.Clear(Color.White); - var fontFamily = new FontFamily(settings.FontFamily); + graphics.Clear(Color.FromName(imageSettingsProvider.ImageSettings.BackgroundColor)); + var fontFamily = new FontFamily(imageSettingsProvider.ImageSettings.FontFamily); var random = new Random(); foreach (var tag in tags) { - var fontSize = 20; - var font = new Font(fontFamily, fontSize); + var font = new Font(fontFamily, tag.Weight); var color = Color.FromArgb(random.Next(100, 256), random.Next(100, 256), random.Next(100, 256)); using var brush = new SolidBrush(color); graphics.DrawString(tag.Word, font, brush, tag.Location); } - bitmap.Save(settings.SavePath, System.Drawing.Imaging.ImageFormat.Png); + bitmap.Save(appSettingsProvider.AppSettings.SavePath, System.Drawing.Imaging.ImageFormat.Png); } } \ No newline at end of file diff --git a/TagCloud/CloudPainter/ICloudPainter.cs b/TagCloud/CloudPainter/ICloudPainter.cs index 4335930a..c40e928c 100644 --- a/TagCloud/CloudPainter/ICloudPainter.cs +++ b/TagCloud/CloudPainter/ICloudPainter.cs @@ -4,5 +4,5 @@ namespace TagCloud.CloudPainter; public interface ICloudPainter { - void Paint(List tags); + void Paint(Tag[] tags); } \ No newline at end of file diff --git a/TagCloud/Settings/AppSettings.cs b/TagCloud/Settings/AppSettings.cs new file mode 100644 index 00000000..385c7d8e --- /dev/null +++ b/TagCloud/Settings/AppSettings.cs @@ -0,0 +1,8 @@ +namespace TagCloud.Settings; + +public class AppSettings +{ + public string SourcePath { get; init; } = string.Empty; + public string SavePath { get; init; } = "output.png"; + public string BoringWordsPath { get; init; } = string.Empty; +} \ No newline at end of file diff --git a/TagCloud/Settings/AppSettingsProvider.cs b/TagCloud/Settings/AppSettingsProvider.cs new file mode 100644 index 00000000..729bb967 --- /dev/null +++ b/TagCloud/Settings/AppSettingsProvider.cs @@ -0,0 +1,6 @@ +namespace TagCloud.Settings; + +public class AppSettingsProvider : IAppSettingsProvider +{ + public AppSettings AppSettings { get; set; } = null!; +} \ No newline at end of file diff --git a/TagCloud/Settings/IAppSettingsProvider.cs b/TagCloud/Settings/IAppSettingsProvider.cs new file mode 100644 index 00000000..50a578a8 --- /dev/null +++ b/TagCloud/Settings/IAppSettingsProvider.cs @@ -0,0 +1,6 @@ +namespace TagCloud.Settings; + +public interface IAppSettingsProvider +{ + AppSettings AppSettings { get; set; } +} \ No newline at end of file diff --git a/TagCloud/Settings/IImageSettingsProvider.cs b/TagCloud/Settings/IImageSettingsProvider.cs new file mode 100644 index 00000000..0795af4f --- /dev/null +++ b/TagCloud/Settings/IImageSettingsProvider.cs @@ -0,0 +1,6 @@ +namespace TagCloud.Settings; + +public interface IImageSettingsProvider +{ + ImageSettings ImageSettings { get; set; } +} \ No newline at end of file diff --git a/TagCloud/Settings/ISettingsProvider.cs b/TagCloud/Settings/ISettingsProvider.cs deleted file mode 100644 index 4b47f9cc..00000000 --- a/TagCloud/Settings/ISettingsProvider.cs +++ /dev/null @@ -1,7 +0,0 @@ -namespace TagCloud.Settings; - -public interface ISettingsProvider -{ - Settings GetSettings(); - void SetSettings(Settings settings); -} \ No newline at end of file diff --git a/TagCloud/Settings/ImageSettings.cs b/TagCloud/Settings/ImageSettings.cs new file mode 100644 index 00000000..219ad460 --- /dev/null +++ b/TagCloud/Settings/ImageSettings.cs @@ -0,0 +1,11 @@ +namespace TagCloud.Settings; + +public class ImageSettings +{ + public int Width { get; init; } + public int Height { get; init; } + public string BackgroundColor { get; init; } = string.Empty; + public string FontFamily { get; init; } = string.Empty; + public int FontSizeMax { get; init; } + public int FontSizeMin { get; init; } +} \ No newline at end of file diff --git a/TagCloud/Settings/ImageSettingsProvider.cs b/TagCloud/Settings/ImageSettingsProvider.cs new file mode 100644 index 00000000..e1bf9eaa --- /dev/null +++ b/TagCloud/Settings/ImageSettingsProvider.cs @@ -0,0 +1,6 @@ +namespace TagCloud.Settings; + +public class ImageSettingsProvider : IImageSettingsProvider +{ + public ImageSettings ImageSettings { get; set; } = null!; +} \ No newline at end of file diff --git a/TagCloud/Settings/Settings.cs b/TagCloud/Settings/Settings.cs deleted file mode 100644 index 846d27f0..00000000 --- a/TagCloud/Settings/Settings.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace TagCloud.Settings; - -public class Settings -{ - public string SourcePath { get; set; } - public int Width { get; set; } - public int Height { get; set; } - public string FontFamily { get; set; } - public string SavePath { get; set; } -} \ No newline at end of file diff --git a/TagCloud/Settings/SettingsProvider.cs b/TagCloud/Settings/SettingsProvider.cs deleted file mode 100644 index 1957cdc2..00000000 --- a/TagCloud/Settings/SettingsProvider.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TagCloud.Settings; - -public class SettingsProvider : ISettingsProvider -{ - private Settings _settings = new(); - - public Settings GetSettings() => - _settings; - - public void SetSettings(Settings settings) => - _settings = settings; -} \ No newline at end of file diff --git a/TagCloud/TagCloud.csproj b/TagCloud/TagCloud.csproj index 4557966b..6d6df06c 100644 --- a/TagCloud/TagCloud.csproj +++ b/TagCloud/TagCloud.csproj @@ -1,22 +1,16 @@  - Exe net8.0 enable enable + CA1416 - - - + + + - - - Always - - - - + \ No newline at end of file diff --git a/TagCloud/Program.cs b/TagCloud/TagCloudModule.cs similarity index 57% rename from TagCloud/Program.cs rename to TagCloud/TagCloudModule.cs index 775e98c6..516030d3 100644 --- a/TagCloud/Program.cs +++ b/TagCloud/TagCloudModule.cs @@ -1,5 +1,4 @@ using Autofac; -using TagCloud.Client; using TagCloud.CloudPainter; using TagCloud.Settings; using TagCloud.TagPositioner; @@ -10,27 +9,19 @@ namespace TagCloud; -class Program +public class TagCloudModule : Module { - static void Main() + protected override void Load(ContainerBuilder builder) { - var builder = new ContainerBuilder(); - builder.RegisterType(); builder.RegisterType().As(); builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As(); - builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As().SingleInstance(); + builder.RegisterType().As().SingleInstance(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); - - var container = builder.Build(); - - var app = container.Resolve(); - - app.Run(); } } \ No newline at end of file diff --git a/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs b/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs index bc15a20c..1fd83e1a 100644 --- a/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs +++ b/TagCloud/TagPositioner/Circular/CircularCloudLayouter.cs @@ -1,29 +1,24 @@ -using System.Drawing; +using System.Diagnostics.CodeAnalysis; +using System.Drawing; using TagCloud.Settings; namespace TagCloud.TagPositioner.Circular; -public class CircularCloudLayouter : ICloudLayouter +public class CircularCloudLayouter(IImageSettingsProvider imageSettingsProvider) : ICloudLayouter { - private readonly ISettingsProvider _settingsProvider; - private Point center; - private double angle; + private Point _center; + private double _angle; private const double SpiralStep = 0.2; - private double angleStep = 0.01; - - public CircularCloudLayouter(ISettingsProvider settingsProvider) - { - _settingsProvider = settingsProvider; - - } + private const double AngleStep = 0.01; public Rectangle PutNextRectangle(Size rectangleSize, ICollection rectangles) { - center = new Point(_settingsProvider.GetSettings().Width /2 , _settingsProvider.GetSettings().Height /2); + _center = new Point(imageSettingsProvider.ImageSettings.Width / 2, + imageSettingsProvider.ImageSettings.Height / 2); Rectangle newRectangle; if (!rectangles.Any()) { - var rectangle = new Rectangle(center, rectangleSize); + var rectangle = new Rectangle(_center, rectangleSize); rectangles.Add(rectangle); return rectangle; } @@ -32,20 +27,20 @@ public Rectangle PutNextRectangle(Size rectangleSize, ICollection rec { var location = GetLocation(rectangleSize); newRectangle = new Rectangle(location, rectangleSize); - } - while (rectangles.IsIntersecting(newRectangle)); + } while (rectangles.IsIntersecting(newRectangle)); rectangles.Add(newRectangle); return newRectangle; } + [SuppressMessage("ReSharper", "PossibleLossOfFraction")] private Point GetLocation(Size rectangleSize) { - var radius = SpiralStep * angle; - var x = (int)(center.X + radius * Math.Cos(angle) - rectangleSize.Width / 2); - var y = (int)(center.Y + radius * Math.Sin(angle) - rectangleSize.Height / 2); - angle += angleStep; + var radius = SpiralStep * _angle; + var x = (int)(_center.X + radius * Math.Cos(_angle) - rectangleSize.Width / 2); + var y = (int)(_center.Y + radius * Math.Sin(_angle) - rectangleSize.Height / 2); + _angle += AngleStep; return new Point(x, y); } diff --git a/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs b/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs index a86b6a1b..3d38e2ba 100644 --- a/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs +++ b/TagCloud/TagPositioner/Circular/CircularCloudLayouterExtensions.cs @@ -4,16 +4,6 @@ namespace TagCloud.TagPositioner.Circular; public static class CircularCloudLayouterExtensions { - public static Size GetBoundaryBox(this IList rectangles) - { - var minX = rectangles.Min(r => r.Left); - var minY = rectangles.Min(r => r.Top); - var maxX = rectangles.Max(r => r.Right); - var maxY = rectangles.Max(r => r.Bottom); - - return new Size(maxX - minX, maxY - minY); - } - public static bool IsIntersecting(this IEnumerable rectangles, Rectangle rectangle) => rectangles.Any(existingRectangle => existingRectangle.IntersectsWith(rectangle)); } \ No newline at end of file diff --git a/TagCloud/TagPositioner/TagPositioner.cs b/TagCloud/TagPositioner/TagPositioner.cs index 4d7943b2..04ff0482 100644 --- a/TagCloud/TagPositioner/TagPositioner.cs +++ b/TagCloud/TagPositioner/TagPositioner.cs @@ -5,39 +5,27 @@ namespace TagCloud.TagPositioner; -public class TagPositioner : ITagPositioner +public class TagPositioner(ICloudLayouter cloudLayouter, IImageSettingsProvider imageSettingsProvider) + : ITagPositioner { - private readonly ICloudLayouter _cloudLayouter; - private readonly ISettingsProvider _settingsProvider; - - public TagPositioner(ICloudLayouter cloudLayouter, ISettingsProvider settingsProvider) - { - _cloudLayouter = cloudLayouter; - _settingsProvider = settingsProvider; - } public List Position(List tags) { - var settings = _settingsProvider.GetSettings(); - var size = new Size(settings.Width, settings.Height); - var center = new Point(size.Width / 2, size.Height / 2); + var size = new Size(imageSettingsProvider.ImageSettings.Width, imageSettingsProvider.ImageSettings.Height); var bitmap = new Bitmap(size.Width, size.Height); - var graphics = Graphics.FromImage(bitmap); + using var graphics = Graphics.FromImage(bitmap); - var fontFamily = new FontFamily(settings.FontFamily); - var rectangels = new List(); + var fontFamily = new FontFamily(imageSettingsProvider.ImageSettings.FontFamily); + var rectangles = new List(); foreach (var tag in tags) { - var fontSize = 20; - var font = new Font(fontFamily, fontSize); + var font = new Font(fontFamily, tag.Weight); var textSize = graphics.MeasureString(tag.Word, font); - var res = _cloudLayouter.PutNextRectangle(new Size((int)textSize.Width, (int)textSize.Height), rectangels); + var res = cloudLayouter.PutNextRectangle(new Size((int)textSize.Width, (int)textSize.Height), rectangles); tag.Location = new Point(res.X, res.Y); } - graphics.Dispose(); - return tags; } } \ No newline at end of file diff --git a/TagCloud/WordCounter/ITagCreator.cs b/TagCloud/WordCounter/ITagCreator.cs new file mode 100644 index 00000000..4e20d916 --- /dev/null +++ b/TagCloud/WordCounter/ITagCreator.cs @@ -0,0 +1,6 @@ +namespace TagCloud.WordCounter; + +public interface ITagCreator +{ + List CreateTags(IEnumerable words); +} \ No newline at end of file diff --git a/TagCloud/WordCounter/IWordCounter.cs b/TagCloud/WordCounter/IWordCounter.cs deleted file mode 100644 index f38125c9..00000000 --- a/TagCloud/WordCounter/IWordCounter.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace TagCloud.WordCounter; - -public interface IWordCounter -{ - List CalculateWordCount(IEnumerable words); -} \ No newline at end of file diff --git a/TagCloud/WordCounter/Tag.cs b/TagCloud/WordCounter/Tag.cs index c47ec503..3992b752 100644 --- a/TagCloud/WordCounter/Tag.cs +++ b/TagCloud/WordCounter/Tag.cs @@ -6,5 +6,6 @@ public class Tag { public string Word { get; set; } = string.Empty; public int Count { get; set; } + public int Weight { get; set; } public Point Location { get; set; } } \ No newline at end of file diff --git a/TagCloud/WordCounter/TagCreator.cs b/TagCloud/WordCounter/TagCreator.cs new file mode 100644 index 00000000..038abd66 --- /dev/null +++ b/TagCloud/WordCounter/TagCreator.cs @@ -0,0 +1,30 @@ +using TagCloud.Settings; + +namespace TagCloud.WordCounter; + +public class TagCreator(IImageSettingsProvider imageSettingsProvider) : ITagCreator +{ + public List CreateTags(IEnumerable words) + { + var tags = words.GetCountInGroups() + .Select(x => + new Tag + { + Count = x.Count, + Word = x.Item + }) + .ToList(); + + var minCount = tags.Min(x => x.Count); + var maxCount = tags.Max(x => x.Count); + var minFontSize = imageSettingsProvider.ImageSettings.FontSizeMin; + var maxFontSize = imageSettingsProvider.ImageSettings.FontSizeMax; + + foreach (var tag in tags) + { + tag.Weight = (int)(minFontSize + (double)(tag.Count - minCount) / (maxCount - minCount) * (maxFontSize - minFontSize)); + } + + return tags; + } +} \ No newline at end of file diff --git a/TagCloud/WordCounter/WordCounter.cs b/TagCloud/WordCounter/WordCounter.cs deleted file mode 100644 index cf927540..00000000 --- a/TagCloud/WordCounter/WordCounter.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace TagCloud.WordCounter; - -public class WordCounter : IWordCounter -{ - public List CalculateWordCount(IEnumerable words) - { - //TODO: Добавить нормализацию или алгоритм нормализации. - return words.GroupBy(x => x) - .Select(x => new Tag(){ Word = x.Key, Count = x.Count() }) - .ToList(); - } -} \ No newline at end of file diff --git a/TagCloud/WordCounter/WordCounterExtensions.cs b/TagCloud/WordCounter/WordCounterExtensions.cs new file mode 100644 index 00000000..69d47432 --- /dev/null +++ b/TagCloud/WordCounter/WordCounterExtensions.cs @@ -0,0 +1,9 @@ +namespace TagCloud.WordCounter; + +public static class WordCounterExtensions +{ + public static IEnumerable<(T Item, int Count)> GetCountInGroups(this IEnumerable source) => + source + .GroupBy(x => x) + .Select(x => (x.Key, x.Count())); +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/DefaultBoringWordProvider.cs b/TagCloud/WordsProcessing/DefaultBoringWordProvider.cs deleted file mode 100644 index fdfcf578..00000000 --- a/TagCloud/WordsProcessing/DefaultBoringWordProvider.cs +++ /dev/null @@ -1,9 +0,0 @@ -namespace TagCloud.WordsProcessing; - -public class DefaultBoringWordProvider : IBoringWordProvider -{ - public string[] GetBoringWords() - { - return ["в", "на"]; - } -} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/FIleBoringWordsProvider.cs b/TagCloud/WordsProcessing/FIleBoringWordsProvider.cs new file mode 100644 index 00000000..13f0611c --- /dev/null +++ b/TagCloud/WordsProcessing/FIleBoringWordsProvider.cs @@ -0,0 +1,13 @@ +using TagCloud.Settings; +using TagCloud.WordsReader; + +namespace TagCloud.WordsProcessing; + +public class FIleBoringWordsProvider(IAppSettingsProvider appSettingsProvider, IWordsReader wordsReader) + : IBoringWordsProvider +{ + public string[] GetWords() => + string.IsNullOrEmpty(appSettingsProvider.AppSettings.BoringWordsPath) + ? [] + : wordsReader.Read(appSettingsProvider.AppSettings.BoringWordsPath); +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/IBoringWordProvider.cs b/TagCloud/WordsProcessing/IBoringWordProvider.cs deleted file mode 100644 index 27fbec7d..00000000 --- a/TagCloud/WordsProcessing/IBoringWordProvider.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace TagCloud.WordsProcessing; - -public interface IBoringWordProvider -{ - string[] GetBoringWords(); -} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/IBoringWordsProvider.cs b/TagCloud/WordsProcessing/IBoringWordsProvider.cs new file mode 100644 index 00000000..83fe6e4f --- /dev/null +++ b/TagCloud/WordsProcessing/IBoringWordsProvider.cs @@ -0,0 +1,6 @@ +namespace TagCloud.WordsProcessing; + +public interface IBoringWordsProvider +{ + string[] GetWords(); +} \ No newline at end of file diff --git a/TagCloud/WordsProcessing/IWordPreprocessor.cs b/TagCloud/WordsProcessing/IWordPreprocessor.cs index 2ad932c7..f7e0cf53 100644 --- a/TagCloud/WordsProcessing/IWordPreprocessor.cs +++ b/TagCloud/WordsProcessing/IWordPreprocessor.cs @@ -2,5 +2,5 @@ public interface IWordPreprocessor { - IEnumerable Process(); + string[] Process(); } \ No newline at end of file diff --git a/TagCloud/WordsProcessing/WordPreprocessor.cs b/TagCloud/WordsProcessing/WordPreprocessor.cs index 73a378e8..486e7d1b 100644 --- a/TagCloud/WordsProcessing/WordPreprocessor.cs +++ b/TagCloud/WordsProcessing/WordPreprocessor.cs @@ -3,23 +3,18 @@ namespace TagCloud.WordsProcessing; -public class WordPreprocessor : IWordPreprocessor +public class WordPreprocessor( + IBoringWordsProvider boringWordsProvider, + IWordsReader wordsReader, + IAppSettingsProvider appSettingsProvider) + : IWordPreprocessor { - private readonly IBoringWordProvider _boringWordProvider; - private readonly IWordsReader _wordsReader; - private readonly ISettingsProvider _settingsProvider; - - public WordPreprocessor(IBoringWordProvider boringWordProvider, IWordsReader wordsReader, ISettingsProvider settingsProvider) - { - _boringWordProvider = boringWordProvider; - _wordsReader = wordsReader; - _settingsProvider = settingsProvider; - } - public IEnumerable Process() + public string[] Process() { - var strings = _wordsReader.Read(_settingsProvider.GetSettings().SourcePath); - return strings + var boringWords = boringWordsProvider.GetWords(); + return wordsReader.Read(appSettingsProvider.AppSettings.SourcePath) .Select(x => x.ToLower()) - .Where(x => !_boringWordProvider.GetBoringWords().Contains(x)); + .Where(x => !boringWords.Contains(x)) + .ToArray(); } } \ No newline at end of file diff --git a/TagCloud/result.png b/TagCloud/result.png deleted file mode 100644 index 991f3a027ac43c9dd864fbb4d073cd15ab997d6d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6632 zcmeHL`Cn647QZj-h>(f}*-WI4=!mk3fMOC91sAkx3n(C46a-~U5s;8XTxb;%94kAd z4&zvhvMLY*1c-z%vWy}k!xAwx5rH5ukOV?9H*M!Hn9p>67~bdeKJRnyefPYxe81Vw{%CjijEs&8FwI5QZh9SI)@>4eu_P~L4h4hNbM9zGrbR54a5 zLbc#nFV6cE2>?T``bOGgeSHRp2gR?aRBz#j zJT-Lz$o>oq0O0@)j?EAh0K}Ea6^E>VVTA}QnPDX>{{K{j%5xQzrzz7fR09ptKIVFr zVmQ`iTA)hVflHoGj-0#|OR3$Xtm(=ST*MbuvsE1_s<&iWf>PPu1ti8P> zk#PeQU=H_aHM0-Xz@q`m^)MGhzdtS@4ppxlJe!AZa?x8JY+dJsBzTaAQe~13Avf*u zH88XZK~QX^BBtn~X@g%7z?;bq#4(XOSXKCcBH%d1N zkEQFz4til?OAFYfejyzUa5NlEwU@AOwc8~8XJ9Ub#_nV;?Fj#Tzk>Wa|^i|Zm z+W{G)_G05hFdz`m`}%-)KE_xOy|4*Ie3BJC-Y-TGJk&wGi#X0JuRrz!kFKaSa#@3| z4MHl{qcj2F>!Ja`LLUMeGz|d9|9CRQnbMFl%~mx;k}DhEkC+x>F5p!yBJNZ~?gDSHt|I`YpNhKdgSjUdX*`?dJV zvz#5rF`ML=;r%bFCNzk;Kgg>r(RMpAM+2SKllqyfa>tpU)5IGIz&G3!ODfae7ip=Q zP@<6v>QreEtteo>+q`V}r15gRzwP5|24brlydg1zHxo}**x$qrQ1qM4A(Z;+aRlDh zb-h>OB_sVh{A$uDDONX&OUglw4fQPT3g`u!VI2CB579FHERL$$sCB39>+X)HXb>eu za$xp8?EJ01IDwpLK`Vf6&U&E9Z)8m*#XBSkQje|99vu+z$h6KhDVb(4Sdmlb7j$_& zuu>Zc7srL%sFqh76^p=)EC{1?>hOnpwh_R{eh4+^5_9ayfIFA&$Vj2_7ip8_7F6+D z=bnbS*TAgY6bmLcK(mG8NP_tqHr}prYy9*xsLbeMLGU)XSb3Q_Skg5)nsbIoEq# zNuo;*Dtyr_7eypbjW=e<@}8Oe>T;ov7Jp_;^(QH&e06s3-(4;7C1g?PV4pCLe(gSB zB}v%R8A*8X2KM<-u7386e)D|~Xo>qS!<#cs5_*>oKX7Bws%$S|A3Zd%`lCiO35^BQ zKZK^oY5`gz{70BB8b0*5#4SufAf>Lpd8B5_B45J#R=#VavG>PC}6X0nv!lfUc@>HOLlF7sHn1?}C|hI_Dyi zV1JL9_e6l6la3`I|< zDT*VX_e2l5x#6C-ENT$lH{k2~qIfu6dU>$!br|=dBznn&E2UeDUmWCJf0M~JgN;4r&xEgM_UxYmpIPos6VaiiZ>oC|C?;c$U- zy5wC?k&FJd0SDIE$<|LSnL90s36Nw%Hb_a93L~pI-%NJn2%C7Jw(iGhMFRcAk;$K0 zN!om_t1=&YYXah|XB6vbs8Yyg<=eH-*g>y$96DryJr<0d%6o)&CLFluV1;!GsN`Kq zs9ck9-ru0dhCmCjA%Kz=ob>`{IqKW%+;7)WEZ#`0ZnL)e3++=fZ-@=ENoAjrOv1u; zuH9~Mh2^@-6e~SPDeq6!A&x46%UabUz5rTNax(yQ%ihikG049yk}#%Y6t zvzZ{Hc{uO%aew{mGf!;NE*S zc$Pj(hULnAro>VQaV&W*V30Q0lgLkeqGFC5X!Z!P%{q)adpTLE@$NSCtagPlcB#_U zFq`EtbEe}wEf5E@fmeHIm6c5yCPUm+z7|qk2U7fH{U_CUo<;7XGe-{OUi1Sxnz{tZ zyss(U&t0TJY)FrfT@4AG@w*=d)QRr+6{;4eE2ep6T{eRZ!!)+MgF92-gse*8f)v} z`Dl`(MrO~ZX8q2ureDct+05H>N+{V^@icC25JQm-P_97)WPCTiF! zljcE)z@dVVR@o1~tal`s2)3qRVHq+}O9-^WmIf!Kw#2p+DDZAg6~OG`R@iP#!2T+x zs}D(t*zppdl|A}wAT^k+75&e~j8G?KcRMUjZ+z4;VL2?Gv%6~dyzMFC_?dZzuuo(& zs49gi;a7c*8Dx9)df2n3q9#9rlqV_%+ACa|$qt7VaQJt}!pfo4%7NU where T : class +{ + protected T Sut { get; set; } + private object[] _constructorParameters; + + [SetUp] + public virtual void SetUp() + { + _constructorParameters = typeof(T) + .GetConstructors() + .First() + .GetParameters() + .Select(method => Substitute.For([method.ParameterType], null)) + .ToArray(); + Sut = Substitute.ForPartsOf(_constructorParameters); + } + + protected TInjectedService Mock() + { + var mock = _constructorParameters.FirstOrDefault(x => x is TInjectedService); + + if (mock == null) + throw new Exception($"Класс {nameof(TInjectedService)} не используется в классе {nameof(T)}"); + + return (TInjectedService)mock; + } +} \ No newline at end of file diff --git a/TagCloudTests/FileBoringWordsProviderTests.cs b/TagCloudTests/FileBoringWordsProviderTests.cs new file mode 100644 index 00000000..1881afde --- /dev/null +++ b/TagCloudTests/FileBoringWordsProviderTests.cs @@ -0,0 +1,21 @@ +using FluentAssertions; +using NSubstitute; +using TagCloud.WordsProcessing; +using TagCloud.WordsReader; + +namespace TagCloudTests; + +public class FileBoringWordsProviderTests : BaseTest +{ + [Test] + public void GetWords_ShouldBeNotNullOrEmpty() + { + Mock() + .Read(Arg.Any()) + .Returns(["some", "word"]); + + var strings = Sut.GetWords(); + + strings.Should().NotBeNullOrEmpty(); + } +} \ No newline at end of file diff --git a/TagCloudTests/Samples/BoringWords.txt b/TagCloudTests/Samples/BoringWords.txt new file mode 100644 index 00000000..8740704a --- /dev/null +++ b/TagCloudTests/Samples/BoringWords.txt @@ -0,0 +1,82 @@ +и +в +на +с +по +из +к +у +за +о +от +до +для +при +об +вокруг +над +под +между +без +вне +через +сквозь +как +что +где +когда +зачем +почему +кто +тот +это +этот +такой +весь +мой +твой +его +её +наш +ваш +их +себя +сам +что-то +кое-что +ничто +никто +нигде +никогда +всегда +тогда +сюда +туда +оттуда +здесь +там +всюду +везде +зачем-то +потому +почему-то +ну +ли +же +уж +ведь +либо +или +тоже +также +даже +лишь +едва +потом +затем +какой-то +такой-то +этакой +тот-то +этот-то +то есть \ No newline at end of file diff --git a/TagCloud/words.txt b/TagCloudTests/Samples/SampleWords.txt similarity index 100% rename from TagCloud/words.txt rename to TagCloudTests/Samples/SampleWords.txt diff --git a/TagCloudTests/TagCloudTest.cs b/TagCloudTests/TagCloudTest.cs new file mode 100644 index 00000000..f0442c52 --- /dev/null +++ b/TagCloudTests/TagCloudTest.cs @@ -0,0 +1,48 @@ +using Autofac; +using TagCloud; +using TagCloud.Settings; + +namespace TagCloudTests; + +[TestFixture] +public class TagCloudTest +{ + private IContainer _container; + + [SetUp] + public void SetUp() + { + var builder = new ContainerBuilder(); + builder.RegisterModule(new TagCloudModule()); + _container = builder.Build(); + } + + [TearDown] + public void TearDown() + { + _container.Dispose(); + } + + [Test] + public void Test() + { + _container.Resolve().ImageSettings = new ImageSettings + { + Width = 500, + Height = 500, + BackgroundColor = "red", + FontFamily = "Arial", + FontSizeMax = 40, + FontSizeMin = 10 + }; + _container.Resolve().AppSettings = new AppSettings + { + SourcePath = TestConstants.SamplesWordsTestFile, + SavePath = @"..\\..\..\test.png", + BoringWordsPath = TestConstants.BoringWordsTestFile + }; + + var app = _container.Resolve(); + app.Run(); + } +} \ No newline at end of file diff --git a/TagCloudTests/TagCloudTests.csproj b/TagCloudTests/TagCloudTests.csproj new file mode 100644 index 00000000..6eb0e70e --- /dev/null +++ b/TagCloudTests/TagCloudTests.csproj @@ -0,0 +1,39 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + + + + Always + + + Always + + + + diff --git a/TagCloudTests/TagCreatorTests.cs b/TagCloudTests/TagCreatorTests.cs new file mode 100644 index 00000000..290cb9d0 --- /dev/null +++ b/TagCloudTests/TagCreatorTests.cs @@ -0,0 +1,47 @@ +using FluentAssertions; +using NSubstitute; +using TagCloud.Settings; +using TagCloud.WordCounter; + +namespace TagCloudTests; + +[TestFixture] +public class TagCreatorTests : BaseTest +{ + public override void SetUp() + { + base.SetUp(); + Mock() + .ImageSettings + .Returns(new ImageSettings { FontSizeMax = 40, FontSizeMin = 10 }); + } + + [Test] + public void CreateTags_ShouldReturnEmptyList_WhenNoWordsProvided() + { + var words = Enumerable.Empty(); + var tags = Sut.CreateTags(words); + tags.Should().BeNullOrEmpty(); + } + + [Test] + public void CreateTags_ShouldCalculateTagWeightsCorrectly() + { + var words = new[] + { "apple", "banana", "apple", "cherry", "banana", "banana" }; // apple: 2, banana: 3, cherry: 1 + var tags = Sut.CreateTags(words); + + tags.Count.Should().Be(3); + var appleTag = tags.Single(t => t.Word == "apple"); + var bananaTag = tags.Single(t => t.Word == "banana"); + var cherryTag = tags.Single(t => t.Word == "cherry"); + + appleTag.Count.Should().Be(2); + bananaTag.Count.Should().Be(3); + cherryTag.Count.Should().Be(1); + + cherryTag.Weight.Should().Be(10); + bananaTag.Weight.Should().Be(40); + cherryTag.Weight.Should().BeGreaterThan(10).And.BeLessThan(40); + } +} \ No newline at end of file diff --git a/TagCloudTests/TestConstants.cs b/TagCloudTests/TestConstants.cs new file mode 100644 index 00000000..81fc0708 --- /dev/null +++ b/TagCloudTests/TestConstants.cs @@ -0,0 +1,7 @@ +namespace TagCloudTests; + +public static class TestConstants +{ + public const string SamplesWordsTestFile = "Samples\\SampleWords.txt"; + public const string BoringWordsTestFile = "Samples\\BoringWords.txt"; +} \ No newline at end of file diff --git a/TagCloudTests/TxtWordsReaderTests.cs b/TagCloudTests/TxtWordsReaderTests.cs new file mode 100644 index 00000000..e05ffa88 --- /dev/null +++ b/TagCloudTests/TxtWordsReaderTests.cs @@ -0,0 +1,28 @@ +using FluentAssertions; +using TagCloud.WordsReader; + +namespace TagCloudTests; + +[TestFixture] +public class TxtWordsReaderTests +{ + private TxtWordsReader _txtWordsReader; + + [SetUp] + public void SetUp() => + _txtWordsReader = new TxtWordsReader(); + + [Test] + public void Read_ShouldNotBeNullOrEmpty() + { + var words = _txtWordsReader.Read(TestConstants.SamplesWordsTestFile); + words.Should().NotBeNullOrEmpty(); + } + + [Test] + public void Read_ShouldThrowExceptionIfFileDoesNotExist() + { + var act = () => _txtWordsReader.Read(""); + act.Should().Throw(); + } +} \ No newline at end of file diff --git a/TagCloudTests/WordPreprocessorTests.cs b/TagCloudTests/WordPreprocessorTests.cs new file mode 100644 index 00000000..878a4046 --- /dev/null +++ b/TagCloudTests/WordPreprocessorTests.cs @@ -0,0 +1,49 @@ +using FluentAssertions; +using NSubstitute; +using TagCloud.Settings; +using TagCloud.WordsProcessing; +using TagCloud.WordsReader; + +namespace TagCloudTests; + +public class WordPreprocessorTests : BaseTest +{ + [SetUp] + public override void SetUp() + { + base.SetUp(); + + Mock() + .AppSettings + .Returns(new AppSettings()); + } + + [Test] + public void Process_WordsShouldFilter() + { + Mock() + .GetWords() + .Returns(["в", "на"]); + Mock() + .Read(Arg.Any()) + .Returns(["в", "на", "привет"]); + + var processedWords = Sut.Process(); + + processedWords.Should().NotBeNullOrEmpty(); + processedWords.Length.Should().Be(1); + processedWords.First().Should().Be("привет"); + } + + [Test] + public void Process_WordsShouldBeLowercase() + { + Mock() + .Read(Arg.Any()) + .Returns(["ПРИВЕТ"]); + + var processedWords = Sut.Process(); + + processedWords.First().Should().Be("привет"); + } +} \ No newline at end of file diff --git a/TagCloudTests/test.png b/TagCloudTests/test.png new file mode 100644 index 0000000000000000000000000000000000000000..36d8405074be51c473c552f0d62b842f06f41ffd GIT binary patch literal 4449 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 Date: Sat, 28 Dec 2024 13:45:50 +0500 Subject: [PATCH 3/4] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=B8=D0=BB?= =?UTF-8?q?=20imageSaver?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- TagCloud/CloudPainter/CloudPainter.cs | 4 +++- TagCloud/CloudPainter/IImageSaver.cs | 8 ++++++++ TagCloud/CloudPainter/PngImageSaver.cs | 13 +++++++++++++ TagCloud/TagCloudModule.cs | 1 + 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 TagCloud/CloudPainter/IImageSaver.cs create mode 100644 TagCloud/CloudPainter/PngImageSaver.cs diff --git a/TagCloud/CloudPainter/CloudPainter.cs b/TagCloud/CloudPainter/CloudPainter.cs index 568934ae..7432159d 100644 --- a/TagCloud/CloudPainter/CloudPainter.cs +++ b/TagCloud/CloudPainter/CloudPainter.cs @@ -4,7 +4,9 @@ namespace TagCloud.CloudPainter; -public class CloudPainter(IImageSettingsProvider imageSettingsProvider, IAppSettingsProvider appSettingsProvider) +internal class CloudPainter(IImageSettingsProvider imageSettingsProvider, + IAppSettingsProvider appSettingsProvider, + IImageSaver imageSaver) : ICloudPainter { public void Paint(Tag[] tags) diff --git a/TagCloud/CloudPainter/IImageSaver.cs b/TagCloud/CloudPainter/IImageSaver.cs new file mode 100644 index 00000000..1dfc5c52 --- /dev/null +++ b/TagCloud/CloudPainter/IImageSaver.cs @@ -0,0 +1,8 @@ +using System.Drawing; + +namespace TagCloud.CloudPainter; + +internal interface IImageSaver +{ + void SaveImage(Bitmap image, string fullFileName); +} \ No newline at end of file diff --git a/TagCloud/CloudPainter/PngImageSaver.cs b/TagCloud/CloudPainter/PngImageSaver.cs new file mode 100644 index 00000000..1d54fbf1 --- /dev/null +++ b/TagCloud/CloudPainter/PngImageSaver.cs @@ -0,0 +1,13 @@ +using System.Drawing; +using System.Drawing.Imaging; + +namespace TagCloud.CloudPainter; + +internal class PngImageSaver : IImageSaver +{ + public void SaveImage(Bitmap image, string fullFileName) + { + image.Save(fullFileName, ImageFormat.Png); + image.Dispose(); + } +} \ No newline at end of file diff --git a/TagCloud/TagCloudModule.cs b/TagCloud/TagCloudModule.cs index 516030d3..2c882b01 100644 --- a/TagCloud/TagCloudModule.cs +++ b/TagCloud/TagCloudModule.cs @@ -21,6 +21,7 @@ protected override void Load(ContainerBuilder builder) builder.RegisterType().As().SingleInstance(); builder.RegisterType().As().SingleInstance(); builder.RegisterType().As(); + builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); } From 7d9c851e3764c7def3754a6f2de3877c0fa711cc Mon Sep 17 00:00:00 2001 From: "kashin.aleksandr" Date: Sat, 28 Dec 2024 13:46:40 +0500 Subject: [PATCH 4/4] =?UTF-8?q?=D0=9F=D0=B5=D1=80=D0=B5=D1=80=D0=B0=D0=B1?= =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=20=D0=BD=D0=B0=D1=81=D1=82=D1=80=D0=BE?= =?UTF-8?q?=D0=B5=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ConsoleClient/ConsoleClient.cs | 6 ++-- ConsoleClient/Program.cs | 2 -- ConsoleClient/Settings/ConsoleSettings.cs | 20 ++++++++++++ .../Settings/ConsoleSettingsManager.cs | 29 ------------------ ConsoleClient/Settings/ISettingsManager.cs | 6 ---- GuiClient/Forms/MainForm.cs | 9 +++--- GuiClient/Forms/ResultForm.cs | 14 ++++----- TagCloud/App.cs | 23 ++++++++++++-- TagCloud/CloudPainter/CloudPainter.cs | 9 ++++-- TagCloud/CloudPainter/ICloudPainter.cs | 2 +- TagCloud/IApp.cs | 8 +++++ TagCloud/Settings/AppSettings.cs | 8 ++--- TagCloud/Settings/AppSettingsProvider.cs | 2 +- TagCloud/Settings/ImageSettings.cs | 6 ++-- TagCloud/Settings/ImageSettingsProvider.cs | 2 +- TagCloud/TagCloud.csproj | 4 +++ TagCloud/TagCloudModule.cs | 2 +- TagCloud/TagPositioner/TagPositioner.cs | 2 +- TagCloud/WordCounter/TagCreator.cs | 3 ++ TagCloud/WordsProcessing/IWordPreprocessor.cs | 2 +- TagCloud/WordsProcessing/WordPreprocessor.cs | 5 ++- TagCloudTests/FileBoringWordsProviderTests.cs | 18 ++++++++++- TagCloudTests/TagCloudTest.cs | 12 +++----- TagCloudTests/TagCloudTests.csproj | 2 +- TagCloudTests/TagCreatorTests.cs | 2 +- TagCloudTests/WordPreprocessorTests.cs | 4 +-- TagCloudTests/test.png | Bin 4449 -> 4438 bytes 27 files changed, 117 insertions(+), 85 deletions(-) delete mode 100644 ConsoleClient/Settings/ConsoleSettingsManager.cs delete mode 100644 ConsoleClient/Settings/ISettingsManager.cs create mode 100644 TagCloud/IApp.cs diff --git a/ConsoleClient/ConsoleClient.cs b/ConsoleClient/ConsoleClient.cs index 3b1d4d19..f8079878 100644 --- a/ConsoleClient/ConsoleClient.cs +++ b/ConsoleClient/ConsoleClient.cs @@ -5,12 +5,12 @@ namespace ConsoleClient; -public class ConsoleClient(App app, ISettingsManager settingsManager) : IClient +public class ConsoleClient(IApp app) : IClient { public void Run() { Parser.Default.ParseArguments(Environment.GetCommandLineArgs()) - .WithParsed(settingsManager.Set); - app.Run(); + .WithParsed(settings => app.Run(settings.GetAppSettings(), settings.GetImageSettings())) + .WithNotParsed(_ => throw new ArgumentException("Invalid command line arguments")); } } \ No newline at end of file diff --git a/ConsoleClient/Program.cs b/ConsoleClient/Program.cs index 6972d81a..8a26a9b9 100644 --- a/ConsoleClient/Program.cs +++ b/ConsoleClient/Program.cs @@ -1,5 +1,4 @@ using Autofac; -using ConsoleClient.Settings; using TagCloud; using TagCloud.Client; @@ -12,7 +11,6 @@ static void Main() var builder = new ContainerBuilder(); builder.RegisterModule(new TagCloudModule()); builder.RegisterType().As(); - builder.RegisterType().As(); var container = builder.Build(); var app = container.Resolve(); diff --git a/ConsoleClient/Settings/ConsoleSettings.cs b/ConsoleClient/Settings/ConsoleSettings.cs index d1b0fb19..16ef165c 100644 --- a/ConsoleClient/Settings/ConsoleSettings.cs +++ b/ConsoleClient/Settings/ConsoleSettings.cs @@ -1,4 +1,5 @@ using CommandLine; +using TagCloud.Settings; namespace ConsoleClient.Settings; @@ -30,4 +31,23 @@ public class ConsoleSettings [Option("maxFont", Default = 40, HelpText = "Максимальный шрифт.")] public int FontSizeMax { get; set; } + + public AppSettings GetAppSettings() => + new() + { + SourcePath = SourcePath, + SavePath = SavePath, + BoringWordsPath = BoringWordsPath + }; + + public ImageSettings GetImageSettings() => + new() + { + Width = Width, + Height = Height, + BackgroundColor = BackgroundColor, + FontFamily = FontFamily, + FontSizeMax = FontSizeMax, + FontSizeMin = FontSizeMin + }; } \ No newline at end of file diff --git a/ConsoleClient/Settings/ConsoleSettingsManager.cs b/ConsoleClient/Settings/ConsoleSettingsManager.cs deleted file mode 100644 index 8d6d3c7e..00000000 --- a/ConsoleClient/Settings/ConsoleSettingsManager.cs +++ /dev/null @@ -1,29 +0,0 @@ -using TagCloud.Settings; - -namespace ConsoleClient.Settings; - -public class ConsoleSettingsManager( - IImageSettingsProvider imageSettingsProvider, - IAppSettingsProvider appSettingsProvider) - : ISettingsManager -{ - public void Set(ConsoleSettings settings) - { - imageSettingsProvider.ImageSettings = new ImageSettings - { - Width = settings.Width, - Height = settings.Height, - BackgroundColor = settings.BackgroundColor, - FontFamily = settings.FontFamily, - FontSizeMax = settings.FontSizeMax, - FontSizeMin = settings.FontSizeMin, - }; - - appSettingsProvider.AppSettings = new AppSettings - { - SourcePath = settings.SourcePath, - SavePath = settings.SavePath, - BoringWordsPath = settings.BoringWordsPath - }; - } -} \ No newline at end of file diff --git a/ConsoleClient/Settings/ISettingsManager.cs b/ConsoleClient/Settings/ISettingsManager.cs deleted file mode 100644 index a41dc035..00000000 --- a/ConsoleClient/Settings/ISettingsManager.cs +++ /dev/null @@ -1,6 +0,0 @@ -namespace ConsoleClient.Settings; - -public interface ISettingsManager -{ - void Set(ConsoleSettings settings); -} \ No newline at end of file diff --git a/GuiClient/Forms/MainForm.cs b/GuiClient/Forms/MainForm.cs index c45e443b..25e9cd1a 100644 --- a/GuiClient/Forms/MainForm.cs +++ b/GuiClient/Forms/MainForm.cs @@ -177,8 +177,7 @@ private void AddGenerateButton() private void GenerateButton_Click(object sender, EventArgs e) { - _lifetimeScope.Resolve() - .ImageSettings = new ImageSettings + var imageSettings = new ImageSettings { Width = (int)_widthInput!.Value, Height = (int)_heightInput!.Value, @@ -187,15 +186,15 @@ private void GenerateButton_Click(object sender, EventArgs e) FontSizeMax = (int)_minFontSizeInput!.Value, FontSizeMin = (int)_maxFontSizeInput!.Value }; - _lifetimeScope.Resolve() - .AppSettings = new AppSettings + + var appSettings = new AppSettings { SourcePath = _sourceFilePath, BoringWordsPath = _boringWordsFilePath, SavePath = "output.png" }; - var resultForm = new ResultForm(_lifetimeScope, this); + var resultForm = new ResultForm(this, _lifetimeScope, appSettings, imageSettings); resultForm.Show(); Hide(); } diff --git a/GuiClient/Forms/ResultForm.cs b/GuiClient/Forms/ResultForm.cs index b17e82c6..a1d5df33 100644 --- a/GuiClient/Forms/ResultForm.cs +++ b/GuiClient/Forms/ResultForm.cs @@ -8,15 +8,14 @@ public class ResultForm : Form { private readonly ILifetimeScope _lifetimeScope; - public ResultForm(ILifetimeScope lifetimeScope, Form mainForm) + public ResultForm(Form mainForm, ILifetimeScope lifetimeScope, AppSettings appSettings, ImageSettings imageSettings) { _lifetimeScope = lifetimeScope; using var scope = _lifetimeScope.BeginLifetimeScope(); - var imageSettingsProvider = scope.Resolve(); Text = "Результат"; - Size = new Size(imageSettingsProvider.ImageSettings.Width, imageSettingsProvider.ImageSettings.Height + 70); + Size = new Size(imageSettings.Width, imageSettings.Height + 70); FormBorderStyle = FormBorderStyle.FixedDialog; MaximizeBox = false; MinimizeBox = false; @@ -29,18 +28,17 @@ public ResultForm(ILifetimeScope lifetimeScope, Form mainForm) Close(); }; - ShowCloudImage(); + ShowCloudImage(appSettings, imageSettings); Controls.Add(regenerateButton); } - private void ShowCloudImage() + private void ShowCloudImage(AppSettings appSettings, ImageSettings imageSettings) { - _lifetimeScope.Resolve().Run(); - var appSettingsProvider = _lifetimeScope.Resolve(); + _lifetimeScope.Resolve().Run(appSettings, imageSettings); var picture = new PictureBox { SizeMode = PictureBoxSizeMode.AutoSize, - ImageLocation = appSettingsProvider.AppSettings.SavePath, + ImageLocation = appSettings.SavePath, Dock = DockStyle.Top, }; picture.Load(); diff --git a/TagCloud/App.cs b/TagCloud/App.cs index 158d87b9..02ec0ec7 100644 --- a/TagCloud/App.cs +++ b/TagCloud/App.cs @@ -1,21 +1,38 @@ using TagCloud.CloudPainter; +using TagCloud.Settings; using TagCloud.TagPositioner; using TagCloud.WordCounter; using TagCloud.WordsProcessing; namespace TagCloud; -public class App( +internal class App( IWordPreprocessor wordPreprocessor, ITagCreator tagCreator, ICloudPainter cloudPainter, - ITagPositioner tagPositioner) + ITagPositioner tagPositioner, + IImageSettingsProvider imageSettingsProvider, + IAppSettingsProvider appSettingsProvider) +: IApp { - public void Run() + public void Run(AppSettings appSettings, ImageSettings imageSettings) { + ValidateAppSettings(appSettings); + imageSettingsProvider.ImageSettings = imageSettings; + appSettingsProvider.AppSettings = appSettings; + var words = wordPreprocessor.Process().ToArray(); var tags = tagCreator.CreateTags(words); tags = tagPositioner.Position(tags); cloudPainter.Paint(tags.ToArray()); } + + private void ValidateAppSettings(AppSettings appSettings) + { + if(string.IsNullOrEmpty(appSettings.SavePath)) + throw new ArgumentException("SavePath is required"); + + if(string.IsNullOrEmpty(appSettings.SourcePath)) + throw new ArgumentException("SourcePath is required"); + } } \ No newline at end of file diff --git a/TagCloud/CloudPainter/CloudPainter.cs b/TagCloud/CloudPainter/CloudPainter.cs index 7432159d..27ef2245 100644 --- a/TagCloud/CloudPainter/CloudPainter.cs +++ b/TagCloud/CloudPainter/CloudPainter.cs @@ -14,8 +14,8 @@ public void Paint(Tag[] tags) using var bitmap = new Bitmap(imageSettingsProvider.ImageSettings.Width, imageSettingsProvider.ImageSettings.Height); using var graphics = Graphics.FromImage(bitmap); - graphics.Clear(Color.FromName(imageSettingsProvider.ImageSettings.BackgroundColor)); - var fontFamily = new FontFamily(imageSettingsProvider.ImageSettings.FontFamily); + graphics.Clear(Color.FromName(imageSettingsProvider.ImageSettings.BackgroundColor ?? "white")); + var fontFamily = new FontFamily(imageSettingsProvider.ImageSettings.FontFamily ?? "arial"); var random = new Random(); foreach (var tag in tags) @@ -26,6 +26,9 @@ public void Paint(Tag[] tags) graphics.DrawString(tag.Word, font, brush, tag.Location); } - bitmap.Save(appSettingsProvider.AppSettings.SavePath, System.Drawing.Imaging.ImageFormat.Png); + if(string.IsNullOrEmpty(appSettingsProvider.AppSettings.SavePath)) + throw new ArgumentException("Save path is required"); + + imageSaver.SaveImage(bitmap, appSettingsProvider.AppSettings.SavePath); } } \ No newline at end of file diff --git a/TagCloud/CloudPainter/ICloudPainter.cs b/TagCloud/CloudPainter/ICloudPainter.cs index c40e928c..3fa9600c 100644 --- a/TagCloud/CloudPainter/ICloudPainter.cs +++ b/TagCloud/CloudPainter/ICloudPainter.cs @@ -2,7 +2,7 @@ namespace TagCloud.CloudPainter; -public interface ICloudPainter +internal interface ICloudPainter { void Paint(Tag[] tags); } \ No newline at end of file diff --git a/TagCloud/IApp.cs b/TagCloud/IApp.cs new file mode 100644 index 00000000..56abfc18 --- /dev/null +++ b/TagCloud/IApp.cs @@ -0,0 +1,8 @@ +using TagCloud.Settings; + +namespace TagCloud; + +public interface IApp +{ + void Run(AppSettings appSettings, ImageSettings imageSettings); +} \ No newline at end of file diff --git a/TagCloud/Settings/AppSettings.cs b/TagCloud/Settings/AppSettings.cs index 385c7d8e..659ee904 100644 --- a/TagCloud/Settings/AppSettings.cs +++ b/TagCloud/Settings/AppSettings.cs @@ -1,8 +1,8 @@ namespace TagCloud.Settings; -public class AppSettings +public record AppSettings { - public string SourcePath { get; init; } = string.Empty; - public string SavePath { get; init; } = "output.png"; - public string BoringWordsPath { get; init; } = string.Empty; + public string? SourcePath { get; init; } + public string? SavePath { get; init; } + public string? BoringWordsPath { get; init; } } \ No newline at end of file diff --git a/TagCloud/Settings/AppSettingsProvider.cs b/TagCloud/Settings/AppSettingsProvider.cs index 729bb967..dca77924 100644 --- a/TagCloud/Settings/AppSettingsProvider.cs +++ b/TagCloud/Settings/AppSettingsProvider.cs @@ -1,6 +1,6 @@ namespace TagCloud.Settings; -public class AppSettingsProvider : IAppSettingsProvider +internal class AppSettingsProvider : IAppSettingsProvider { public AppSettings AppSettings { get; set; } = null!; } \ No newline at end of file diff --git a/TagCloud/Settings/ImageSettings.cs b/TagCloud/Settings/ImageSettings.cs index 219ad460..7a3488f0 100644 --- a/TagCloud/Settings/ImageSettings.cs +++ b/TagCloud/Settings/ImageSettings.cs @@ -1,11 +1,11 @@ namespace TagCloud.Settings; -public class ImageSettings +public record ImageSettings { public int Width { get; init; } public int Height { get; init; } - public string BackgroundColor { get; init; } = string.Empty; - public string FontFamily { get; init; } = string.Empty; + public string? BackgroundColor { get; init; } + public string? FontFamily { get; init; } public int FontSizeMax { get; init; } public int FontSizeMin { get; init; } } \ No newline at end of file diff --git a/TagCloud/Settings/ImageSettingsProvider.cs b/TagCloud/Settings/ImageSettingsProvider.cs index e1bf9eaa..e0b82f55 100644 --- a/TagCloud/Settings/ImageSettingsProvider.cs +++ b/TagCloud/Settings/ImageSettingsProvider.cs @@ -1,6 +1,6 @@ namespace TagCloud.Settings; -public class ImageSettingsProvider : IImageSettingsProvider +internal class ImageSettingsProvider : IImageSettingsProvider { public ImageSettings ImageSettings { get; set; } = null!; } \ No newline at end of file diff --git a/TagCloud/TagCloud.csproj b/TagCloud/TagCloud.csproj index 6d6df06c..410f99a1 100644 --- a/TagCloud/TagCloud.csproj +++ b/TagCloud/TagCloud.csproj @@ -12,5 +12,9 @@ + + + + \ No newline at end of file diff --git a/TagCloud/TagCloudModule.cs b/TagCloud/TagCloudModule.cs index 2c882b01..eb4038e4 100644 --- a/TagCloud/TagCloudModule.cs +++ b/TagCloud/TagCloudModule.cs @@ -13,7 +13,7 @@ public class TagCloudModule : Module { protected override void Load(ContainerBuilder builder) { - builder.RegisterType(); + builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); builder.RegisterType().As(); diff --git a/TagCloud/TagPositioner/TagPositioner.cs b/TagCloud/TagPositioner/TagPositioner.cs index 04ff0482..66a4a421 100644 --- a/TagCloud/TagPositioner/TagPositioner.cs +++ b/TagCloud/TagPositioner/TagPositioner.cs @@ -14,7 +14,7 @@ public List Position(List tags) var bitmap = new Bitmap(size.Width, size.Height); using var graphics = Graphics.FromImage(bitmap); - var fontFamily = new FontFamily(imageSettingsProvider.ImageSettings.FontFamily); + var fontFamily = new FontFamily(imageSettingsProvider.ImageSettings.FontFamily ?? "Arial"); var rectangles = new List(); foreach (var tag in tags) diff --git a/TagCloud/WordCounter/TagCreator.cs b/TagCloud/WordCounter/TagCreator.cs index 038abd66..344565fc 100644 --- a/TagCloud/WordCounter/TagCreator.cs +++ b/TagCloud/WordCounter/TagCreator.cs @@ -6,6 +6,9 @@ public class TagCreator(IImageSettingsProvider imageSettingsProvider) : ITagCrea { public List CreateTags(IEnumerable words) { + if (!words.Any()) + return [..Array.Empty()]; + var tags = words.GetCountInGroups() .Select(x => new Tag diff --git a/TagCloud/WordsProcessing/IWordPreprocessor.cs b/TagCloud/WordsProcessing/IWordPreprocessor.cs index f7e0cf53..825a0080 100644 --- a/TagCloud/WordsProcessing/IWordPreprocessor.cs +++ b/TagCloud/WordsProcessing/IWordPreprocessor.cs @@ -1,6 +1,6 @@ namespace TagCloud.WordsProcessing; -public interface IWordPreprocessor +internal interface IWordPreprocessor { string[] Process(); } \ No newline at end of file diff --git a/TagCloud/WordsProcessing/WordPreprocessor.cs b/TagCloud/WordsProcessing/WordPreprocessor.cs index 486e7d1b..295e6f81 100644 --- a/TagCloud/WordsProcessing/WordPreprocessor.cs +++ b/TagCloud/WordsProcessing/WordPreprocessor.cs @@ -3,7 +3,7 @@ namespace TagCloud.WordsProcessing; -public class WordPreprocessor( +internal class WordPreprocessor( IBoringWordsProvider boringWordsProvider, IWordsReader wordsReader, IAppSettingsProvider appSettingsProvider) @@ -11,6 +11,9 @@ public class WordPreprocessor( { public string[] Process() { + if (appSettingsProvider.AppSettings.SourcePath == null) + throw new ArgumentException("Source path is required"); + var boringWords = boringWordsProvider.GetWords(); return wordsReader.Read(appSettingsProvider.AppSettings.SourcePath) .Select(x => x.ToLower()) diff --git a/TagCloudTests/FileBoringWordsProviderTests.cs b/TagCloudTests/FileBoringWordsProviderTests.cs index 1881afde..bc8cea8a 100644 --- a/TagCloudTests/FileBoringWordsProviderTests.cs +++ b/TagCloudTests/FileBoringWordsProviderTests.cs @@ -1,5 +1,6 @@ using FluentAssertions; using NSubstitute; +using TagCloud.Settings; using TagCloud.WordsProcessing; using TagCloud.WordsReader; @@ -8,8 +9,11 @@ namespace TagCloudTests; public class FileBoringWordsProviderTests : BaseTest { [Test] - public void GetWords_ShouldBeNotNullOrEmpty() + public void GetWords_ShouldBeNotNullOrEmpty_WhenPathIsNotEmpty() { + Mock() + .AppSettings + .Returns(new AppSettings {BoringWordsPath = "SomePath"}); Mock() .Read(Arg.Any()) .Returns(["some", "word"]); @@ -18,4 +22,16 @@ public void GetWords_ShouldBeNotNullOrEmpty() strings.Should().NotBeNullOrEmpty(); } + + [Test] + public void GetWords_ShouldBeEmpty_WhenPathIsNull() + { + Mock() + .AppSettings + .Returns(new AppSettings()); + + var strings = Sut.GetWords(); + + strings.Should().BeEmpty(); + } } \ No newline at end of file diff --git a/TagCloudTests/TagCloudTest.cs b/TagCloudTests/TagCloudTest.cs index f0442c52..61a19141 100644 --- a/TagCloudTests/TagCloudTest.cs +++ b/TagCloudTests/TagCloudTest.cs @@ -18,15 +18,13 @@ public void SetUp() } [TearDown] - public void TearDown() - { + public void TearDown() => _container.Dispose(); - } [Test] public void Test() { - _container.Resolve().ImageSettings = new ImageSettings + var imageSettings = new ImageSettings { Width = 500, Height = 500, @@ -35,14 +33,14 @@ public void Test() FontSizeMax = 40, FontSizeMin = 10 }; - _container.Resolve().AppSettings = new AppSettings + var appSettings = new AppSettings { SourcePath = TestConstants.SamplesWordsTestFile, SavePath = @"..\\..\..\test.png", BoringWordsPath = TestConstants.BoringWordsTestFile }; - var app = _container.Resolve(); - app.Run(); + var app = _container.Resolve(); + app.Run(appSettings, imageSettings); } } \ No newline at end of file diff --git a/TagCloudTests/TagCloudTests.csproj b/TagCloudTests/TagCloudTests.csproj index 6eb0e70e..cb4cc093 100644 --- a/TagCloudTests/TagCloudTests.csproj +++ b/TagCloudTests/TagCloudTests.csproj @@ -36,4 +36,4 @@ - + \ No newline at end of file diff --git a/TagCloudTests/TagCreatorTests.cs b/TagCloudTests/TagCreatorTests.cs index 290cb9d0..eaa94158 100644 --- a/TagCloudTests/TagCreatorTests.cs +++ b/TagCloudTests/TagCreatorTests.cs @@ -42,6 +42,6 @@ public void CreateTags_ShouldCalculateTagWeightsCorrectly() cherryTag.Weight.Should().Be(10); bananaTag.Weight.Should().Be(40); - cherryTag.Weight.Should().BeGreaterThan(10).And.BeLessThan(40); + appleTag.Weight.Should().BeGreaterThan(10).And.BeLessThan(40); } } \ No newline at end of file diff --git a/TagCloudTests/WordPreprocessorTests.cs b/TagCloudTests/WordPreprocessorTests.cs index 878a4046..12b0edcc 100644 --- a/TagCloudTests/WordPreprocessorTests.cs +++ b/TagCloudTests/WordPreprocessorTests.cs @@ -6,7 +6,7 @@ namespace TagCloudTests; -public class WordPreprocessorTests : BaseTest +internal class WordPreprocessorTests : BaseTest { [SetUp] public override void SetUp() @@ -15,7 +15,7 @@ public override void SetUp() Mock() .AppSettings - .Returns(new AppSettings()); + .Returns(new AppSettings { SourcePath = "Path" }); } [Test] diff --git a/TagCloudTests/test.png b/TagCloudTests/test.png index 36d8405074be51c473c552f0d62b842f06f41ffd..f59be397ec52b02fc8e42397e844c4a7af20201f 100644 GIT binary patch delta 2625 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 W)%%UNOnjrWa>Bkl9NO}20{LGaRfF*W