You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 3813004 by Matt.Kuhlenschmidt Fix dpi scale being wrong when there is a mix of high dpi and low dpi monitors and the editor opens the window on the low dpi monitor Change 3946515 by Michael.Trepka Reverted CL 3813004. We need to save editor's root window size and position in DPI-independent units, as that's what the loading code expects. Change 4052825 by Brandon.Schaefer Add back -funwind-tables for arm This was removed an only tested on x86 which worked just fine. Arm reqiures this for backtrace #jira none Change 4055318 by Brandon.Schaefer Remove extra mallocs when crash handling Still need to look into gmalloc calls, such as using FStrings during Ensure/Crash handling [at]Arciel.Rekman #jira UE-58538 Change 4055623 by Brandon.Schaefer Replace std::endl with "\n" As std::endl is "\n" << std::flush. On windows dump_syms was taking 33 seconds to fflush with std::endl on a 1.2GB file. No longer with "\n". [at]Josh.Engebretson Change 4057102 by Jamie.Dale Added missing API export Change 4057384 by Rex.Hill Fix ReversePolygonFacing crash Change 4067426 by Matt.Kuhlenschmidt PR #4667: Source control history: remove empty spacing in the right of the detail panel (Contributed by SRombauts) Change 4067587 by Matt.Kuhlenschmidt PR #4311: PlacementModeTools shapes searchable and thumbnail (Contributed by projectgheist) Change 4068480 by Cody.Albert Fix display name for Display UI Extension Points Change 4070876 by Brandon.Schaefer Avoid printing when in a signal handler. Put that off until the end #jira UE-36663 [at]Arciel.Rekman, [at]Anthony.Bills Change 4071980 by Brandon.Schaefer Cache files that are invalid or the wrong case sensitivity #jira UE-58250 [at]Arciel.Rekman Change 4079967 by Matt.Kuhlenschmidt Added scale parameter to Canvas::DrawText #jira UE-59023 Change 4080228 by Alexis.Matte Fix the PerPlatformPropertiesWidget to be readable when there is many platform #jira UE-57556 Change 4081171 by Matt.Kuhlenschmidt PR #4272: Fix typo. (Contributed by Damianno19) Change 4081601 by Matt.Kuhlenschmidt GitHub 4077 : Hide SDetailView Filterbox when no actor selected Change 4090114 by Matt.Kuhlenschmidt Fixed touch events simulated through mouse not respecting high dpi #jira UE-59477 Change 4091999 by Matt.Kuhlenschmidt Fixed insert/delete/duplicate children calling PostEditChange on the existing child node not the array Change 4093187 by Arciel.Rekman Do not save window position if running with -nullrhi (UE-52498). - This also fixes a crash on exiting automation tests. #jira UE-52498 Change 4096404 by Richard.TalbotWatkin Resaved test assets to update to latest UStaticMesh serialization format. Change 4096445 by Richard.TalbotWatkin New serialization layout for UMeshDescription. - Only the bare minimum is serialized: any internal values which can be inferred from others in the Mesh Description are omitted. - Triangles are no longer serialized: a triangulation step is performed per polygon when serialized. - Attribute arrays of simple types are now serialized with BulkSerialize for speed; only FName requires element-by-element serialization. Change 4112843 by Brandon.Schaefer Rebuilt replacing std::endl with '\n' avoiding a std::flush *pre* write Was taking 30 seconds to std::flush on a 1.2 GB file #jira none Change 4113422 by Brandon.Schaefer If we are using the native bundled toolchain set LC_ALL=C to avoid locale issues #jira UE-59416 Change 4113849 by Cody.Albert Fix support for toolbar extensions in the UMG editor Change 4118758 by Richard.TalbotWatkin - Refactor to put UStaticMesh Mesh Descriptions in a separate object which is not loaded by default, but which can be requested when needed. This needs to be kept in sync with the number of SourceModel LODs. - Various refactors to import/building. - Changed UMeshDescription to FMeshDescription, and made its preferred semantics pass-by-reference rather than by pointer. - Deprecated UMeshDescription. Change 4119883 by Rex.Hill Cleanup blueprint callable categories Landscape Editor -> Landscape|Editor Landscape Runtime -> Landscape|Runtime Cloth -> Clothing Simulation Cinematics -> Cinematic Utility -> Utilities Change 4119898 by Rex.Hill Cleanup blueprint callable categories x|Magic Leap -> Magic Leap|x Apple ARKit * -> Apple ARKit|* Change 4119972 by Brandon.Schaefer Dont add colors if we are not outputing to a terminal #jira UE-58173 Change 4119994 by Brandon.Schaefer Only check once if we are outputing to a terminal #jira UE-58173 Change 4122654 by Alexis.Matte Fix re import assignment of sections #jira UE-59611 Change 4123536 by Alexis.Matte Add to the fbx importer the possibility to use different sample rate when importing an animation. #jira UE-59444 Change 4124702 by Brandon.Schaefer Fix duplicated struct/class from slightly different submit into main coming back into dev-editor #jira UE-60163 Change 4133449 by Mike.Erwin glTF importer work Foundations of work for Skeletal Mesh import; right now we just support Static Mesh. - node hierarchy - joint IDs & skinning weights - matrix & quaternion values #jira none Change 4133749 by Matt.Kuhlenschmidt PR #4771: Fix access violation for ImportAsset commandlet fbx reimport. (Contributed by UristMcRainmaker) Change 4133758 by Matt.Kuhlenschmidt PR #4675: Properly set TextScale for OnScreenDebugMessages (Contributed by projectgheist) Change 4134543 by Alexis.Matte Update the staticmesh LOD model max deviation when generating a LOD #jira UE-60353 Change 4134559 by Alexis.Matte Deprecate FRawMesh, replace by MeshDescription - Editor scripting utilities #jira UE-60666 Change 4134560 by Alexis.Matte Deprecate FRawMesh, replace by MeshDescription - SpeedTreeImporter #jira UE-60667 Change 4135335 by Alexis.Matte Deprecate FRawMesh - GLTF importer #jira UE-60670 Change 4135857 by Alexis.Matte Fix CIS build warning #jira none Change 4137249 by Matt.Kuhlenschmidt Fix tiny fonts from appearing in slow task dialogs Change 4137280 by Matt.Kuhlenschmidt Fix specifying relative paths for the auto-import commandlet not working Change 4137283 by Matt.Kuhlenschmidt PR #4305: Light map index was unintialized (Contributed by DSDambuster) Change 4137290 by Matt.Kuhlenschmidt PR #4382: Prevent error log due to non-existing plugin directory (Contributed by projectgheist) Change 4147032 by Alexis.Matte Deprecate FRawMesh, replace by MeshDescription - ABC Importer #jira UE-60702 Change 4147978 by Matt.Kuhlenschmidt Fix one of the CIS fails Change 4154874 by Matt.Kuhlenschmidt Fix hidden asset properties in struct details panels. We consider all object properties with "allowedclasses" metadata to be asset properties since they only show an asset picker. Change 4167303 by Matt.Kuhlenschmidt Work around for sync to content browser from details panels not working for interface properties Change 4167388 by Matt.Kuhlenschmidt Make sure when converting relative path filenames in automated import that we convert them relative to the project directory. Change 4171891 by Matt.Kuhlenschmidt Fix preview mesh actor becoming stuck to the cursor when the editor or viewport loses focus #jira UE-61246 Change 4175503 by Cody.Albert Updated variable details panels to not display unusable metadata options for UMG widget references #jira UE-55078 Change 4175736 by Cody.Albert PR #4663: UE-20103: Slate widgets retain their category name v2 (Contributed by projectgheist) Change 4178937 by Rex.Hill Fix crash opening level after removing as sublevel jira: UE-61305 Change 4181097 by Matt.Kuhlenschmidt Fix Linux/Mac CIS Change 4184333 by Alexis.Matte Fix the material ID assignation when re-importing static mesh #jira none Change 4199682 by Arciel.Rekman Linux: enable XGE during cross-builds to see whether the build issues persist. - Licensees are asking for this and XGE folks are eager to help investigating the crashes, if any. Change 4200944 by Cody.Albert Updated VR Mode button to become inactive during SIE (instead of disappearing altogether) #jira UE-50220 Change 4204817 by Alexis.Matte Enable or disable the morph target weight slider depending of the project settings. #jira UE-61671 Change4204821by Alexis.Matte Optimize import time for morph targets #jira UE-61670 Change4207394by Cody.Albert PR #3299: UMG Slider Additions (Contributed by Dzuelu) Change 4208299 by Brandon.Schaefer Fix warning/error with logical operators #jira none Change 4210660 by Cody.Albert PR #3458: UE-43728: Always show scrollbar when necessary (Contributed by projectgheist) #jira UE-43727, UE-43278 Change 4215684 by Brandon.Schaefer Linux: Implement minimized function for LinuxWindow #jira UE-56023 Change 4217350 by Brandon.Schaefer Linux: Clean up IsMaximized #jira none Change 4217489 by Brandon.Schaefer Linux: Make popup menus BORDERLESS. Slate will give the menu events This appears to fix a lot of our grabs causing compiz to do something issue. #jira UE-59237, UE-54085, UE-51407, UE-50018, UE-53915 Change 4225018 by Cody.Albert UMG Hierarchy now remembers expansion state when being destroyed and recreated (due to closing widget or switching to Graph view) #jira UE-61836 Change 4225088 by Cody.Albert Added hover style for color picker slider Change 4226081 by Richard.TalbotWatkin New attribute array API. Fixed some flaws in the original API, deprecated various methods, and introduced some new features. - Now attribute arrays are accessed via TAttributesRef or TAttributesView (and corresponding const versions). These value types hold references to attribute arrays, and individual elements can be accessed by their element ID and attribute index. Using a value type is safer than the previous method which required assignment to a const-ref (and not doing so would take a temporary copy of the attribute array). - The attribute set has been totally flattened, so all attributes of different types are added to the same container. This greatly improves compile times, prevents attributes from being created with the same name but different types, and permits the view feature. - The class hierarchy has changed to have generic base classes where possible with no particular ElementID type. This reduces the code footprint by no longer generating nearly identical copies of templated methods. - A TAttributesView allows the user to access an attribute array by the type of their choosing, regardless of its actual type. For example, the Normal attribute may be registered with type FPackedVector, but accessed as if it was an FVector. This allows us to move away from very strong typing, and instead transparently store attributes of a more efficient size, while the user is not affected. - A transient attribute flag has been added, to denote that a particular attribute should not be saved. Change 4226083 by Richard.TalbotWatkin Reinstated original mesh editor materials. Change 4226102 by Richard.TalbotWatkin Fixed some deprecation warnings, and a mistake in MeshAttributeArray.h. Change 4226118 by Richard.TalbotWatkin Fix build errors: - Added missing file - Corrected the last fix. Change 4226121 by Richard.TalbotWatkin Bumped static mesh mesh data GUID. Change 4226231 by Richard.TalbotWatkin Removed some test code which got checked in by mistake. Change 4226232 by Richard.TalbotWatkin Fixed typo which caused build errors. Change 4226234 by Richard.TalbotWatkin Fixed a typo in MeshDescriptionTests. Change 4226237 by Richard.TalbotWatkin Removed over-cautious deprecation warnings. Once GetAttributes() is changed to GetAttributesRef(), element access will still work with array syntax. Change 4226625 by Richard.TalbotWatkin Added missing asset. Change 4227365 by Matt.Kuhlenschmidt Fix brush actors not showing the correct icon in scene outliner. - Actors can now supply their own icon if needed #jira UE-61948 Change 4229632 by Alexis.Matte Make the namespace an import option #jira UE-62099 #jira UE-62067 Change 4229637 by Alexis.Matte Fix fbx importer staticmesh the light map index, the index was check before the build. #jira UE-62064 Change 4232793 by Chris.Gagnon Added include to fix non unity builds. #jira UE-62138 Change 4234206 by Brandon.Schaefer Linux: Allow windows that want to be resizable to be resizeable Github PR #3578 thanks hhyyrylainen #jira UE-45847 Change 4234322 by Brandon.Schaefer Continue after starting UnrealVersionSelector to avoid blocking a chain command #jira UE-61530 Change 4234446 by Chris.Gagnon Properly handled FPackageName::TryConvertFilenameToLongPackageName() failing in Cache Thumbnail. #jira UE-61990 Change 4235057 by Brandon.Schaefer Linux: Write to stderr when we fail to find expected to find sym file #jira none Change 4235121 by Brandon.Schaefer Linux: Mark the static bool as soon as we enter the scope #jira none Change4235399by Brandon.Schaefer Linux: Check we are not x86 otherwise add unwind tables Copying the change that went over into 4.20.1 here #jira none Change 4240539 by Jamie.Dale Made DataTableUtils::GetX functions take a const data pointer Change 4240646 by Chris.Gagnon Fix for delayed destruction of UWidgets when they are manually removed from a panel as part of tear down. Inspired by the pull request, however I put in a more generic fix. PR #4904: Fix late release of Slate resources managed by UMG slot widgets (Contributed by cmp-) Change 4242975 by Yuriy.ODonnell Moved duplicated code from MeshUtilities and MeshDescriptionOperations (FLayoutUV, FAllocator2D, FOverlappingCorners, etc.) into a new single module MeshUtilitiesCommon. Add a generic opaque mesh view interface FLayoutUV::IMeshView to abstract mesh data access and allow FLayoutUV to be used with any mesh type in any module. Replaced few instances of using an old version of overlapping corners data structure (multi-map) with new specialized FOverlappingCorners container. Change 4243112 by Yuriy.ODonnell Use new attribute array API for accessing FMeshDescription data. Change 4243131 by Brandon.Schaefer Cast our new resize w/h to int before checking if we are already that size #jira UE-52291 Change 4243172 by Brandon.Schaefer Ceil not trunk for this compare #jira none Change 4243271 by Brandon.Schaefer Change address to be more portable MS compiler does not place a '0x' on %p formating. Linux/Mac append a '0x' to the address #jira UE-62325 Change 4243276 by Richard.TalbotWatkin Fixed deprecated MeshDescription calls (merged with Yuriy's changes). Change 4244067 by Lauren.Ridge Preventing crash on floating text if asset container does not exist. VR Editor floating text is now not placeable or blueprintable. #jira UE-62139 Change 4244547 by Lauren.Ridge Changes to more accurately represent android behavior in PIE and UMG #jira UE-62301 Change 4244830 by Alexis.Matte Fix animation Range import, prevent changing the option when validating the anim range. #jira UE-62055 Change 4250565 by Yuriy.ODonnell Removed GeometryCache dependency on MeshUtilitiesCommon in non-editor configs. Change 4254733 by Matt.Kuhlenschmidt Slate Fast Path - Changed FSlateWindowElementList GetWindow to be thread safe. For fast path, this is accessed on multiple threads so it needs to be safe GetWindow is deprecated and GetPaintWindow should be used instead Edigrate from source CL 4254611 Change 4257092 by Chris.Gagnon Improved UMG rename validation to respect the errors from the blueprint validator. This fixes at least the case where it miss reported the issue when the name was greater than the length limit in blueprints. #jira UE-62417 Change 4257124 by Chris.Gagnon PR #4924: UE-62113 Fix Other filters toggling all assets to show up (Contributed by mamoniem) #jira UE-62457 Change 4258696 by Chris.Gagnon Removed Tab Spawner for Color Curve Editor is your not editing the color curve. #jira none Change 4258937 by Chris.Gagnon Simplifed the code in the case of a null CurveOwner. #jira UE-62443 Change 4259162 by Richard.TalbotWatkin Fixed crash when entering mesh editor mode after having loaded a new level. Change 4259909 by Chris.Gagnon Added better check output to try and learn more about a crash in the wild. Added some better const saftey while in there. #jira UE-60696 Change 4259995 by Chris.Gagnon Fix for possible crash if the mesh has invalid materials. Also fixed the fact the FindMaterialIndicesUsingTexture() didn't work as advertised at all. Seems like you'd attemp to paint all materials even when trying to only paint the ones using a particular texture. #jira UE-62488 Change 4261012 by Michael.Dupuis #jira UE-48899: Make sure the RootComponent is valid before trying to use it. Change 4261361 by Michael.Dupuis #jira UE-48899: Fixed the warning about scale Change 4261926 by Michael.Dupuis #jira UE-48899: Only check the root component validity as it's possible that the component is not registered when this get called. Change 4262163 by Richard.TalbotWatkin Fixed uninitialized member. #jira UE-62493 #jira UE-62506 Change 4262549 by Brandon.Schaefer Linux: Update the Slate application what the window size will most likely be As X11 takes a frame to send an Event that a window has had its size changed. This causes things such as the slate renderer to think the window size is different then it actually it. This causes streching of tooltips #jira UE-62555 Change 4262581 by Brandon.Schaefer Linux: Use Show so we preserve our bIsVisible bool and avoid sending SDL_ShowWindow twice (ie. if its already shown) #jira none Change 4262906 by Chris.Gagnon PR #4915: [UMG] Bind UWidgetAnimation from C++ to blueprint created animation (Contributed by TheCodez) Change 4262965 by Chris.Gagnon PR #4932: Fix to generate cleaner C++ files when using "New C++ Class" (Contributed by TheCodez) Change 4263177 by Chris.Gagnon PR #4935: Prevent crash when clicking use selected game mode multiple times (Contributed by projectgheist) Change 4264723 by Christina.TempelaarL Fixed SceneCaptureComponent so ShowOnlyActors property is writeable in blueprints. #jira UE-62547 Change 4266029 by Michael.Dupuis #jira none: Guarded against the scene being null Change 4266356 by Richard.TalbotWatkin Changed FMeshDescription to a struct from a class. Added log errors when loading UMeshDescription objects (now deprecated), in preparation to resave any which remain. Once all serialized UMeshDescriptions are wiped out (they only exist internally), FMeshDescription will become a USTRUCT. Change 4266621 by Matt.Kuhlenschmidt Fix UE4 icon to be the correct one Change 4266635 by Chris.Gagnon Added Message Log output for invalid software cursor as opposed to ensure/log. #jira UE-62554 Change 4268136 by Matt.Kuhlenschmidt Fix outline colors not updating when changing on the fly #jira UE-42116 Change 4269184 by Chris.Gagnon Fix for possible nullptr dereference. #jira none Change 4269902 by Brandon.Schaefer Slate dialog modal window was not settings its parent window #jira UE-62608 Change 4272083 by Chris.Gagnon Fix for case where the the property noded arn't rebuilt in time and custom property ui can be using stale data. #jira UE-62499 Change 4272869 by Michael.Trepka Make sure ShooterGame sets correct input modes/mouse capture in menus and in game to avoid problems with keyboard not working in menus after alt-tab #jira UE-61017 Change 4275155 by Michael.Dupuis #jira UE-62526: Update lightmap/shadow UV mapping after lighting build on HISMC. ISM will get also updated due to the Edit() that will reapply the values on CreateSceneProxy Change 4275298 by Lauren.Ridge Fixed string parsing when looking at parent cvar values #jira UE-62301 Change 4275391 by Lauren.Ridge Fix for resolutions increasing when swapping landscape/portrait Change 4275606 by Lauren.Ridge Moving all asset container access to PostActorCreated to avoid VR editor assets in cooks #jira UE-57797 Change 4275807 by Lauren.Ridge Duplicating color themes now dupllicates the color labels as well #jira UE-60697 Change 4275989 by Lauren.Ridge When selecting a node while the details panel is behind a different panel in the same dock tab, the details panel is brought forward #jira UETOOL-1325 Change 4276146 by Lauren.Ridge Fix for new texture sample nodes not taking the selected texture from the content browser as the starting value. #jira UETOOL-1322 Change 4276412 by Lauren.Ridge Assets that can be dragged into the material graph now indicate that with a checkmark #jira UE-56024 Change 4279549 by Lauren.Ridge Fixed recursion of calls through SetDesignerFlags to avoid double-recursion with many nested panels #jira none Change 4279894 by Lauren.Ridge Adding check for RootWidget existing Change 4279969 by Michael.Trepka Updated FDesktopPlatformMac::FileDialogShared() to handle a case where no extensions were specified in FileTypes string #jira UE-62421 Change 4280317 by Lauren.Ridge Adding if WITH_EDITOR Change 4280716 by Chris.Gagnon PR #4979: UE-62795: Deprecate bAutoWrapText in TextBlock (Contributed by projectgheist) Slightly modified, the base syncronize sets the autowrap value. Change 4280847 by Lauren.Ridge Single property setting changes will now also call OnModified delegate for their section #jira UE-58276 Change 4280850 by Chris.Gagnon Added early out and log if focus is attempted to be set when the window is suppost to be be disabled due to a modal window being up. #jira UE-62742 Change 4280931 by Brandon.Schaefer Linux: Use MallocCrash when hitting out of memory issues in BinnedAllocFromOS #jira FORT-108267 Change 4281460 by Lauren.Ridge Clearing focus on a variable once it is committed. Fixes assert on undo #jira UE-61872 Change 4283706 by tim.gautier QAGame: Adding HISM test map / assets Change 4283980 by Michael.Trepka Unshelved from pending changelist '4238012': Xcode project generator improvements - Per-project precompiled header that wraps UnrealEd.h with #ifdef __cplusplus to allow Xcode to compile the pch in ObjC mode. Later we could replace UnrealEd.h with some other header file for non-editor targets - Moved commands that disable compile warnings from MacToolChain's GetCompileArguments_Global to ApplePlatformCompilerPreSetup.h. Thanks to this we can have all the Xcode recommended warnings enabled in the project, but still allow Clang to index our code without reporting warnings - Few more minor changes to fix Xcode's project validation and indexing warnings Also, unify compile warning flags across all Apple platforms. #jira UE-47965, UE-44327 Change 4284062 by Michael.Trepka Copy of CL 4222794 from 4.20 Fixed a crash at exit in Mac editor caused by an attempt to use MetalProfiler after deleting it #jira none Change 4284266 by Brandon.Schaefer Linux: Fix deadlock in a file cache which could be locked in a crash handler #jira UE-62808 Change 4284469 by Lauren.Ridge Fix for material parameter node crashing Change 4284541 by Lauren.Ridge Blueprints inheriting from UWidget will now show up in the palette view even if they are not loaded. #jira UE-59164 Change 4284542 by Michael.Trepka Copy of CL 4222797 Fixed a problem with FMacPlatformMisc::NormalizePath allocating an autorelease pool during crash handling, which resulted in the OS killing the process before we spawn CrashReportClient. Now this function is identical to Linux version. #jira UE-61779 Change 4285288 by Cody.Albert Fixed crash when changing "Show Coalesced" setting in profiler Change 4285483 by Chris.Gagnon PR #4936: Duplicate widget functionality for UMG editor (Contributed by projectgheist) Fixed up some variable names. #jira UE-62528 Change 4287219 by Brandon.Schaefer dump_syms: Replace inline file/line with their callsite over the inline location Fix <name omitted> appearing as the names for the function Disable CFI generation for Windows (Linux theres a command line). Speeds up symbol generation #jira FORT-670 Change 4287247 by Brandon.Schaefer BreakpadSymbolEncoder: If the file doesnt have a newline at EOF handle that as a seperate case #jira none Change 4287259 by Brandon.Schaefer dump_syms: Build on centos7 #jira none Change 4287269 by Brandon.Schaefer Linux: Disable generating CFI info when running dump_syms #jira none Change 4287326 by Brandon.Schaefer dump_syms: Update to disabling the CFI generation version #jira none Change 4287902 by Brandon.Schaefer TestPAL: Add cases for testing inline callstacks #jira UEENGQA-21414 Change 4288365 by Lauren.Ridge PR #4422: Set default material parameter name (Contributed by projectgheist) Change 4292002 by Brandon.Schaefer Linux: If our default settings are empty help fill in the proper name #jira UE-62910 Change 4292496 by Lauren.Ridge Now all renamable nodes do name verification also Change 4292532 by Lauren.Ridge PR #4989: Add icons to folder context menu favorites (Contributed by projectgheist) Change 4293043 by tim.gautier QAGame: Added a panner to ML_Albedo Change 4295326 by Richard.TalbotWatkin - Updated MeshDescription attribute calls to fix deprecation warnings. - Removed TMeshAttributeArraySet::AddArray because the functionality was already available as part of SetNumIndices. - Renamed TMeshAttributeArraySet::InsertArray, RemoveArray to InsertIndex, RemoveIndex for naming convention consistency (these methods deal with attribute indices, not with arrays). Added support for them in other attribute classes, and made them virtual so they can be called as part of an AttributesView. - Removed redundant code in FUSDStaticMeshImportState::AddPolygons, when determining the number of UVs in the mesh description. Change 4295795 by Richard.TalbotWatkin Corrected MAX_MESH_TEXTURE_COORDS_MD references. Change 4297308 by Cody.Albert Fixed bug with InputPreProcessorsHelper::Add not correctly adding input processors Change 4297799 by Brandon.Schaefer Linux: Dont assume DISPlAY=:0 #jira UE-63050 Change 4298150 by Brandon.Schaefer dump_syms: This is rebuilding dump_sym changes from CL 4287219 for Mac Replace inline file/line with their callsite over the inline location Fix <name omitted> appearing as the names for the function Disable CFI generation for Windows (Linux theres a command line). Speeds up symbol generation Source code changes for dump_syms was changed at CL 4287219 #jira none Change 4298369 by Brandon.Schaefer dump_syms: Rebuild for Linux/Windows to fix a possible crash when missing debug_ranges in the debug section Source changed in CL 4298150 #jira none Change 4301952 by Lauren.Ridge Fixing input labels on material function inputs #jira UE-63077 Change 4302388 by Brandon.Schaefer Linux: If we have a 0 LineNumber lets try to use to the previous Record. Still an issue with non-virtual thunks reporting line number zero but it seems even windows skips these frames. GDB reports a different callsite that doesnt seem super related (possibly?) Nothing to do with thunking though. #jira UE-62930 Change 4304835 by Alexis.Matte Add imported framerate info to anime sequence #jira UE-51302 Change 4307480 by Brandon.Schaefer SDL2: Update to newer version hg-12121:4358e537000a Fixed github PR #4844 as well (thanks tomix1024) #jira UE-62783 UE-61369 Change 4307481 by Brandon.Schaefer SDL2: Rebuild with the newer version hg-12121:4358e537000a Fixed github PR #4844 as well (thanks tomix1024) #jira UE-62783 UE-61369 Change 4308264 by Brandon.Schaefer Linux: Make both DLLIMPORT the same value #jira UE-61174 Change 4308640 by Matt.Kuhlenschmidt Added a "report bug" menu entry to the help menu #jira UE-63182 Change 4309508 by Brandon.Schaefer nvTextureTools: Rebuild on Linux using our libc++ and not libstdc++ Move to the proper runtime depend location #jira UE-54892 UE-61705 Change 4309554 by Brandon.Schaefer SDL2: Add last missing folder #jira none Change 4309955 by Chris.Gagnon PR #5017: UE-63105: Modify SGraphActionMenu::OnKeyDown to use a different branc. (Contributed by projectgheist) Change 4311008 by Brandon.Schaefer nvTextureTools: Actually remove libstdc++ from Linux build #jira UE-54892 Change 4312195 by Alexis.Matte - Fix the set range feature to always use the file sample rate so the range match what the user see in the DCC - Also add some fbx file information to the import dialog #jira UE-62504 Change 4315347 by Brandon.Schaefer Linux: Disable XGE builds as it appears to be lower casing folders when the build platform is Windows #jira UE-63296 Change 4318704 by Lauren.Ridge Fix for crash on opening map built data #jira UE-63301 Change 4319999 by Lauren.Ridge Fix for crash in vr mode #jira UE-63376 Change 4320144 by Chris.Gagnon Fix for smoke content that set the hovered size different to the normal size on the UMG slider handle. #jira UE-63367 Change 4327887 by Michael.Trepka Disable nonportable-include-path warning in iOS toolchain to allow incorrect case in paths to headers passed using -include #jira UE-63408 Change 4217622 by Brandon.Schaefer Linux: Pass a command line argument to crash reporter to show or skip a user agreement popup #jira none Change 4312048 by Brandon.Schaefer Linux: Dont disable ICU by default on Servers #jira UE-59113 Change 4320173 by Chris.Gagnon Fix for startup movie streamer on xbox not finishing. #ROBOMERGE-OWNER: jason.bestimt #ROBOMERGE-SOURCE: CL 4329255 in //UE4/Main/... #ROBOMERGE-BOT: DEVVR (Main -> Dev-VR) [CL 4329265 by chris gagnon in Dev-VR branch]
1480 lines
49 KiB
C++
1480 lines
49 KiB
C++
// Copyright 1998-2018 Epic Games, Inc. All Rights Reserved.
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Misc/MessageDialog.h"
|
|
#include "Misc/Paths.h"
|
|
#include "ISourceControlOperation.h"
|
|
#include "SourceControlOperations.h"
|
|
#include "ISourceControlRevision.h"
|
|
#include "SourceControlWindows.h"
|
|
#include "SourceControlHelpers.h"
|
|
#include "ISourceControlModule.h"
|
|
#include "Modules/ModuleManager.h"
|
|
#include "UObject/Object.h"
|
|
#include "UObject/Package.h"
|
|
#include "Misc/PackageName.h"
|
|
#include "InputCoreTypes.h"
|
|
#include "Layout/Visibility.h"
|
|
#include "Layout/Geometry.h"
|
|
#include "Widgets/SNullWidget.h"
|
|
#include "Styling/SlateBrush.h"
|
|
#include "Input/Events.h"
|
|
#include "Input/DragAndDrop.h"
|
|
#include "Input/Reply.h"
|
|
#include "Widgets/DeclarativeSyntaxSupport.h"
|
|
#include "Widgets/SWidget.h"
|
|
#include "Widgets/SCompoundWidget.h"
|
|
#include "Widgets/SBoxPanel.h"
|
|
#include "Widgets/SWindow.h"
|
|
#include "SlateOptMacros.h"
|
|
#include "Framework/Application/SlateApplication.h"
|
|
#include "Textures/SlateIcon.h"
|
|
#include "Framework/Commands/UIAction.h"
|
|
#include "Widgets/Layout/SBorder.h"
|
|
#include "Widgets/Images/SImage.h"
|
|
#include "Widgets/Text/STextBlock.h"
|
|
#include "Widgets/Layout/SBox.h"
|
|
#include "Framework/MultiBox/MultiBoxBuilder.h"
|
|
#include "Widgets/Layout/SSplitter.h"
|
|
#include "Widgets/Views/SExpanderArrow.h"
|
|
#include "Widgets/Views/SHeaderRow.h"
|
|
#include "Widgets/Views/STableViewBase.h"
|
|
#include "Widgets/Views/STableRow.h"
|
|
#include "Widgets/Views/STreeView.h"
|
|
#include "Framework/Docking/TabManager.h"
|
|
#include "EditorStyleSet.h"
|
|
|
|
#include "IAssetTools.h"
|
|
#include "IAssetTypeActions.h"
|
|
#include "AssetToolsModule.h"
|
|
|
|
/**
|
|
* Wrapper around data from ISourceControlRevision
|
|
*/
|
|
class FHistoryRevisionListViewItem
|
|
{
|
|
public:
|
|
/** Changelist description */
|
|
FString Description;
|
|
|
|
/** User name of submitter */
|
|
FString UserName;
|
|
|
|
/** Clientspec/workspace of submitter */
|
|
FString ClientSpec;
|
|
|
|
/** File action for this revision (branch, delete, edit, etc.) */
|
|
FString Action;
|
|
|
|
/** Source path of branch, if any */
|
|
FString BranchSource;
|
|
|
|
/** Date of this revision */
|
|
FDateTime Date;
|
|
|
|
/** Number of this revision */
|
|
FString Revision;
|
|
|
|
/** Changelist number */
|
|
int32 ChangelistNumber;
|
|
|
|
/** Filesize for this revision (0 in the event of a deletion) */
|
|
int32 FileSize;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param InRevision File revision info. to populate this wrapper with
|
|
*/
|
|
FHistoryRevisionListViewItem( const TSharedRef<ISourceControlRevision, ESPMode::ThreadSafe>& InRevision )
|
|
{
|
|
Description = InRevision->GetDescription();
|
|
UserName = InRevision->GetUserName();
|
|
ClientSpec = InRevision->GetClientSpec();
|
|
Action = InRevision->GetAction();
|
|
BranchSource = InRevision->GetBranchSource().IsValid() ? InRevision->GetBranchSource()->GetFilename() : TEXT("");
|
|
Date = InRevision->GetDate();
|
|
Revision = InRevision->GetRevision();
|
|
ChangelistNumber = InRevision->GetCheckInIdentifier();
|
|
FileSize = InRevision->GetFileSize();
|
|
}
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
* Managed mirror of FSourceControlFileHistoryInfo. Designed to represent the history of a file in
|
|
* a listview.
|
|
*/
|
|
class FHistoryFileListViewItem
|
|
{
|
|
public:
|
|
|
|
/** Depot name of the file */
|
|
FString FileName;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param InFileName File name of the list item
|
|
*/
|
|
FHistoryFileListViewItem( const FString& InFileName )
|
|
: FileName(InFileName)
|
|
{
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* A container class to use the tree view to represent a dynamically expandable nested list
|
|
*/
|
|
struct FHistoryTreeItem
|
|
{
|
|
// Only one of FileListItem or RevisionListItem should be set
|
|
|
|
/** Pointer to file info */
|
|
TSharedPtr<FHistoryFileListViewItem> FileListItem;
|
|
/** Pointer to revision info */
|
|
TSharedPtr<FHistoryRevisionListViewItem> RevisionListItem;
|
|
|
|
/** If we are a revision entry, pointer to file entry that owns us */
|
|
TWeakPtr<FHistoryTreeItem> Parent;
|
|
/** List of revisions if we are file entry */
|
|
TArray< TSharedPtr<FHistoryTreeItem> > Children;
|
|
};
|
|
|
|
/**
|
|
* Attempts to get a file list-item that represents the file that specified
|
|
* history-tree entry belongs to.
|
|
*
|
|
* @param HistoryTreeItemIn The history-tree entry that you want a file item for.
|
|
* @return The file list-item that the specified entry conceptually belongs to (invalid if HistoryTreeItemIn was invalid).
|
|
*/
|
|
static TSharedPtr<FHistoryFileListViewItem> GetFileListItem(TSharedPtr<FHistoryTreeItem> HistoryTreeItemIn)
|
|
{
|
|
TSharedPtr<FHistoryFileListViewItem> FileListItem;
|
|
|
|
if (HistoryTreeItemIn.IsValid())
|
|
{
|
|
FileListItem = HistoryTreeItemIn->FileListItem;
|
|
|
|
// if this isn't a file list-item itself
|
|
if (!FileListItem.IsValid())
|
|
{
|
|
// then it should have a parent that is one
|
|
TSharedPtr<FHistoryTreeItem> ParentFileItem = HistoryTreeItemIn->Parent.Pin();
|
|
check(ParentFileItem.IsValid());
|
|
check(ParentFileItem->FileListItem.IsValid());
|
|
FileListItem = ParentFileItem->FileListItem;
|
|
}
|
|
}
|
|
|
|
return FileListItem;
|
|
}
|
|
|
|
/**
|
|
* Takes a history-tree entry and attempts to find a corresponding asset object
|
|
* for the specified revision. If the specified history item doesn't have a valid
|
|
* RevisionListItem (it's a file list-item), we take that to represent the current
|
|
* working version of the asset.
|
|
*
|
|
* @param HistoryTreeItemIn The history-tree entry that you want a corresponding object for.
|
|
* @return A UObject that represents the asset at the specified revision (NULL if we failed to find/create one).
|
|
*/
|
|
static UObject* GetAssetRevisionObject(TSharedPtr<FHistoryTreeItem> HistoryTreeItemIn)
|
|
{
|
|
UObject* AssetObject = NULL;
|
|
if (HistoryTreeItemIn.IsValid())
|
|
{
|
|
UPackage* AssetPackage = NULL; // need a package to find the asset in
|
|
|
|
TSharedPtr<FHistoryFileListViewItem> FileListItem = GetFileListItem(HistoryTreeItemIn);
|
|
check(FileListItem.IsValid());
|
|
|
|
TSharedPtr<FHistoryRevisionListViewItem> RevisionListItem = HistoryTreeItemIn->RevisionListItem;
|
|
// if this item is referencing a specific revision (and not the current working version of the asset)
|
|
if (RevisionListItem.IsValid()) // else,
|
|
{
|
|
// grab details on this file's state in source control (history, etc.)
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
FSourceControlStatePtr FileSourceControlState = SourceControlProvider.GetState(FileListItem->FileName, EStateCacheUsage::Use);
|
|
|
|
if (FileSourceControlState.IsValid())
|
|
{
|
|
// lookup the specific revision we want
|
|
TSharedPtr<ISourceControlRevision, ESPMode::ThreadSafe> FileRevision = FileSourceControlState->FindHistoryRevision(RevisionListItem->Revision);
|
|
|
|
FString TempPackageName;
|
|
if (FileRevision.IsValid() && FileRevision->Get(TempPackageName)) // grab the path to a temporary package (where the revision item will be stored)
|
|
{
|
|
// try and load the temporary package
|
|
AssetPackage = LoadPackage(NULL, *TempPackageName, LOAD_DisableCompileOnLoad);
|
|
}
|
|
} // if FileSourceControlState.IsValid()
|
|
}
|
|
else // if we want the current working version of this asset
|
|
{
|
|
FString AssetPackageName = FPackageName::FilenameToLongPackageName(FileListItem->FileName);
|
|
AssetPackage = FindObject<UPackage>(NULL, *AssetPackageName);
|
|
}
|
|
|
|
// grab the asset from the package - we assume asset name matches file name
|
|
FString AssetName = FPaths::GetBaseFilename(FileListItem->FileName);
|
|
AssetObject = FindObject<UObject>(AssetPackage, *AssetName);
|
|
|
|
} // if HistoryTreeItemIn.IsValid()
|
|
|
|
return AssetObject;
|
|
}
|
|
|
|
|
|
/**
|
|
* Constructs revision info for the specified history-tree entry.
|
|
*
|
|
* @param HistoryTreeItemIn The history-tree entry that you want revision info for.
|
|
* @param RevisionInfoOut The resulting revision info (out).
|
|
*/
|
|
static void GetRevisionInfo(TSharedPtr<FHistoryTreeItem> HistoryTreeItemIn, FRevisionInfo& RevisionInfoOut)
|
|
{
|
|
RevisionInfoOut.Revision = TEXT(""); // clear the revision info (empty string is used signify the current working version)
|
|
|
|
// if this is a specific revision item
|
|
if (HistoryTreeItemIn.IsValid() && HistoryTreeItemIn->RevisionListItem.IsValid())
|
|
{
|
|
TSharedPtr<FHistoryRevisionListViewItem> RevisionListItem = HistoryTreeItemIn->RevisionListItem;
|
|
|
|
// fill out the revision info
|
|
RevisionInfoOut.Revision = RevisionListItem->Revision;
|
|
RevisionInfoOut.Changelist = RevisionListItem->ChangelistNumber;
|
|
RevisionInfoOut.Date = RevisionListItem->Date;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Takes a array of FHistoryTreeItems and determines if the entries can all be diffed against each other.
|
|
*
|
|
* @param SelectedItems A array of FHistoryTreeItems that you want to diff against each other.
|
|
* @param ErrorTextOut Text explaining why the selected items cannot be diffed (only valid if the return value was false).
|
|
* @return True if the selected items could be diffed against each other, false if not.
|
|
*/
|
|
static bool CanDiffSelectedItems(TArray< TSharedPtr<FHistoryTreeItem> > const& SelectedItems, FText& ErrorTextOut)
|
|
{
|
|
bool bCanDiffSelected = false;
|
|
|
|
if (SelectedItems.Num() > 2)
|
|
{
|
|
ErrorTextOut = NSLOCTEXT("SourceControlHistory", "TooManyToDiff", "Cannot diff more than two revisions.");
|
|
}
|
|
else if (SelectedItems.Num() < 2)
|
|
{
|
|
ErrorTextOut = NSLOCTEXT("SourceControlHistory", "NotEnoughToDiff", "Need to select two revisions in order to compare one against the other.");
|
|
}
|
|
else
|
|
{
|
|
TSharedPtr<FHistoryTreeItem> FirstSelection = SelectedItems[0];
|
|
TSharedPtr<FHistoryTreeItem> SecondSelection = SelectedItems[1];
|
|
|
|
if (!FirstSelection.IsValid() || !SecondSelection.IsValid())
|
|
{
|
|
ErrorTextOut = NSLOCTEXT("SourceControlHistory", "InvalidSelection", "Invalid revisions selected.");
|
|
}
|
|
else if (FirstSelection == SecondSelection)
|
|
{
|
|
ErrorTextOut = NSLOCTEXT("SourceControlHistory", "CannotDiffWithSelf", "You cannot diff a revision against itself.");
|
|
}
|
|
else
|
|
{
|
|
// @TODO make sure the two selections match type (calling GetAssetRevisionObject() to compare class types is too slow)
|
|
bCanDiffSelected = true;
|
|
}
|
|
}
|
|
|
|
return bCanDiffSelected;
|
|
};
|
|
|
|
/**
|
|
* Takes two FHistoryTreeItems and attempts to diff them against each other (bringing up the diff window).
|
|
*
|
|
* @param FirstSelection The first item you want to diff.
|
|
* @param SecondSelection The second item you want to diff.
|
|
* @return True if a diff was performed, false if not.
|
|
*/
|
|
static bool DiffHistoryItems(TSharedPtr<FHistoryTreeItem> const FirstSelection, TSharedPtr<FHistoryTreeItem> const SecondSelection)
|
|
{
|
|
bool bDiffPerformed = false;
|
|
|
|
if (FirstSelection.IsValid() && SecondSelection.IsValid())
|
|
{
|
|
TSharedPtr<FHistoryFileListViewItem> FirstSelectionFileItem = GetFileListItem(FirstSelection);
|
|
TSharedPtr<FHistoryFileListViewItem> SecondSelectionFileItem = GetFileListItem(SecondSelection);
|
|
|
|
// we want to make sure the two selections are presented in a sensible order
|
|
UObject* LeftDiffAsset = NULL;
|
|
FRevisionInfo LeftVersionInfo;
|
|
UObject* RightDiffAsset = NULL;
|
|
FRevisionInfo RightVersionInfo;
|
|
|
|
bool bIsForSingleAsset = (FirstSelectionFileItem == SecondSelectionFileItem);
|
|
// if we're comparing two revisions for one asset
|
|
if (bIsForSingleAsset)
|
|
{
|
|
bool bFirstSelectionIsCurrentVersion = FirstSelection->FileListItem.IsValid();
|
|
bool bSecondSelectionIsCurrentVersion = SecondSelection->FileListItem.IsValid();
|
|
|
|
// the second selection is the newer revision iff the first isn't the current working version, and
|
|
// it's either the current working version itself, or a newer revision
|
|
bool bSecondSelectionIsNewer = !bFirstSelectionIsCurrentVersion &&
|
|
(bSecondSelectionIsCurrentVersion ||(SecondSelection->RevisionListItem->Date > FirstSelection->RevisionListItem->Date));
|
|
|
|
if (bSecondSelectionIsNewer)
|
|
{
|
|
RightDiffAsset = GetAssetRevisionObject(SecondSelection);
|
|
GetRevisionInfo(SecondSelection, RightVersionInfo);
|
|
LeftDiffAsset = GetAssetRevisionObject(FirstSelection);
|
|
GetRevisionInfo(FirstSelection, LeftVersionInfo);
|
|
}
|
|
else
|
|
{
|
|
LeftDiffAsset = GetAssetRevisionObject(SecondSelection);
|
|
GetRevisionInfo(SecondSelection, LeftVersionInfo);
|
|
RightDiffAsset = GetAssetRevisionObject(FirstSelection);
|
|
GetRevisionInfo(FirstSelection, RightVersionInfo);
|
|
}
|
|
}
|
|
else // else, we're comparing revisions from two separate assets
|
|
{
|
|
// keep them in selection order (left to right)
|
|
LeftDiffAsset = GetAssetRevisionObject(FirstSelection);
|
|
GetRevisionInfo(FirstSelection, LeftVersionInfo);
|
|
RightDiffAsset = GetAssetRevisionObject(SecondSelection);
|
|
GetRevisionInfo(SecondSelection, RightVersionInfo);
|
|
}
|
|
|
|
// if we have an asset object for both selections
|
|
if ((LeftDiffAsset != NULL) && (RightDiffAsset != NULL))
|
|
{
|
|
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
|
|
AssetToolsModule.Get().DiffAssets(LeftDiffAsset, RightDiffAsset, LeftVersionInfo, RightVersionInfo);
|
|
|
|
bDiffPerformed = true;
|
|
}
|
|
}
|
|
|
|
return bDiffPerformed;
|
|
}
|
|
|
|
/**
|
|
* A FDragDropOperation that represents dragging a source-control history tree item around.
|
|
*/
|
|
class FSourceControlHistoryRowDragDropOp : public FDragDropOperation
|
|
{
|
|
private:
|
|
/**
|
|
* Stubbed private constructor (in order to force use of the static New() method).
|
|
*/
|
|
FSourceControlHistoryRowDragDropOp()
|
|
: PendingDropAction(EDropAction::None)
|
|
{
|
|
}
|
|
|
|
public:
|
|
/**
|
|
* Allocates and registers a new FSourceControlHistoryRowDragDropOp for use.
|
|
*
|
|
* @return The newly allocated (and registered) instance.
|
|
*/
|
|
static TSharedRef<FSourceControlHistoryRowDragDropOp> New()
|
|
{
|
|
TSharedPtr<FSourceControlHistoryRowDragDropOp> NewOperation = MakeShareable(new FSourceControlHistoryRowDragDropOp);
|
|
NewOperation->Construct();
|
|
|
|
return NewOperation.ToSharedRef();
|
|
}
|
|
|
|
DRAG_DROP_OPERATOR_TYPE(FSourceControlHistoryRowDragDropOp, FDragDropOperation)
|
|
|
|
struct EDropAction
|
|
{
|
|
enum Type
|
|
{
|
|
None,
|
|
Diff,
|
|
};
|
|
};
|
|
/** An enum value detailing what operation is queued to happen (if this item is dropped) */
|
|
EDropAction::Type PendingDropAction;
|
|
|
|
/** The items that this operation is conceptually dragging around */
|
|
TArray< TSharedPtr<FHistoryTreeItem> > SelectedItems;
|
|
|
|
/** Text to display with the widget being dragged around */
|
|
FText HoverText;
|
|
|
|
/**
|
|
* Creates the visual widget that you drag around (to help visualize the drag/drop operation.
|
|
*
|
|
* @return A new slate widget representing the dragged item
|
|
*/
|
|
virtual TSharedPtr<SWidget> GetDefaultDecorator() const override
|
|
{
|
|
return SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("Graph.ConnectorFeedback.Border"))
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(0,0,3,0)
|
|
[
|
|
SNew(SImage)
|
|
.Image(this, &FSourceControlHistoryRowDragDropOp::GetIcon)
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &FSourceControlHistoryRowDragDropOp::GetHoverText)
|
|
]
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Easy accessor function for getting at the HoverText variable (provides a
|
|
* default one if HoverText is empty).
|
|
*
|
|
* @return HoverText if it's not empty, otherwise: a default string describing that dropping would result in nothing.
|
|
*/
|
|
FText GetHoverText() const
|
|
{
|
|
return !HoverText.IsEmpty()
|
|
? HoverText
|
|
: NSLOCTEXT("SourceControlHistory", "DropActionToolTip_InvalidDropTarget", "Cannot drop here.");
|
|
}
|
|
|
|
/**
|
|
* Returns a icon brush corresponding to this operation's pending drop action.
|
|
*
|
|
* @return An 'error' icon if there is no pending action, otherwise an 'OK' icon.
|
|
*/
|
|
FSlateBrush const* GetIcon() const
|
|
{
|
|
return PendingDropAction != EDropAction::None
|
|
? FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.OK"))
|
|
: FEditorStyle::GetBrush(TEXT("Graph.ConnectorFeedback.Error"));
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Class used to construct the ordered row content for revision data
|
|
*/
|
|
class SHistoryRevisionListRowContent : public SMultiColumnTableRow< TSharedPtr<FHistoryTreeItem> >
|
|
{
|
|
public:
|
|
|
|
SLATE_BEGIN_ARGS( SHistoryRevisionListRowContent )
|
|
: _RevisionListItem()
|
|
{}
|
|
SLATE_EVENT( FOnDragDetected, OnDragDetected )
|
|
SLATE_EVENT( FOnTableRowDragEnter, OnDragEnter )
|
|
SLATE_EVENT( FOnTableRowDragLeave, OnDragLeave )
|
|
SLATE_EVENT( FOnTableRowDrop, OnDrop )
|
|
|
|
SLATE_ARGUMENT( TSharedPtr<FHistoryRevisionListViewItem>, RevisionListItem )
|
|
|
|
/** Whether we should display the expander for this item as it has children */
|
|
SLATE_ARGUMENT( bool, HasChildren )
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
/**
|
|
* Construct the widget
|
|
*
|
|
* @param InArgs A declaration from which to construct the widget
|
|
*/
|
|
void Construct( const FArguments& InArgs, const TSharedRef<STableViewBase>& InOwnerTableView )
|
|
{
|
|
RevisionListItem = InArgs._RevisionListItem;
|
|
check(RevisionListItem.IsValid());
|
|
|
|
bHasChildren = InArgs._HasChildren;
|
|
|
|
SMultiColumnTableRow< TSharedPtr<FHistoryTreeItem> >::Construct(
|
|
FSuperRowType::FArguments()
|
|
.OnDragDetected(InArgs._OnDragDetected)
|
|
.OnDragEnter(InArgs._OnDragEnter)
|
|
.OnDragLeave(InArgs._OnDragLeave)
|
|
.OnDrop(InArgs._OnDrop),
|
|
InOwnerTableView
|
|
);
|
|
}
|
|
|
|
virtual TSharedRef<SWidget> GenerateWidgetForColumn( const FName& ColumnName ) override
|
|
{
|
|
check(RevisionListItem.IsValid());
|
|
|
|
if ( ColumnName == TEXT("Revision") )
|
|
{
|
|
|
|
FString SCCAction = RevisionListItem->Action;
|
|
FName ResourceKey;
|
|
if (SCCAction == FString(TEXT("add")))
|
|
{
|
|
ResourceKey = TEXT("SourceControl.Add");
|
|
}
|
|
else if (SCCAction == FString(TEXT("edit")))
|
|
{
|
|
ResourceKey = TEXT("SourceControl.Edit");
|
|
}
|
|
else if (SCCAction == FString(TEXT("delete")))
|
|
{
|
|
ResourceKey = TEXT("SourceControl.Delete");
|
|
}
|
|
else if (SCCAction == FString(TEXT("branch")))
|
|
{
|
|
ResourceKey = TEXT("SourceControl.Branch");
|
|
}
|
|
else if (SCCAction == FString(TEXT("integrate")))
|
|
{
|
|
ResourceKey = TEXT("SourceControl.Integrate");
|
|
}
|
|
else
|
|
{
|
|
ResourceKey = TEXT("SourceControl.Edit");
|
|
}
|
|
|
|
// Rows in a tree need to show an SExpanderArrow (it also indents!) to give the appearance of being a tree.
|
|
return
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.HAlign(HAlign_Right)
|
|
.VAlign(VAlign_Fill)
|
|
[
|
|
SNew(SExpanderArrow, SharedThis(this) )
|
|
.Visibility(this, &SHistoryRevisionListRowContent::GetExpanderVisibility)
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
.Padding(10,0,10,0)
|
|
.HAlign(HAlign_Center)
|
|
.VAlign(VAlign_Center)
|
|
[
|
|
SNew(SImage)
|
|
.Image(FEditorStyle::GetBrush(ResourceKey))
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.AutoWidth()
|
|
[
|
|
SNew(STextBlock)
|
|
.Text( FText::FromString(RevisionListItem->Revision) )
|
|
];
|
|
}
|
|
else if (ColumnName == TEXT("Changelist"))
|
|
{
|
|
return
|
|
SNew(STextBlock)
|
|
.Text( FText::AsNumber( RevisionListItem->ChangelistNumber, NULL, FInternationalization::Get().GetInvariantCulture() ) ) ;
|
|
}
|
|
else if (ColumnName == TEXT("Date"))
|
|
{
|
|
return
|
|
SNew(STextBlock)
|
|
.Text( RevisionListItem->Date > FDateTime::MinValue() == 0 ? FText() : FText::AsDateTime( RevisionListItem->Date ) );
|
|
}
|
|
else if (ColumnName == TEXT("UserName"))
|
|
{
|
|
return
|
|
SNew(STextBlock)
|
|
.Text( FText::FromString( RevisionListItem->UserName ) );
|
|
}
|
|
else if (ColumnName == TEXT("Description"))
|
|
{
|
|
// Cut down the description to a single line for the list view
|
|
FString SingleLineDescription = RevisionListItem->Description;
|
|
int32 NewLinePos;
|
|
if (SingleLineDescription.FindChar(TCHAR('\n'), NewLinePos))
|
|
{
|
|
SingleLineDescription = SingleLineDescription.Left(NewLinePos);
|
|
}
|
|
|
|
// Trim any trailing new-line characters from the description for the tooltip
|
|
FString TooltipDescription = RevisionListItem->Description;
|
|
while(TooltipDescription.Len() && FChar::IsLinebreak(TooltipDescription[TooltipDescription.Len() - 1]))
|
|
{
|
|
TooltipDescription.RemoveAt(TooltipDescription.Len() - 1, 1, false);
|
|
}
|
|
|
|
return
|
|
SNew(STextBlock)
|
|
.Text(FText::FromString(SingleLineDescription))
|
|
.ToolTipText(FText::FromString(TooltipDescription));
|
|
}
|
|
else
|
|
{
|
|
return
|
|
SNew(STextBlock)
|
|
. Text( FText::Format( NSLOCTEXT("SourceControlHistory", "UnsupportedColumn", "Unsupported Column: {0}"), FText::FromName( ColumnName ) ) );
|
|
}
|
|
}
|
|
|
|
EVisibility GetExpanderVisibility() const
|
|
{
|
|
return bHasChildren ? EVisibility::Visible : EVisibility::Collapsed;
|
|
}
|
|
|
|
private:
|
|
TSharedPtr<FHistoryRevisionListViewItem> RevisionListItem;
|
|
|
|
/** Whether we should display the expander for this item as it has children */
|
|
bool bHasChildren;
|
|
};
|
|
|
|
/** Panel designed to display the revision history of a package */
|
|
class SSourceControlHistoryWidget : public SCompoundWidget
|
|
{
|
|
public:
|
|
SLATE_BEGIN_ARGS( SSourceControlHistoryWidget )
|
|
: _ParentWindow()
|
|
, _SourceControlStates()
|
|
{}
|
|
|
|
SLATE_ATTRIBUTE( TSharedPtr<SWindow>, ParentWindow )
|
|
SLATE_ATTRIBUTE( TArray< FSourceControlStateRef >, SourceControlStates)
|
|
|
|
SLATE_END_ARGS()
|
|
|
|
|
|
SSourceControlHistoryWidget()
|
|
{
|
|
}
|
|
|
|
void Construct( const FArguments& InArgs )
|
|
{
|
|
AddHistoryInfo(InArgs._SourceControlStates.Get());
|
|
|
|
TSharedRef<SHeaderRow> HeaderRow = SNew(SHeaderRow);
|
|
|
|
const bool bUsesChangelists = ISourceControlModule::Get().GetProvider().UsesChangelists();
|
|
|
|
HeaderRow->AddColumn(SHeaderRow::FColumn::FArguments().ColumnId("Revision") .DefaultLabel(NSLOCTEXT("SourceControl.HistoryPanel.Header", "Revision", "Revision")) .FillWidth(bUsesChangelists ? 100 : 200));
|
|
if(bUsesChangelists)
|
|
{
|
|
HeaderRow->AddColumn(SHeaderRow::FColumn::FArguments().ColumnId("Changelist") .DefaultLabel(NSLOCTEXT("SourceControl.HistoryPanel.Header", "Changelist", "ChangeList")) .FillWidth(100));
|
|
}
|
|
HeaderRow->AddColumn(SHeaderRow::FColumn::FArguments().ColumnId("Date") .DefaultLabel(NSLOCTEXT("SourceControl.HistoryPanel.Header", "Date", "Date Submitted")) .FillWidth(250));
|
|
HeaderRow->AddColumn(SHeaderRow::FColumn::FArguments().ColumnId("UserName") .DefaultLabel(NSLOCTEXT("SourceControl.HistoryPanel.Header", "UserName", "Submitted By")) .FillWidth(200));
|
|
HeaderRow->AddColumn(SHeaderRow::FColumn::FArguments().ColumnId("Description") .DefaultLabel(NSLOCTEXT("SourceControl.HistoryPanel.Header", "Description", "Description")) .FillWidth(650));
|
|
|
|
ChildSlot
|
|
[
|
|
SNew(SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
.BorderBackgroundColor(FLinearColor(0.5f,0.5f,0.5f,1.f))
|
|
[
|
|
SNew(SSplitter)
|
|
.Orientation(Orient_Vertical)
|
|
+SSplitter::Slot()
|
|
.Value(0.5f)
|
|
[
|
|
SNew(SBorder)
|
|
[
|
|
SNew(SBox)
|
|
.WidthOverride(600)
|
|
[
|
|
SAssignNew( MainHistoryListView, SHistoryFileListType)
|
|
.TreeItemsSource( &HistoryCollection )
|
|
.ItemHeight(25.f)
|
|
.SelectionMode(ESelectionMode::Multi)
|
|
.OnSelectionChanged(this, &SSourceControlHistoryWidget::OnRevisionPropertyChanged)
|
|
.OnGenerateRow( this, &SSourceControlHistoryWidget::OnGenerateRowForHistoryFileList )
|
|
.OnGetChildren( this, &SSourceControlHistoryWidget::OnGetChildrenForHistoryFileList )
|
|
.OnContextMenuOpening(this, &SSourceControlHistoryWidget::OnCreateContextMenu )
|
|
.HeaderRow
|
|
(
|
|
HeaderRow
|
|
)
|
|
]
|
|
]
|
|
]
|
|
|
|
+SSplitter::Slot()
|
|
.Value(0.5f)
|
|
[
|
|
SAssignNew(AdditionalInfoItemsControl,SBorder)
|
|
.BorderImage(FEditorStyle::GetBrush("ToolPanel.GroupBorder"))
|
|
[
|
|
GetAdditionalInfoItemsControlContent()
|
|
]
|
|
]
|
|
]
|
|
];
|
|
|
|
//expand the top level nodes...
|
|
for (int32 i=0; i<HistoryCollection.Num(); i++)
|
|
{
|
|
MainHistoryListView->SetItemExpansion(HistoryCollection[i],true);
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
/**
|
|
* Constructs the "Additional Info" panel that displays specific revision info
|
|
*/
|
|
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
TSharedRef<SWidget> GetAdditionalInfoItemsControlContent()
|
|
{
|
|
const float Padding = 2.f;
|
|
|
|
return
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
[
|
|
SNew(SHorizontalBox)
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(0.25f)
|
|
[
|
|
//Text Column
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "Revision", "Revision:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "Date", "Date Submitted:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "SubmittedBy", "Submitted By:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "Action", "Action:"))
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(0.25f)
|
|
.Padding(20,0)
|
|
[
|
|
//Data column
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetRevisionNumber)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetDate)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetUserName)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetAction)
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(0.25f)
|
|
.Padding(50,0)
|
|
[
|
|
//Text Column
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "Changelist", "Changelist:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "Workspace", "Workspace:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "FileSize", "File Size:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "BranchedFrom", "Branched From:"))
|
|
]
|
|
]
|
|
+SHorizontalBox::Slot()
|
|
.FillWidth(0.25f)
|
|
.Padding(20,0)
|
|
[
|
|
//Data column
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetChangelistNumber)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetClientSpec)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetFileSize)
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(0.25f)
|
|
.Padding(Padding)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetBranchedFrom)
|
|
]
|
|
]
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(Padding, 10, Padding, 5)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(NSLOCTEXT("SourceControl.HistoryPanel.Info", "Description", "Description:"))
|
|
]
|
|
+SVerticalBox::Slot()
|
|
.FillHeight(1.0f)
|
|
[
|
|
SNew(SBorder)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(5)
|
|
[
|
|
SNew(STextBlock)
|
|
.Text(this, &SSourceControlHistoryWidget::GetDescription)
|
|
]
|
|
]
|
|
]
|
|
;
|
|
}
|
|
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
|
|
|
|
/** Get the last selected revision's revision number */
|
|
FText GetRevisionNumber() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
return FText::FromString(LastSelectedRevisionItem.Pin()->Revision);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's date */
|
|
FText GetDate() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid() && LastSelectedRevisionItem.Pin()->Date != 0)
|
|
{
|
|
return FText::AsDateTime(LastSelectedRevisionItem.Pin()->Date);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's username */
|
|
FText GetUserName() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
return FText::FromString(LastSelectedRevisionItem.Pin()->UserName);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's revision number */
|
|
FText GetAction() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
return FText::FromString(LastSelectedRevisionItem.Pin()->Action);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's changelist number */
|
|
FText GetChangelistNumber() const
|
|
{
|
|
static const bool bUsesChangelists = ISourceControlModule::Get().GetProvider().UsesChangelists();
|
|
if(LastSelectedRevisionItem.IsValid() && bUsesChangelists)
|
|
{
|
|
// don't group the CL# as Perforce doesn't display it that way
|
|
return FText::AsNumber(LastSelectedRevisionItem.Pin()->ChangelistNumber, &FNumberFormattingOptions::DefaultNoGrouping());
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's client spec */
|
|
FText GetClientSpec() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
return FText::FromString(LastSelectedRevisionItem.Pin()->ClientSpec);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's file size */
|
|
FText GetFileSize() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
static const FNumberFormattingOptions FileSizeFormatOptions = FNumberFormattingOptions()
|
|
.SetMinimumFractionalDigits(1)
|
|
.SetMaximumFractionalDigits(1);
|
|
return FText::Format(
|
|
NSLOCTEXT("SourceControlHistory", "FileSizeInMBFmt", "{0} MB"),
|
|
FText::AsNumber(((float)LastSelectedRevisionItem.Pin()->FileSize) / (1024.f * 1024.f), &FileSizeFormatOptions)
|
|
);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's description */
|
|
FText GetDescription() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
return FText::FromString(LastSelectedRevisionItem.Pin()->Description);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/** Get the last selected revision's description */
|
|
FText GetBranchedFrom() const
|
|
{
|
|
if(LastSelectedRevisionItem.IsValid())
|
|
{
|
|
return FText::FromString(LastSelectedRevisionItem.Pin()->BranchSource);
|
|
}
|
|
return FText::GetEmpty();
|
|
}
|
|
|
|
/**
|
|
* Generates the content of each row, displaying a the File or Revision data for its corresponding type
|
|
*/
|
|
TSharedRef<ITableRow> OnGenerateRowForHistoryFileList( TSharedPtr<FHistoryTreeItem> TreeItemPtr, const TSharedRef<STableViewBase>& OwnerTable )
|
|
{
|
|
TSharedPtr<SWidget> RowContent;
|
|
if (TreeItemPtr->FileListItem.IsValid())
|
|
{
|
|
TSharedPtr<FHistoryFileListViewItem> FileListItem = TreeItemPtr->FileListItem;
|
|
|
|
return
|
|
SNew(STableRow< TSharedPtr<FName> >, OwnerTable)
|
|
[
|
|
SNew(SVerticalBox)
|
|
+SVerticalBox::Slot()
|
|
.AutoHeight()
|
|
.Padding(5)
|
|
[
|
|
SNew( STextBlock )
|
|
.Font( FEditorStyle::GetFontStyle( TEXT("BoldFont") ))
|
|
.Text( FText::FromString(FileListItem->FileName) )
|
|
]
|
|
]
|
|
.OnDragDetected(this, &SSourceControlHistoryWidget::OnRowDragDetected)
|
|
.OnDragEnter(this, &SSourceControlHistoryWidget::OnRowDragEnter, TreeItemPtr)
|
|
.OnDragLeave(this, &SSourceControlHistoryWidget::OnRowDragLeave)
|
|
.OnDrop(this, &SSourceControlHistoryWidget::OnRowDrop, TreeItemPtr);
|
|
}
|
|
else if (TreeItemPtr->RevisionListItem.IsValid())
|
|
{
|
|
TSharedPtr<FHistoryRevisionListViewItem> RevisionListItem = TreeItemPtr->RevisionListItem;
|
|
|
|
return
|
|
SNew(SHistoryRevisionListRowContent, OwnerTable)
|
|
.RevisionListItem(RevisionListItem)
|
|
.OnDragDetected(this, &SSourceControlHistoryWidget::OnRowDragDetected)
|
|
.OnDragEnter(this, &SSourceControlHistoryWidget::OnRowDragEnter, TreeItemPtr)
|
|
.OnDragLeave(this, &SSourceControlHistoryWidget::OnRowDragLeave)
|
|
.OnDrop(this, &SSourceControlHistoryWidget::OnRowDrop, TreeItemPtr)
|
|
.HasChildren(TreeItemPtr->Children.Num() > 0);
|
|
}
|
|
|
|
//we should never get here...
|
|
return
|
|
SNew(STableRow< TSharedPtr<FName> >, OwnerTable)
|
|
[
|
|
SNew( STextBlock )
|
|
.Text( NSLOCTEXT("SourceControlHistory", "ErrorMessage", "---ERROR---") )
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Fill out the tree structure with the SSC data
|
|
*/
|
|
void AddHistoryInfo( const TArray< FSourceControlStateRef >& InStates )
|
|
{
|
|
// Construct a new observable collection to serve as the items source for the main list view. It will contain each history file item.
|
|
for( TArray< FSourceControlStateRef >::TConstIterator Iter(InStates); Iter; Iter++)
|
|
{
|
|
FSourceControlStateRef SourceControlState = *Iter;
|
|
TSharedPtr<FHistoryTreeItem> FileItem = MakeShareable(new FHistoryTreeItem());
|
|
FileItem->FileListItem = MakeShareable(new FHistoryFileListViewItem( SourceControlState->GetFilename() ));
|
|
|
|
// Add each file revision
|
|
for ( int HistoryIndex = 0; HistoryIndex < SourceControlState->GetHistorySize(); HistoryIndex++ )
|
|
{
|
|
TSharedPtr<ISourceControlRevision, ESPMode::ThreadSafe> Revision = SourceControlState->GetHistoryItem(HistoryIndex);
|
|
check(Revision.IsValid());
|
|
TSharedPtr<FHistoryTreeItem> RevisionItem = MakeShareable(new FHistoryTreeItem());
|
|
RevisionItem->RevisionListItem = MakeShareable(new FHistoryRevisionListViewItem( Revision.ToSharedRef() ));
|
|
FileItem->Children.Add(RevisionItem);
|
|
RevisionItem->Parent = FileItem;
|
|
|
|
// add branch items if we have one
|
|
if(Revision->GetBranchSource().IsValid())
|
|
{
|
|
TSharedPtr<FHistoryTreeItem> BranchFileItem = MakeShareable(new FHistoryTreeItem());
|
|
|
|
const FString BranchRevisionName = FString::Printf(TEXT("%s #%d"), *Revision->GetBranchSource()->GetFilename(), Revision->GetBranchSource()->GetRevisionNumber());
|
|
BranchFileItem->FileListItem = MakeShareable(new FHistoryFileListViewItem( BranchRevisionName ));
|
|
RevisionItem->Children.Add(BranchFileItem);
|
|
BranchFileItem->Parent = RevisionItem;
|
|
}
|
|
}
|
|
|
|
HistoryCollection.Add(FileItem);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Callback returns the revision history (Children) nodes for the file (InItem) node
|
|
*/
|
|
void OnGetChildrenForHistoryFileList( TSharedPtr< FHistoryTreeItem > InItem, TArray< TSharedPtr<FHistoryTreeItem> >& OutChildren )
|
|
{
|
|
OutChildren = InItem->Children;
|
|
}
|
|
|
|
/**
|
|
* Called whenever the IsSelected property on a MHistoryRevisionListViewItem changes. Used to specify the last selected revision item.
|
|
*
|
|
* @param Owner Object which triggered the event
|
|
* @param Args Event arguments for the property change
|
|
*/
|
|
void OnRevisionPropertyChanged(TSharedPtr<FHistoryTreeItem> Item, ESelectInfo::Type SelectInfo)
|
|
{
|
|
LastSelectedRevisionItem.Reset();
|
|
if (Item.IsValid())
|
|
{
|
|
if (Item->RevisionListItem.IsValid())
|
|
{
|
|
LastSelectedRevisionItem = Item->RevisionListItem;
|
|
}
|
|
else if (Item->Children.Num() > 0 && Item->Children[0]->RevisionListItem.IsValid())
|
|
{
|
|
LastSelectedRevisionItem = Item->Children[0]->RevisionListItem;
|
|
}
|
|
}
|
|
|
|
|
|
AdditionalInfoItemsControl->SetContent(GetAdditionalInfoItemsControlContent());
|
|
}
|
|
|
|
/** Called to create a context menu when right-clicking on a history item */
|
|
TSharedPtr< SWidget > OnCreateContextMenu()
|
|
{
|
|
FMenuBuilder MenuBuilder( true, NULL );
|
|
|
|
MenuBuilder.AddMenuEntry(
|
|
NSLOCTEXT("SourceControl.HistoryWindow.Menu", "DiffAgainstPrev", "Diff Against Previous Revision"),
|
|
NSLOCTEXT("SourceControl.HistoryWindow.Menu", "DiffAgainstPrevTooltip", "See changes between this revision and the previous one."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateSP( this, &SSourceControlHistoryWidget::OnDiffAgainstPreviousRev ),
|
|
FCanExecuteAction::CreateSP(this, &SSourceControlHistoryWidget::CanDiffAgainstPreviousRev)
|
|
)
|
|
);
|
|
|
|
if (CanDiffSelected())
|
|
{
|
|
MenuBuilder.AddMenuEntry(
|
|
NSLOCTEXT("SourceControl.HistoryWindow.Menu", "DiffSelected", "Diff Selected"),
|
|
NSLOCTEXT("SourceControl.HistoryWindow.Menu", "DiffSelectedTooltip", "Diff the two assets that you have selected."),
|
|
FSlateIcon(),
|
|
FUIAction(
|
|
FExecuteAction::CreateSP(this, &SSourceControlHistoryWidget::OnDiffSelected)
|
|
)
|
|
);
|
|
}
|
|
|
|
return MenuBuilder.MakeWidget();
|
|
}
|
|
|
|
/** See if we should enabled the 'diff against previous' option */
|
|
bool CanDiffAgainstPreviousRev() const
|
|
{
|
|
// Only allow option if we selected one item and it was a revision, not a file entry
|
|
TArray< TSharedPtr<FHistoryTreeItem> > SelectedRevs = MainHistoryListView->GetSelectedItems();
|
|
return( SelectedRevs.Num() == 1 && SelectedRevs[0].IsValid() );
|
|
}
|
|
|
|
/** Try and perfom a diff between the selected revision and the previous one */
|
|
void OnDiffAgainstPreviousRev()
|
|
{
|
|
TArray< TSharedPtr<FHistoryTreeItem> > SelectedRevs = MainHistoryListView->GetSelectedItems();
|
|
|
|
if(SelectedRevs.Num() > 0 && SelectedRevs[0].IsValid())
|
|
{
|
|
FAssetToolsModule& AssetToolsModule = FModuleManager::LoadModuleChecked<FAssetToolsModule>(TEXT("AssetTools"));
|
|
|
|
TSharedPtr<FHistoryTreeItem> SelectedItem = SelectedRevs[0];
|
|
UObject* SelectedAsset = GetAssetRevisionObject(SelectedItem);
|
|
|
|
if (SelectedItem->RevisionListItem.IsValid())
|
|
{
|
|
TSharedPtr<FHistoryTreeItem> FileItem = SelectedItem->Parent.Pin();
|
|
check(FileItem.IsValid());
|
|
|
|
// Now we need to find previous revision
|
|
TSharedPtr<FHistoryTreeItem> PreRevisionItem;
|
|
|
|
// First, find index of selected revision in its parent file item
|
|
// NB. 0 is newest, increasing index means older
|
|
int32 RevIndex = FileItem->Children.Find(SelectedItem);
|
|
check(RevIndex != INDEX_NONE);
|
|
if(RevIndex == FileItem->Children.Num()-1) // If oldest revision of this file
|
|
{
|
|
// .. see if we have an older file
|
|
int32 FileIndex = HistoryCollection.Find(FileItem);
|
|
check(FileIndex != INDEX_NONE);
|
|
// Do nothing if we selected the newest revision of the newest file...
|
|
if(FileIndex < HistoryCollection.Num()-1)
|
|
{
|
|
// Previous revision is a different file, so get the newest revision of the older file
|
|
TSharedPtr<FHistoryTreeItem> PrevFileItem = HistoryCollection[FileIndex+1];
|
|
check(PrevFileItem.IsValid());
|
|
if(PrevFileItem->Children.Num() > 0)
|
|
{
|
|
PreRevisionItem = PrevFileItem->Children[0];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Not the oldest revision of this file, grab the older entry and get revision number
|
|
PreRevisionItem = FileItem->Children[RevIndex+1];
|
|
}
|
|
|
|
UObject* PreviousAsset = GetAssetRevisionObject(PreRevisionItem);
|
|
|
|
if ((SelectedAsset != NULL) && (PreviousAsset != NULL))
|
|
{
|
|
FRevisionInfo OldRevisionInfo;
|
|
GetRevisionInfo(PreRevisionItem, OldRevisionInfo);
|
|
FRevisionInfo NewRevisionInfo;
|
|
GetRevisionInfo(SelectedItem, NewRevisionInfo);
|
|
|
|
AssetToolsModule.Get().DiffAssets(PreviousAsset, SelectedAsset, OldRevisionInfo, NewRevisionInfo);
|
|
}
|
|
else
|
|
{
|
|
FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("SourceControl.HistoryWindow", "UnableToLoadAssets", "Unable to load assets to diff. Content may no longer be supported?"));
|
|
}
|
|
}
|
|
else if (SelectedAsset != NULL)
|
|
{
|
|
// this should be a file list-item (representing the current working version)
|
|
check(SelectedItem->FileListItem.IsValid());
|
|
|
|
FString const AssetName = SelectedAsset->GetName();
|
|
FString const PackageName = FPackageName::FilenameToLongPackageName(SelectedItem->FileListItem->FileName);
|
|
AssetToolsModule.Get().DiffAgainstDepot(SelectedAsset, PackageName, AssetName);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks to see if the selected history-tree items can be diffed against each other.
|
|
*
|
|
* @return True if the selected items can be diffed, false if not.
|
|
*/
|
|
bool CanDiffSelected() const
|
|
{
|
|
// throw away text so we can utilize a shared utility method
|
|
FText ThrowAwayErrorText;
|
|
|
|
TArray< TSharedPtr<FHistoryTreeItem> > SelectedRevs = MainHistoryListView->GetSelectedItems();
|
|
return CanDiffSelectedItems(SelectedRevs, ThrowAwayErrorText);
|
|
}
|
|
|
|
/**
|
|
* Takes the two selected history items and finds a UObject asset for each,
|
|
* then attempts to open a diff window to compare them.
|
|
*/
|
|
void OnDiffSelected() const
|
|
{
|
|
TArray< TSharedPtr<FHistoryTreeItem> > SelectedRevs = MainHistoryListView->GetSelectedItems();
|
|
if (SelectedRevs.Num() >= 2)
|
|
{
|
|
if (!DiffHistoryItems(SelectedRevs[0], SelectedRevs[1]))
|
|
{
|
|
FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("SourceControl.HistoryWindow", "UnableToLoadAssets", "Unable to load assets to diff. Content may no longer be supported?"));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An event handler for mouse drag detection events. Intended to be used as a delegate for
|
|
* history tree rows. Creates a FSourceControlHistoryRowDragDropOp (if the drag was with
|
|
* the left mouse-button) and assumes that all the selected items are the objects being dragged.
|
|
*
|
|
* @param MyGeometry The geometry for the dragged widget.
|
|
* @param MouseEvent Describes the mouse drag action (from when the drag was detected).
|
|
* @return A reply detailing how this event was handled ("Unhandled" if the click was not a left-click).
|
|
*/
|
|
FReply OnRowDragDetected(FGeometry const& MyGeometry, FPointerEvent const& MouseEvent) const
|
|
{
|
|
if (MouseEvent.IsMouseButtonDown(EKeys::LeftMouseButton)) //can only drag when editing
|
|
{
|
|
TSharedRef<FSourceControlHistoryRowDragDropOp> DragOperation = FSourceControlHistoryRowDragDropOp::New();
|
|
|
|
// assume that what we're dragging is what we have selected
|
|
DragOperation->SelectedItems = MainHistoryListView->GetSelectedItems();
|
|
check(DragOperation->SelectedItems.Num() > 0);
|
|
|
|
return FReply::Handled().BeginDragDrop(DragOperation);
|
|
}
|
|
else
|
|
{
|
|
return FReply::Unhandled();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An event handler for mouse drag enter events. Intended to be used as a delegate for
|
|
* history tree rows. Only handles FSourceControlHistoryRowDragDropOp drag/drop operations.
|
|
* Updates the FSourceControlHistoryRowDragDropOp to reflect if a drop action is doable
|
|
* (when over this item).
|
|
*
|
|
* @param DragDropEvent The drag/drop operation that triggered this handler.
|
|
* @param HoveredItem The history tree item that is conceptually being hovered over.
|
|
*/
|
|
void OnRowDragEnter(FDragDropEvent const& DragDropEvent, TSharedPtr<FHistoryTreeItem> const HoveredItem) const
|
|
{
|
|
TSharedPtr<FSourceControlHistoryRowDragDropOp> DragRowOp = DragDropEvent.GetOperationAs<FSourceControlHistoryRowDragDropOp>();
|
|
if (DragRowOp.IsValid())
|
|
{
|
|
DragRowOp->PendingDropAction = FSourceControlHistoryRowDragDropOp::EDropAction::None;
|
|
|
|
TArray< TSharedPtr<FHistoryTreeItem> > DiffingItems = DragRowOp->SelectedItems;
|
|
check(HoveredItem.IsValid());
|
|
DiffingItems.Add(HoveredItem);
|
|
|
|
if (CanDiffSelectedItems(DiffingItems, DragRowOp->HoverText))
|
|
{
|
|
DragRowOp->PendingDropAction = FSourceControlHistoryRowDragDropOp::EDropAction::Diff;
|
|
|
|
FText const RevisionFormatText = NSLOCTEXT("SourceControlHistory", "Revision", "Revision {0}");
|
|
FText const CurrentRevisionText = NSLOCTEXT("SourceControlHistory", "CurrentRevsion", "Current Revision");
|
|
|
|
check(DragRowOp->SelectedItems.Num() > 0);
|
|
TSharedPtr<FHistoryTreeItem> DraggedItem = DiffingItems[0];
|
|
// set text identifying the dragged item's revision (current version vs. revision X)
|
|
FText DraggedRevisionText = CurrentRevisionText;
|
|
if (DraggedItem->RevisionListItem.IsValid())
|
|
{
|
|
DraggedRevisionText = FText::Format(RevisionFormatText, FText::FromString(DraggedItem->RevisionListItem->Revision));
|
|
}
|
|
|
|
// set text identifying the hovered item's revision (current version vs. revision X)
|
|
FText HoveredRevisionText = CurrentRevisionText;
|
|
if (HoveredItem->RevisionListItem.IsValid())
|
|
{
|
|
HoveredRevisionText = FText::Format(RevisionFormatText, FText::FromString(HoveredItem->RevisionListItem->Revision));
|
|
}
|
|
|
|
TSharedPtr<FHistoryFileListViewItem> const DraggedFileItem = GetFileListItem(DraggedItem);
|
|
// convert DraggedRevisionText from the form "revision X" (or "the current version") to
|
|
// "revision X of <filename>"
|
|
FString const DraggedFileName = FPaths::GetBaseFilename(DraggedFileItem->FileName);
|
|
FText const NamedRevisionTextFormat = NSLOCTEXT("SourceControlHistory", "NamedRevision", "{0} ({1})");
|
|
DraggedRevisionText = FText::Format(NamedRevisionTextFormat, FText::FromString(DraggedFileName), DraggedRevisionText);
|
|
|
|
TSharedPtr<FHistoryFileListViewItem> const HoveredFileItem = GetFileListItem(HoveredItem);
|
|
// if we're diffing two separate files against each other
|
|
if (DraggedFileItem != HoveredFileItem)
|
|
{
|
|
// need to separately identify the hovered over item
|
|
FString const HoveredFileName = FPaths::GetBaseFilename(HoveredFileItem->FileName);
|
|
HoveredRevisionText = FText::Format(NamedRevisionTextFormat, FText::FromString(HoveredFileName), HoveredRevisionText);
|
|
}
|
|
|
|
FText const DropToDiffTextFormat = NSLOCTEXT("SourceControlHistory", "DropToDiff", "Drop {0} to diff against: {1}.");
|
|
DragRowOp->HoverText = FText::Format(DropToDiffTextFormat, DraggedRevisionText, HoveredRevisionText);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An event handler for mouse drag leave events. Intended to be used as a delegate for
|
|
* history tree rows. Only handles FSourceControlHistoryRowDragDropOp drag/drop operations.
|
|
* Clears any pending drop actions from the FSourceControlHistoryRowDragDropOp.
|
|
*
|
|
* @param DragDropEvent The drag/drop operation that triggered this handler.
|
|
*/
|
|
void OnRowDragLeave(FDragDropEvent const& DragDropEvent) const
|
|
{
|
|
TSharedPtr<FSourceControlHistoryRowDragDropOp> DragRowOp = DragDropEvent.GetOperationAs<FSourceControlHistoryRowDragDropOp>();
|
|
if (DragRowOp.IsValid())
|
|
{
|
|
DragRowOp->HoverText = FText::GetEmpty();
|
|
DragRowOp->PendingDropAction = FSourceControlHistoryRowDragDropOp::EDropAction::None;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* An event handler for mouse drop events. Intended to be used as a delegate for
|
|
* history tree rows. Only handles FSourceControlHistoryRowDragDropOp drag/drop operations.
|
|
* Executes the pending FSourceControlHistoryRowDragDropOp action (diff, etc.)
|
|
*
|
|
* @param DragDropEvent The drag/drop operation that triggered this handler.
|
|
* @param HoveredItem The history tree item that is conceptually being dropped on to.
|
|
* @return A reply detailing how this event was handled ("Unhandled" if the operation was not a FSourceControlHistoryRowDragDropOp).
|
|
*/
|
|
FReply OnRowDrop(FDragDropEvent const& DragDropEvent, TSharedPtr<FHistoryTreeItem> const HoveredItem) const
|
|
{
|
|
TSharedPtr<FSourceControlHistoryRowDragDropOp> DragRowOp = DragDropEvent.GetOperationAs<FSourceControlHistoryRowDragDropOp>();
|
|
if (DragRowOp.IsValid())
|
|
{
|
|
if (DragRowOp->PendingDropAction == FSourceControlHistoryRowDragDropOp::EDropAction::Diff)
|
|
{
|
|
check(DragRowOp->SelectedItems.Num() > 0);
|
|
DiffHistoryItems(DragRowOp->SelectedItems[0], HoveredItem);
|
|
|
|
return FReply::Handled();
|
|
}
|
|
}
|
|
return FReply::Unhandled();
|
|
}
|
|
|
|
/** Main list view of the panel, displays each file history item */
|
|
typedef STreeView< TSharedPtr<FHistoryTreeItem> > SHistoryFileListType;
|
|
|
|
/** ListBox for selecting which object to consolidate */
|
|
TSharedPtr< SHistoryFileListType > MainHistoryListView;
|
|
|
|
/** Items control for the "additional information" subpanel */
|
|
TSharedPtr<SBorder> AdditionalInfoItemsControl;
|
|
|
|
/** All file history items the panel should display */
|
|
TArray< TSharedPtr<FHistoryTreeItem> > HistoryCollection;
|
|
|
|
/** The last selected revision item; Displayed in the "additional information" subpanel */
|
|
TWeakPtr<FHistoryRevisionListViewItem> LastSelectedRevisionItem;
|
|
};
|
|
|
|
void FSourceControlWindows::DisplayRevisionHistory( const TArray<FString>& InPackageNames )
|
|
{
|
|
ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider();
|
|
|
|
// Query for the file history for the provided packages
|
|
TArray<FString> PackageFilenames = SourceControlHelpers::PackageFilenames(InPackageNames);
|
|
TSharedRef<FUpdateStatus, ESPMode::ThreadSafe> UpdateStatusOperation = ISourceControlOperation::Create<FUpdateStatus>();
|
|
UpdateStatusOperation->SetUpdateHistory(true);
|
|
if(SourceControlProvider.Execute(UpdateStatusOperation, PackageFilenames))
|
|
{
|
|
TArray< FSourceControlStateRef > SourceControlStates;
|
|
for(const FString& PackageFilename : PackageFilenames)
|
|
{
|
|
TArray<FString> RevisionName;
|
|
RevisionName.Add(PackageFilename);
|
|
|
|
while(RevisionName.Num() != 0)
|
|
{
|
|
int32 InitialNum = SourceControlStates.Num();
|
|
SourceControlProvider.GetState(RevisionName, SourceControlStates, EStateCacheUsage::Use);
|
|
int32 NewNum = SourceControlStates.Num();
|
|
ensure(NewNum >= InitialNum);
|
|
|
|
RevisionName.Empty();
|
|
// check to see if origin of this file is a branch, append the history from the branch point:
|
|
if(NewNum > InitialNum)
|
|
{
|
|
int32 HistorySize = SourceControlStates.Last()->GetHistorySize();
|
|
if( HistorySize > 0 )
|
|
{
|
|
TSharedPtr<class ISourceControlRevision, ESPMode::ThreadSafe> InitialHistory = SourceControlStates.Last()->GetHistoryItem(HistorySize - 1);
|
|
TSharedPtr<ISourceControlRevision, ESPMode::ThreadSafe> BranchSource = InitialHistory->GetBranchSource();
|
|
if( BranchSource.IsValid() )
|
|
{
|
|
RevisionName.Add(BranchSource->GetFilename());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
TSharedRef<SWindow> NewWindow = SNew(SWindow)
|
|
.Title( NSLOCTEXT("SourceControl.HistoryWindow", "Title", "File History") )
|
|
.SizingRule(ESizingRule::UserSized)
|
|
.AutoCenter(EAutoCenter::PreferredWorkArea)
|
|
.ClientSize(FVector2D(1000, 400));
|
|
|
|
TSharedRef<SSourceControlHistoryWidget> SourceControlWidget =
|
|
SNew(SSourceControlHistoryWidget)
|
|
.ParentWindow(NewWindow)
|
|
.SourceControlStates(SourceControlStates);
|
|
|
|
|
|
NewWindow->SetContent( SourceControlWidget );
|
|
|
|
TSharedPtr<SWindow> RootWindow = FGlobalTabmanager::Get()->GetRootWindow();
|
|
if(RootWindow.IsValid())
|
|
{
|
|
FSlateApplication::Get().AddWindowAsNativeChild(NewWindow, RootWindow.ToSharedRef());
|
|
}
|
|
else
|
|
{
|
|
FSlateApplication::Get().AddWindow(NewWindow);
|
|
}
|
|
}
|
|
}
|