2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
/*=============================================================================
SDeviceProcesses . cpp : Implements the SDeviceProcesses class .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# include "DeviceManagerPrivatePCH.h"
# define LOCTEXT_NAMESPACE "SDeviceProcesses"
/* SMessagingEndpoints structors
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
SDeviceProcesses : : ~ SDeviceProcesses ( )
{
if ( Model . IsValid ( ) )
{
Model - > OnSelectedDeviceServiceChanged ( ) . RemoveAll ( this ) ;
}
}
/* SDeviceDetails interface
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SDeviceProcesses : : Construct ( const FArguments & InArgs , const FDeviceManagerModelRef & InModel )
{
Model = InModel ;
ShowProcessTree = true ;
ChildSlot
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
[
SNew ( SVerticalBox )
. IsEnabled ( this , & SDeviceProcesses : : HandleProcessesBoxIsEnabled )
+ SVerticalBox : : Slot ( )
. FillHeight ( 1.0f )
. Padding ( 0.0f , 4.0f , 0.0f , 0.0f )
[
// process list
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
. Padding ( 0.0f )
[
SAssignNew ( ProcessTreeView , STreeView < FDeviceProcessesProcessTreeNodePtr > )
. ItemHeight ( 20.0f )
. OnGenerateRow ( this , & SDeviceProcesses : : HandleProcessTreeViewGenerateRow )
. OnGetChildren ( this , & SDeviceProcesses : : HandleProcessTreeViewGetChildren )
. SelectionMode ( ESelectionMode : : Multi )
. TreeItemsSource ( & ProcessList )
. HeaderRow
(
SNew ( SHeaderRow )
+ SHeaderRow : : Column ( " Name " )
2014-04-23 18:06:41 -04:00
. DefaultLabel ( LOCTEXT ( " ProcessListNameColumnHeader " , " Process Name " ) )
2014-03-14 14:13:41 -04:00
. FillWidth ( 0.275f )
+ SHeaderRow : : Column ( " PID " )
2014-04-23 18:06:41 -04:00
. DefaultLabel ( LOCTEXT ( " ProcessListPidColumnHeader " , " PID " ) )
2014-03-14 14:13:41 -04:00
. FillWidth ( 0.15f )
+ SHeaderRow : : Column ( " User " )
2014-04-23 18:06:41 -04:00
. DefaultLabel ( LOCTEXT ( " ProcessListUserColumnHeader " , " User " ) )
2014-03-14 14:13:41 -04:00
. FillWidth ( 0.275f )
+ SHeaderRow : : Column ( " Threads " )
2014-04-23 18:06:41 -04:00
. DefaultLabel ( LOCTEXT ( " ProcessListThreadsColumnHeader " , " Threads " ) )
2014-03-14 14:13:41 -04:00
. FillWidth ( 0.15f )
+ SHeaderRow : : Column ( " Parent " )
2014-04-23 18:06:41 -04:00
. DefaultLabel ( LOCTEXT ( " ProcessListParentColumnHeader " , " Parent PID " ) )
2014-03-14 14:13:41 -04:00
. FillWidth ( 0.15f )
)
]
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0.0f , 4.0f , 0.0f , 0.0f )
[
SNew ( SBorder )
. Padding ( FMargin ( 8.0f , 6.0f , 8.0f , 4.0f ) )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
[
SNew ( SCheckBox )
. IsChecked ( this , & SDeviceProcesses : : HandleProcessTreeCheckBoxIsChecked )
. OnCheckStateChanged ( this , & SDeviceProcesses : : HandleProcessTreeCheckBoxCheckStateChanged )
. Padding ( FMargin ( 4.0f , 0.0f ) )
2014-04-23 18:06:41 -04:00
. ToolTipText ( LOCTEXT ( " ProcessTreeCheckBoxToolTip " , " Check this box to display the list of processes as a tree instead of a flat list " ) )
2014-03-14 14:13:41 -04:00
[
SNew ( STextBlock )
2014-04-23 18:06:41 -04:00
. Text ( LOCTEXT ( " ProcessTreeCheckBoxText " , " Show process tree " ) )
2014-03-14 14:13:41 -04:00
]
]
+ SHorizontalBox : : Slot ( )
. HAlign ( HAlign_Right )
[
SNew ( SButton )
. IsEnabled ( this , & SDeviceProcesses : : HandleTerminateProcessButtonIsEnabled )
. OnClicked ( this , & SDeviceProcesses : : HandleTerminateProcessButtonClicked )
2014-04-23 18:06:41 -04:00
. Text ( LOCTEXT ( " TerminateProcessButtonText " , " Terminate Process " ) )
2014-03-14 14:13:41 -04:00
]
]
]
]
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " NotificationList.ItemBackground " ) )
. Padding ( 8.0f )
2014-04-02 18:09:23 -04:00
. Visibility ( this , & SDeviceProcesses : : HandleMessageOverlayVisibility )
2014-03-14 14:13:41 -04:00
[
SNew ( STextBlock )
2014-04-02 18:09:23 -04:00
. Text ( this , & SDeviceProcesses : : HandleMessageOverlayText )
2014-03-14 14:13:41 -04:00
]
]
] ;
Model - > OnSelectedDeviceServiceChanged ( ) . AddRaw ( this , & SDeviceProcesses : : HandleModelSelectedDeviceServiceChanged ) ;
ReloadProcessList ( true ) ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
/* SCompoundWidget overrides
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void SDeviceProcesses : : Tick ( const FGeometry & AllottedGeometry , const double InCurrentTime , const float InDeltaTime )
{
SCompoundWidget : : Tick ( AllottedGeometry , InCurrentTime , InDeltaTime ) ;
if ( LastProcessListRefreshTime + FTimespan : : FromSeconds ( 2.5 ) < FDateTime : : Now ( ) )
{
ReloadProcessList ( true ) ;
}
}
/* SDeviceDetails implementation
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void SDeviceProcesses : : ReloadProcessList ( bool FullyReload )
{
// reload running processes
if ( FullyReload )
{
RunningProcesses . Reset ( ) ;
ITargetDeviceServicePtr DeviceService = Model - > GetSelectedDeviceService ( ) ;
if ( DeviceService . IsValid ( ) )
{
ITargetDevicePtr TargetDevice = DeviceService - > GetDevice ( ) ;
if ( TargetDevice . IsValid ( ) )
{
TargetDevice - > GetProcessSnapshot ( RunningProcesses ) ;
}
}
}
// update process tree
TMap < uint32 , FDeviceProcessesProcessTreeNodePtr > NewProcessMap ;
for ( int32 ProcessIndex = 0 ; ProcessIndex < RunningProcesses . Num ( ) ; + + ProcessIndex )
{
const FTargetDeviceProcessInfo & ProcessInfo = RunningProcesses [ ProcessIndex ] ;
FDeviceProcessesProcessTreeNodePtr Node = ProcessMap . FindRef ( ProcessInfo . Id ) ;
if ( Node . IsValid ( ) )
{
Node - > ClearChildren ( ) ;
Node - > SetParent ( NULL ) ;
NewProcessMap . Add ( ProcessInfo . Id , Node ) ;
}
else
{
NewProcessMap . Add ( ProcessInfo . Id , MakeShareable ( new FDeviceProcessesProcessTreeNode ( ProcessInfo ) ) ) ;
}
}
ProcessMap = NewProcessMap ;
// build process tree
if ( ShowProcessTree )
{
for ( TMap < uint32 , FDeviceProcessesProcessTreeNodePtr > : : TConstIterator It ( ProcessMap ) ; It ; + + It )
{
FDeviceProcessesProcessTreeNodePtr Node = It . Value ( ) ;
FDeviceProcessesProcessTreeNodePtr Parent = ProcessMap . FindRef ( Node - > GetProcessInfo ( ) . ParentId ) ;
if ( Parent . IsValid ( ) )
{
Node - > SetParent ( Parent ) ;
Parent - > AddChild ( Node ) ;
}
}
}
// filter process list
ProcessList . Reset ( ) ;
for ( TMap < uint32 , FDeviceProcessesProcessTreeNodePtr > : : TConstIterator It ( ProcessMap ) ; It ; + + It )
{
FDeviceProcessesProcessTreeNodePtr Node = It . Value ( ) ;
if ( ! Node - > GetParent ( ) . IsValid ( ) )
{
ProcessList . Add ( Node ) ;
}
}
// refresh list view
ProcessTreeView - > RequestTreeRefresh ( ) ;
LastProcessListRefreshTime = FDateTime : : Now ( ) ;
}
/* SDeviceDetails callbacks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-04-02 18:09:23 -04:00
FText SDeviceProcesses : : HandleMessageOverlayText ( ) const
{
ITargetDeviceServicePtr DeviceService = Model - > GetSelectedDeviceService ( ) ;
if ( DeviceService . IsValid ( ) )
{
ITargetDevicePtr Device = DeviceService - > GetDevice ( ) ;
if ( Device . IsValid ( ) & & Device - > IsConnected ( ) )
{
if ( Device - > SupportsFeature ( ETargetDeviceFeatures : : ProcessSnapshot ) )
{
return FText : : GetEmpty ( ) ;
}
return LOCTEXT ( " ProcessSnapshotsUnsupportedOverlayText " , " The selected device does not support process snapshots " ) ;
}
return LOCTEXT ( " DeviceUnavailableOverlayText " , " The selected device is currently unavailable " ) ;
}
return LOCTEXT ( " SelectDeviceOverlayText " , " Please select a device from the Device Browser " ) ;
}
EVisibility SDeviceProcesses : : HandleMessageOverlayVisibility ( ) const
{
ITargetDeviceServicePtr DeviceService = Model - > GetSelectedDeviceService ( ) ;
if ( DeviceService . IsValid ( ) )
{
ITargetDevicePtr Device = DeviceService - > GetDevice ( ) ;
if ( Device . IsValid ( ) & & Device - > IsConnected ( ) & & Device - > SupportsFeature ( ETargetDeviceFeatures : : ProcessSnapshot ) )
{
return EVisibility : : Hidden ;
}
}
return EVisibility : : Visible ;
}
2014-03-14 14:13:41 -04:00
void SDeviceProcesses : : HandleModelSelectedDeviceServiceChanged ( )
{
ReloadProcessList ( true ) ;
}
void SDeviceProcesses : : HandleProcessTreeCheckBoxCheckStateChanged ( ESlateCheckBoxState : : Type NewState )
{
ShowProcessTree = ( NewState = = ESlateCheckBoxState : : Checked ) ;
ReloadProcessList ( false ) ;
}
ESlateCheckBoxState : : Type SDeviceProcesses : : HandleProcessTreeCheckBoxIsChecked ( ) const
{
if ( ShowProcessTree )
{
return ESlateCheckBoxState : : Checked ;
}
return ESlateCheckBoxState : : Unchecked ;
}
TSharedRef < ITableRow > SDeviceProcesses : : HandleProcessTreeViewGenerateRow ( FDeviceProcessesProcessTreeNodePtr Item , const TSharedRef < STableViewBase > & OwnerTable )
{
return SNew ( SDeviceProcessesProcessListRow , OwnerTable )
. Node ( Item ) ;
}
void SDeviceProcesses : : HandleProcessTreeViewGetChildren ( FDeviceProcessesProcessTreeNodePtr Item , TArray < FDeviceProcessesProcessTreeNodePtr > & OutChildren )
{
if ( Item . IsValid ( ) )
{
OutChildren = Item - > GetChildren ( ) ;
}
}
bool SDeviceProcesses : : HandleProcessesBoxIsEnabled ( ) const
{
ITargetDeviceServicePtr DeviceService = Model - > GetSelectedDeviceService ( ) ;
2014-04-02 18:09:23 -04:00
if ( DeviceService . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-04-02 18:09:23 -04:00
ITargetDevicePtr Device = DeviceService - > GetDevice ( ) ;
return ( Device . IsValid ( ) & & Device - > IsConnected ( ) & & Device - > SupportsFeature ( ETargetDeviceFeatures : : ProcessSnapshot ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-04-02 18:09:23 -04:00
return false ;
2014-03-14 14:13:41 -04:00
}
bool SDeviceProcesses : : HandleTerminateProcessButtonIsEnabled ( ) const
{
return ( ProcessTreeView - > GetNumItemsSelected ( ) > 0 ) ;
}
FReply SDeviceProcesses : : HandleTerminateProcessButtonClicked ( )
{
ITargetDeviceServicePtr DeviceService = Model - > GetSelectedDeviceService ( ) ;
if ( DeviceService . IsValid ( ) )
{
if ( FMessageDialog : : Open ( EAppMsgType : : OkCancel , LOCTEXT ( " TerminateProcessWarning " , " Warning: If you terminate a process that is associated with a game or an application, you willl lose any unsaved data. If you end a system process, it might result in an unstable system. " ) ) = = EAppReturnType : : Ok )
{
TArray < FDeviceProcessesProcessTreeNodePtr > FailedProcesses ;
TArray < FDeviceProcessesProcessTreeNodePtr > SelectedProcesses = ProcessTreeView - > GetSelectedItems ( ) ;
for ( int32 ProcessIndex = 0 ; ProcessIndex < SelectedProcesses . Num ( ) ; + + ProcessIndex )
{
ITargetDevicePtr TargetDevice = DeviceService - > GetDevice ( ) ;
if ( TargetDevice . IsValid ( ) )
{
const FDeviceProcessesProcessTreeNodePtr & Process = SelectedProcesses [ ProcessIndex ] ;
if ( ! TargetDevice - > TerminateProcess ( Process - > GetProcessInfo ( ) . Id ) )
{
FailedProcesses . Add ( Process ) ;
}
}
}
if ( FailedProcesses . Num ( ) > 0 )
{
FString ProcessInfo ;
for ( int32 FailedProcessIndex = 0 ; FailedProcessIndex < FailedProcesses . Num ( ) ; + + FailedProcessIndex )
{
const FTargetDeviceProcessInfo & FailedProcessInfo = FailedProcesses [ FailedProcessIndex ] - > GetProcessInfo ( ) ;
ProcessInfo + = FString : : Printf ( TEXT ( " %s (PID: %d) \n " ) , * FailedProcessInfo . Name , FailedProcessInfo . Id ) ;
}
const FText ErrorMessage = FText : : Format ( LOCTEXT ( " FailedToTerminateProcessesMessage " , " The following processes could not be terminated. \n You may not have the required permissions: \n \n {0} " ) , FText : : FromString ( ProcessInfo ) ) ;
FMessageDialog : : Open ( EAppMsgType : : Ok , ErrorMessage ) ;
}
}
}
return FReply : : Handled ( ) ;
}
# undef LOCTEXT_NAMESPACE