2022-10-23 11:02:31 +13:00
// <copyright file="RowData.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>
namespace SystemTrayMenu.DataClasses
{
using System ;
2023-05-19 09:28:52 +12:00
using System.ComponentModel ;
using System.Diagnostics.CodeAnalysis ;
2022-10-23 11:02:31 +13:00
using System.IO ;
2023-05-19 09:28:52 +12:00
using System.Runtime.CompilerServices ;
using System.Windows ;
using System.Windows.Media ;
2023-05-20 06:43:19 +12:00
using System.Windows.Media.Imaging ;
using SystemTrayMenu.Helpers ;
2023-05-19 09:28:52 +12:00
using SystemTrayMenu.Properties ;
using SystemTrayMenu.UserInterface ;
2022-10-23 11:02:31 +13:00
using SystemTrayMenu.Utilities ;
2023-05-19 09:28:52 +12:00
internal class RowData : INotifyPropertyChanged
2022-10-23 11:02:31 +13:00
{
2023-05-19 09:28:52 +12:00
private Brush ? backgroundBrush ;
private Brush ? borderBrush ;
private ImageSource ? columnIcon ;
private string? columnText ;
private bool isSelected ;
2022-10-23 11:02:31 +13:00
/// <summary>
/// Initializes a new instance of the <see cref="RowData"/> class.
/// (Related replace "\x00" see #171.)
/// </summary>
/// <param name="isFolder">Flag if file or folder.</param>
2023-04-17 06:17:24 +12:00
/// <param name="isAdditionalItem">Flag if additional item, from other folder than root folder.</param>
2022-10-23 11:02:31 +13:00
/// <param name="level">The number of the menu level.</param>
/// <param name="path">Path to item.</param>
2023-04-29 04:48:39 +12:00
internal RowData ( bool isFolder , bool isAdditionalItem , int level , string path )
2022-10-23 11:02:31 +13:00
{
IsFolder = isFolder ;
2023-04-17 06:17:24 +12:00
IsAdditionalItem = isAdditionalItem ;
2022-10-23 11:02:31 +13:00
Level = level ;
2023-04-30 04:57:39 +12:00
FileInfo = new FileInfo ( path . Replace ( "\x00" , string . Empty ) ) ;
Path = isFolder ? $@"{FileInfo.FullName}\" : FileInfo . FullName ;
FileExtension = System . IO . Path . GetExtension ( Path ) ? ? string . Empty ;
2022-10-23 11:02:31 +13:00
2023-04-30 04:57:39 +12:00
if ( FileExtension . Equals ( ".lnk" , StringComparison . InvariantCultureIgnoreCase ) )
{
ResolvedPath = FileLnk . GetResolvedFileName ( Path , out bool isLinkToFolder ) ;
2023-05-19 09:28:52 +12:00
ShowOverlay = Settings . Default . ShowLinkOverlay ;
2023-05-20 06:43:19 +12:00
ColumnText = System . IO . Path . GetFileNameWithoutExtension ( Path ) ;
2023-05-19 09:28:52 +12:00
if ( Settings . Default . ResolveLinksToFolders )
2023-04-30 04:57:39 +12:00
{
IsPointingToFolder | = isLinkToFolder | | FileLnk . IsNetworkRoot ( ResolvedPath ) ;
}
}
else
2022-10-23 11:02:31 +13:00
{
2023-04-30 04:57:39 +12:00
ResolvedPath = Path ;
if ( string . IsNullOrEmpty ( FileInfo . Name ) )
{
int nameBegin = FileInfo . FullName . LastIndexOf ( @"\" , StringComparison . InvariantCulture ) + 1 ;
2023-05-20 06:43:19 +12:00
ColumnText = FileInfo . FullName [ nameBegin . . ] ;
2023-04-30 04:57:39 +12:00
}
else if ( FileExtension . Equals ( ".url" , StringComparison . InvariantCultureIgnoreCase ) | |
FileExtension . Equals ( ".appref-ms" , StringComparison . InvariantCultureIgnoreCase ) )
2022-10-23 11:02:31 +13:00
{
2023-05-19 09:28:52 +12:00
ShowOverlay = Settings . Default . ShowLinkOverlay ;
2023-05-20 06:43:19 +12:00
ColumnText = System . IO . Path . GetFileNameWithoutExtension ( FileInfo . Name ) ;
2022-10-23 11:02:31 +13:00
}
2023-04-30 04:57:39 +12:00
else if ( ! isFolder & & Config . IsHideFileExtension ( ) )
2022-10-23 11:02:31 +13:00
{
2023-05-20 06:43:19 +12:00
ColumnText = System . IO . Path . GetFileNameWithoutExtension ( FileInfo . Name ) ;
2022-10-23 11:02:31 +13:00
}
2023-04-30 04:57:39 +12:00
else
2022-10-23 11:02:31 +13:00
{
2023-05-20 06:43:19 +12:00
ColumnText = FileInfo . Name ;
2022-10-23 11:02:31 +13:00
}
}
2023-04-30 04:57:39 +12:00
IsPointingToFolder | = isFolder ;
2022-10-23 11:02:31 +13:00
}
2023-05-19 09:28:52 +12:00
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 ( ) ;
}
}
}
2023-04-30 04:57:39 +12:00
internal FileInfo FileInfo { get ; }
/// <summary>
/// Gets the original/local path.
/// </summary>
internal string Path { get ; }
2022-10-23 11:02:31 +13:00
2023-04-30 04:57:39 +12:00
/// <summary>
/// Gets the resulting target path after following shortcuts or CLSIDs.
/// </summary>
internal string ResolvedPath { get ; }
2022-10-23 11:02:31 +13:00
2023-04-30 04:57:39 +12:00
/// <summary>
/// Gets a value indicating whether
/// the item is actually a folder and not a file.
/// E.g. a shortcut (.lnk) would return false.
/// </summary>
2022-10-23 11:02:31 +13:00
internal bool IsFolder { get ; }
2023-04-30 04:57:39 +12:00
/// <summary>
/// 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.
/// </summary>
internal bool IsPointingToFolder { get ; }
2023-04-17 06:17:24 +12:00
internal bool IsAdditionalItem { get ; }
2022-10-23 11:02:31 +13:00
2023-05-19 08:28:05 +12:00
internal int Level { get ; }
2022-10-23 11:02:31 +13:00
2023-04-30 04:57:39 +12:00
internal string FileExtension { get ; }
2022-10-23 11:02:31 +13:00
internal bool ShowOverlay { get ; }
2023-05-04 09:18:03 +12:00
internal Menu ? Owner { get ; set ; }
2022-12-05 13:27:57 +13:00
internal Menu ? SubMenu { get ; set ; }
2022-10-23 11:02:31 +13:00
internal bool HiddenEntry { get ; set ; }
internal int RowIndex { get ; set ; }
2023-05-19 08:28:05 +12:00
internal bool IconLoading { get ; private set ; }
2022-10-23 11:02:31 +13:00
2023-05-19 09:28:52 +12:00
public override string ToString ( ) = > nameof ( RowData ) + ": " + ColumnText + ", Owner: " + ( Owner ? . ToString ( ) ? ? "null" ) ;
/// <summary>
/// Triggers an PropertyChanged event of INotifyPropertyChanged.
/// </summary>
/// <param name="propertyName">Name of the changing property.</param>
public void CallPropertyChanged ( [ CallerMemberName ] string? propertyName = null ) = > PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( propertyName ) ) ;
2023-05-20 04:50:53 +12:00
internal void LoadIcon ( )
2022-10-23 11:02:31 +13:00
{
2023-05-20 01:27:35 +12:00
bool cacheHit ;
2023-05-19 10:17:07 +12:00
2023-04-30 04:57:39 +12:00
if ( IsPointingToFolder )
2022-10-23 11:02:31 +13:00
{
2023-05-20 04:50:53 +12:00
cacheHit = IconReader . GetFolderIconWithCache ( Path , ShowOverlay , Level = = 0 , UpdateFinalIcon ) ;
2022-10-23 11:02:31 +13:00
}
else
{
2023-05-20 04:50:53 +12:00
cacheHit = IconReader . GetFileIconWithCache ( Path , ResolvedPath , ShowOverlay , Level = = 0 , UpdateFinalIcon ) ;
2022-10-23 11:02:31 +13:00
}
2023-05-20 01:27:35 +12:00
if ( ! cacheHit )
2022-10-23 11:02:31 +13:00
{
2023-05-20 01:27:35 +12:00
IconLoading = true ;
2023-08-12 12:33:11 +12:00
ColumnIcon = ( ImageSource ? ) Application . Current . Resources [ "LoadingIconImage" ] ; // TODO: Maybe add rotation animation like for the loading Menu icon? (See: pictureBoxLoading, LoadingRotation)
2022-10-23 11:02:31 +13:00
}
}
2023-05-19 09:28:52 +12:00
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 ( )
{
2023-08-14 08:26:01 +12:00
Menu ? openSubMenu = Owner ? . SubMenu ;
2023-05-19 09:28:52 +12:00
2023-08-14 08:26:01 +12:00
// 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 )
2023-05-19 09:28:52 +12:00
{
2023-08-14 08:26:01 +12:00
openSubMenu . SubMenu . HideWithFade ( true ) ;
openSubMenu . RefreshSelection ( ) ;
2023-05-19 09:28:52 +12:00
}
2023-08-14 08:26:01 +12:00
}
else
{
// In case another menu exists, close it
if ( openSubMenu ! = null )
2023-05-19 09:28:52 +12:00
{
2023-08-14 08:26:01 +12:00
// 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 ( ) ;
}
2023-05-19 09:28:52 +12:00
2023-08-14 08:26:01 +12:00
if ( IsPointingToFolder )
{
Owner ? . RiseStartLoadSubMenu ( this ) ;
2023-05-19 09:28:52 +12:00
}
}
}
internal void UpdateColors ( )
{
if ( SubMenu ! = null )
{
BorderBrush = MenuDefines . ColorOpenFolderBorder ;
BackgroundBrush = MenuDefines . ColorOpenFolder ;
}
else if ( IsSelected )
{
BorderBrush = MenuDefines . ColorSelectedItemBorder ;
BackgroundBrush = MenuDefines . ColorSelectedItem ;
}
else
{
2023-06-04 07:40:33 +12:00
BorderBrush = null ;
BackgroundBrush = null ;
2023-05-19 09:28:52 +12:00
}
}
2023-05-20 01:27:35 +12:00
2023-05-20 06:43:19 +12:00
private void UpdateFinalIcon ( BitmapSource ? icon )
2023-05-20 01:27:35 +12:00
{
if ( icon = = null )
{
2023-08-12 12:33:11 +12:00
icon = ( BitmapSource ) Application . Current . Resources [ "NotFoundIconImage" ] ;
2023-05-20 01:27:35 +12:00
}
else if ( HiddenEntry )
{
2023-08-12 12:33:11 +12:00
icon = ImagingHelper . ApplyOpactiy ( icon , 0.5d ) ;
2023-05-20 07:26:47 +12:00
icon ? . Freeze ( ) ; // Make it accessible for any thread
2023-05-20 01:27:35 +12:00
}
IconLoading = false ;
2023-05-20 06:43:19 +12:00
ColumnIcon = icon ;
2023-05-20 01:27:35 +12:00
}
2022-10-23 11:02:31 +13:00
}
}