// // Copyright (c) PlaceholderCompany. All rights reserved. // namespace SystemTrayMenu.DataClasses { using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Media; using System.Windows.Media.Imaging; using SystemTrayMenu.Helpers; using SystemTrayMenu.Properties; using SystemTrayMenu.UserInterface; using SystemTrayMenu.Utilities; internal class RowData : INotifyPropertyChanged { private Brush? backgroundBrush; private Brush? borderBrush; private ImageSource? columnIcon; private string? columnText; private bool isSelected; /// /// Initializes a new instance of the class. /// (Related replace "\x00" see #171.) /// /// Flag if file or folder. /// Flag if additional item, from other folder than root folder. /// The number of the menu level. /// Path to item. internal RowData(bool isFolder, bool isAdditionalItem, int level, string path) { IsFolder = isFolder; IsAdditionalItem = isAdditionalItem; Level = level; FileInfo = new FileInfo(path.Replace("\x00", string.Empty)); Path = isFolder ? $@"{FileInfo.FullName}\" : FileInfo.FullName; FileExtension = System.IO.Path.GetExtension(Path) ?? string.Empty; if (FileExtension.Equals(".lnk", StringComparison.InvariantCultureIgnoreCase)) { ResolvedPath = FileLnk.GetResolvedFileName(Path, out bool isLinkToFolder); ShowOverlay = Settings.Default.ShowLinkOverlay; ColumnText = System.IO.Path.GetFileNameWithoutExtension(Path); if (Settings.Default.ResolveLinksToFolders) { IsPointingToFolder |= isLinkToFolder || FileLnk.IsNetworkRoot(ResolvedPath); } } else { ResolvedPath = Path; if (string.IsNullOrEmpty(FileInfo.Name)) { int nameBegin = FileInfo.FullName.LastIndexOf(@"\", StringComparison.InvariantCulture) + 1; ColumnText = FileInfo.FullName[nameBegin..]; } else if (FileExtension.Equals(".url", StringComparison.InvariantCultureIgnoreCase) || FileExtension.Equals(".appref-ms", StringComparison.InvariantCultureIgnoreCase)) { ShowOverlay = Settings.Default.ShowLinkOverlay; ColumnText = System.IO.Path.GetFileNameWithoutExtension(FileInfo.Name); } else if (!isFolder && Config.IsHideFileExtension()) { ColumnText = System.IO.Path.GetFileNameWithoutExtension(FileInfo.Name); } else { ColumnText = FileInfo.Name; } } IsPointingToFolder |= isFolder; } public event PropertyChangedEventHandler? PropertyChanged; public Brush? BackgroundBrush { get => backgroundBrush; private set { if (value != backgroundBrush) { backgroundBrush = value; CallPropertyChanged(); } } } public Brush? BorderBrush { get => borderBrush; private set { if (value != borderBrush) { borderBrush = value; CallPropertyChanged(); } } } public ImageSource? ColumnIcon { get => columnIcon; set { if (value != columnIcon) { columnIcon = value; CallPropertyChanged(); } } } [AllowNull] public string ColumnText { get => columnText ?? "?"; set { if (value != columnText) { columnText = value; CallPropertyChanged(); } } } internal int SortIndex { get; set; } internal bool IsPendingOpenItem { get; set; } internal bool IsSelected { get => isSelected; set { if (value != isSelected) { isSelected = value; CallPropertyChanged(); } } } internal FileInfo FileInfo { get; } /// /// Gets the original/local path. /// internal string Path { get; } /// /// Gets the resulting target path after following shortcuts or CLSIDs. /// internal string ResolvedPath { get; } /// /// Gets a value indicating whether /// the item is actually a folder and not a file. /// E.g. a shortcut (.lnk) would return false. /// internal bool IsFolder { get; } /// /// Gets a value indicating whether /// the item is actually a folder or at least points to one. /// E.g. a shortcut (.lnk) could return either false or true. /// internal bool IsPointingToFolder { get; } internal bool IsAdditionalItem { get; } internal int Level { get; } internal string FileExtension { get; } internal bool ShowOverlay { get; } internal Menu? Owner { get; set; } internal Menu? SubMenu { get; set; } internal bool HiddenEntry { get; set; } internal int RowIndex { get; set; } internal bool IconLoading { get; private set; } public override string ToString() => nameof(RowData) + ": " + ColumnText + ", Owner: " + (Owner?.ToString() ?? "null"); /// /// Triggers an PropertyChanged event of INotifyPropertyChanged. /// /// Name of the changing property. public void CallPropertyChanged([CallerMemberName] string? propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); internal void LoadIcon() { bool cacheHit; if (IsPointingToFolder) { cacheHit = IconReader.GetFolderIconWithCache(Path, ShowOverlay, Level == 0, UpdateFinalIcon); } else { cacheHit = IconReader.GetFileIconWithCache(Path, ResolvedPath, ShowOverlay, Level == 0, UpdateFinalIcon); } if (!cacheHit) { IconLoading = true; ColumnIcon = (ImageSource?)Application.Current.Resources["LoadingIconImage"]; // TODO: Maybe add rotation animation like for the loading Menu icon? (See: pictureBoxLoading, LoadingRotation) } } internal void OpenItem(int clickCount) { bool doCloseAfterOpen = false; if (!IsPointingToFolder) { if (clickCount == -1 || (clickCount == 1 && Settings.Default.OpenItemWithOneClick) || (clickCount == 2 && !Settings.Default.OpenItemWithOneClick)) { string? workingDirectory = System.IO.Path.GetDirectoryName(ResolvedPath); Log.ProcessStart(Path, string.Empty, false, workingDirectory, true, ResolvedPath); if (!Settings.Default.StaysOpenWhenItemClicked) { doCloseAfterOpen = true; } } } else { if (clickCount == -1 || (clickCount == 1 && Settings.Default.OpenDirectoryWithOneClick) || (clickCount == 2 && !Settings.Default.OpenDirectoryWithOneClick)) { Log.ProcessStart(Path); if (!Settings.Default.StaysOpenWhenItemClicked) { doCloseAfterOpen = true; } } } if (Owner != null) { if (clickCount == 1) { Owner.RiseItemOpened(this); } if (doCloseAfterOpen) { Owner.HideAllMenus(); } } } internal void OpenShellContextMenu(Point position) { if (IsPointingToFolder) { ShellContextMenu.OpenShellContextMenu(new DirectoryInfo(Path), position); } else { ShellContextMenu.OpenShellContextMenu(FileInfo, position); } } internal void OpenSubMenu() { Menu? openSubMenu = Owner?.SubMenu; // only re-open when the menu is not already open if (SubMenu != null && SubMenu == openSubMenu) { // Close second level sub menus when already opened openSubMenu.SelectedItem = null; if (openSubMenu.SubMenu != null) { openSubMenu.SubMenu.HideWithFade(true); openSubMenu.RefreshSelection(); } } else { // In case another menu exists, close it if (openSubMenu != null) { // Give the opening window focus // if closing window lose focus, no window would have focus any more Owner?.Activate(); Owner?.FocusTextBox(); openSubMenu.HideWithFade(true); Owner?.RefreshSelection(); } if (IsPointingToFolder) { Owner?.RiseStartLoadSubMenu(this); } } } internal void UpdateColors() { if (SubMenu != null) { BorderBrush = MenuDefines.ColorOpenFolderBorder; BackgroundBrush = MenuDefines.ColorOpenFolder; } else if (IsSelected) { BorderBrush = MenuDefines.ColorSelectedItemBorder; BackgroundBrush = MenuDefines.ColorSelectedItem; } else { BorderBrush = null; BackgroundBrush = null; } } private void UpdateFinalIcon(BitmapSource? icon) { if (icon == null) { icon = (BitmapSource)Application.Current.Resources["NotFoundIconImage"]; } else if (HiddenEntry) { icon = ImagingHelper.ApplyOpactiy(icon, 0.5d); icon?.Freeze(); // Make it accessible for any thread } IconLoading = false; ColumnIcon = icon; } } }