TSharedRef<SDockTab> FMerge::GenerateMergeWidget(const UBlueprint& Object, TSharedRef<FBlueprintEditor> Editor) { auto ActiveTabPtr = ActiveTab.Pin(); if( ActiveTabPtr.IsValid() ) { // just bring the tab to the foreground: auto CurrentTab = FGlobalTabmanager::Get()->InvokeTab(MergeToolTabId); check( CurrentTab == ActiveTabPtr ); return ActiveTabPtr.ToSharedRef(); } // merge the local asset with the depot, SCC provides us with the last common revision as // a basis for the merge: TSharedPtr<SWidget> Contents; if (!PendingMerge(Object)) { // this should load up the merge-tool, with an asset picker, where they // can pick the asset/revisions to merge against Contents = GenerateMergeTabContents(Editor, nullptr, FRevisionInfo::InvalidRevision(), nullptr, FRevisionInfo::InvalidRevision(), &Object, FOnMergeResolved()); } else { // @todo DO: this will probably need to be async.. pulling down some old versions of assets: const FString& PackageName = Object.GetOutermost()->GetName(); const FString& AssetName = Object.GetName(); FSourceControlStatePtr SourceControlState = FMergeToolUtils::GetSourceControlState(PackageName); if (!SourceControlState.IsValid()) { DisplayErrorMessage( FText::Format( LOCTEXT("MergeFailedNoSourceControl", "Aborted Load of {0} from {1} because the source control state was invalidated") , FText::FromString(AssetName) , FText::FromString(PackageName) ) ); Contents = SNew(SHorizontalBox); } else { ISourceControlState const& SourceControlStateRef = *SourceControlState; FRevisionInfo CurrentRevInfo = FRevisionInfo::InvalidRevision(); const UBlueprint* RemoteBlueprint = Cast< UBlueprint >(LoadHeadRev(PackageName, AssetName, SourceControlStateRef, CurrentRevInfo)); FRevisionInfo BaseRevInfo = FRevisionInfo::InvalidRevision(); const UBlueprint* BaseBlueprint = Cast< UBlueprint >(LoadBaseRev(PackageName, AssetName, SourceControlStateRef, BaseRevInfo)); Contents = GenerateMergeTabContents(Editor, BaseBlueprint, BaseRevInfo, RemoteBlueprint, CurrentRevInfo, &Object, FOnMergeResolved()); } } TSharedRef<SDockTab> Tab = FGlobalTabmanager::Get()->InvokeTab(MergeToolTabId); Tab->SetContent(Contents.ToSharedRef()); ActiveTab = Tab; return Tab; }
FText UK2Node_DynamicCast::GetNodeTitle(ENodeTitleType::Type TitleType) const { if (TargetType == nullptr) { return NSLOCTEXT("K2Node_DynamicCast", "BadCastNode", "Bad cast node"); } else if (CachedNodeTitle.IsOutOfDate()) { // If casting to BP class, use BP name not class name (ie. remove the _C) FString TargetName; UBlueprint* CastToBP = UBlueprint::GetBlueprintFromClass(TargetType); if (CastToBP != NULL) { TargetName = CastToBP->GetName(); } else { TargetName = TargetType->GetName(); } FFormatNamedArguments Args; Args.Add(TEXT("TargetName"), FText::FromString(TargetName)); // FText::Format() is slow, so we cache this to save on performance CachedNodeTitle = FText::Format(NSLOCTEXT("K2Node_DynamicCast", "CastTo", "Cast To {TargetName}"), Args); } return CachedNodeTitle; }
void FAssetTypeActions_Blueprint::PerformAssetDiff(UObject* OldAsset, UObject* NewAsset, const FRevisionInfo& OldRevision, const FRevisionInfo& NewRevision) const { UBlueprint* OldBlueprint = Cast<UBlueprint>(OldAsset); check(OldBlueprint != NULL); check(OldBlueprint->SkeletonGeneratedClass != NULL); UBlueprint* NewBlueprint = Cast<UBlueprint>(NewAsset); check(NewBlueprint != NULL); check(NewBlueprint->SkeletonGeneratedClass != NULL); // sometimes we're comparing different revisions of one single asset (other // times we're comparing two completely separate assets altogether) bool bIsSingleAsset = (NewBlueprint->GetName() == OldBlueprint->GetName()); FText WindowTitle = LOCTEXT("NamelessBlueprintDiff", "Blueprint Diff"); // if we're diff'ing one asset against itself if (bIsSingleAsset) { // identify the assumed single asset in the window's title WindowTitle = FText::Format(LOCTEXT("Blueprint Diff", "{0} - Blueprint Diff"), FText::FromString(NewBlueprint->GetName())); } const TSharedPtr<SWindow> Window = SNew(SWindow) .Title(WindowTitle) .ClientSize(FVector2D(1000,800)); Window->SetContent(SNew(SBlueprintDiff) .BlueprintOld(OldBlueprint) .BlueprintNew(NewBlueprint) .OldRevision(OldRevision) .NewRevision(NewRevision) .ShowAssetNames(!bIsSingleAsset) .OpenInDefaults(const_cast<FAssetTypeActions_Blueprint*>(this), &FAssetTypeActions_Blueprint::OpenInDefaults) ); // Make this window a child of the modal window if we've been spawned while one is active. TSharedPtr<SWindow> ActiveModal = FSlateApplication::Get().GetActiveModalWindow(); if ( ActiveModal.IsValid() ) { FSlateApplication::Get().AddWindowAsNativeChild( Window.ToSharedRef(), ActiveModal.ToSharedRef() ); } else { FSlateApplication::Get().AddWindow( Window.ToSharedRef() ); } }
TSharedRef<SWidget> FEditorClassUtils::GetSourceLinkFormatted(const UClass* Class, const TWeakObjectPtr<UObject> ObjectWeakPtr, const FText& BlueprintFormat, const FText& CodeFormat) { TSharedRef<SWidget> SourceHyperlink = SNew( SSpacer ); UBlueprint* Blueprint = (Class ? Cast<UBlueprint>(Class->ClassGeneratedBy) : nullptr); if (Blueprint) { struct Local { static void OnEditBlueprintClicked( TWeakObjectPtr<UBlueprint> InBlueprint, TWeakObjectPtr<UObject> InAsset ) { if (UBlueprint* BlueprintToEdit = InBlueprint.Get()) { // Set the object being debugged if given an actor reference (if we don't do this before we edit the object the editor wont know we are debugging something) if (UObject* Asset = InAsset.Get()) { check(Asset->GetClass()->ClassGeneratedBy == BlueprintToEdit); BlueprintToEdit->SetObjectBeingDebugged(Asset); } // Open the blueprint GEditor->EditObject( BlueprintToEdit ); } } }; TWeakObjectPtr<UBlueprint> BlueprintPtr = Blueprint; SourceHyperlink = SNew(SHyperlink) .Style(FEditorStyle::Get(), "Common.GotoBlueprintHyperlink") .OnNavigate_Static(&Local::OnEditBlueprintClicked, BlueprintPtr, ObjectWeakPtr) .Text(FText::Format(BlueprintFormat, FText::FromString(Blueprint->GetName()))) .ToolTipText(NSLOCTEXT("SourceHyperlink", "EditBlueprint_ToolTip", "Click to edit the blueprint")); } else if( FSourceCodeNavigation::IsCompilerAvailable() ) { FString ClassHeaderPath; if( FSourceCodeNavigation::FindClassHeaderPath( Class, ClassHeaderPath ) && IFileManager::Get().FileSize( *ClassHeaderPath ) != INDEX_NONE ) { struct Local { static void OnEditCodeClicked( FString InClassHeaderPath ) { FString AbsoluteHeaderPath = IFileManager::Get().ConvertToAbsolutePathForExternalAppForRead(*InClassHeaderPath); FSourceCodeNavigation::OpenSourceFile( AbsoluteHeaderPath ); } }; SourceHyperlink = SNew(SHyperlink) .Style(FEditorStyle::Get(), "Common.GotoNativeCodeHyperlink") .OnNavigate_Static(&Local::OnEditCodeClicked, ClassHeaderPath) .Text(FText::Format(CodeFormat, FText::FromString(FPaths::GetCleanFilename( *ClassHeaderPath ) ) ) ) .ToolTipText(FText::Format(NSLOCTEXT("SourceHyperlink", "GoToCode_ToolTip", "Click to open this source file in {0}"), FSourceCodeNavigation::GetSuggestedSourceCodeIDE())); } } return SourceHyperlink; }
//------------------------------------------------------------------------------ FText SBlueprintLibraryPalette::GetFilterClassName() const { FText FilterDisplayString = LOCTEXT("All", "All"); if (FilterClass != NULL) { UBlueprint* Blueprint = UBlueprint::GetBlueprintFromClass(FilterClass.Get()); FilterDisplayString = FText::FromString((Blueprint != NULL) ? Blueprint->GetName() : FilterClass->GetName()); } return FilterDisplayString; }
/** Util to give better names for BP generated classes */ static FString GetClassDisplayName(const UObject* Object) { const UClass* Class = Cast<UClass>(Object); if (Class != NULL) { UBlueprint* BP = UBlueprint::GetBlueprintFromClass(Class); if(BP != NULL) { return BP->GetName(); } } return (Object) ? Object->GetName() : "None"; }
void UK2Node_Variable::ValidateNodeDuringCompilation(class FCompilerResultsLog& MessageLog) const { Super::ValidateNodeDuringCompilation(MessageLog); UProperty* VariableProperty = GetPropertyForVariable(); // Local variables do not exist until much later in the compilation than this function can provide if (VariableProperty == NULL && !VariableReference.IsLocalScope()) { if (!VariableReference.IsDeprecated()) { FString OwnerName; UBlueprint* Blueprint = GetBlueprint(); if (Blueprint != nullptr) { OwnerName = Blueprint->GetName(); if (UClass* VarOwnerClass = VariableReference.GetMemberParentClass(Blueprint->GeneratedClass)) { OwnerName = VarOwnerClass->GetName(); } } FString const VarName = VariableReference.GetMemberName().ToString(); FText const WarningFormat = LOCTEXT("VariableNotFound", "Could not find a variable named \"%s\" in '%s'.\nMake sure '%s' has been compiled for @@"); MessageLog.Warning(*FString::Printf(*WarningFormat.ToString(), *VarName, *OwnerName, *OwnerName), this); } else { MessageLog.Warning(*FString::Printf(*LOCTEXT("VariableDeprecated", "Variable '%s' for @@ was deprecated. Please update it.").ToString(), *VariableReference.GetMemberName().ToString()), this); } } if (VariableProperty && (VariableProperty->ArrayDim > 1)) { MessageLog.Warning(*LOCTEXT("StaticArray_Warning", "@@ - the native property is a static array, which is not supported by blueprints").ToString(), this); } }
void FAssetTypeActions_BlueprintGeneratedClass::ExecuteEditDefaults(TArray<TWeakObjectPtr<UBlueprintGeneratedClass>> Objects) { TArray< UBlueprint* > Blueprints; FMessageLog EditorErrors("EditorErrors"); EditorErrors.NewPage(LOCTEXT("ExecuteEditDefaultsNewLogPage", "Loading Blueprints")); for (auto ObjIt = Objects.CreateConstIterator(); ObjIt; ++ObjIt) { auto GeneratedClass = (*ObjIt).Get(); UBlueprint* Object = GeneratedClass ? Cast<UBlueprint>(GeneratedClass->ClassGeneratedBy) : NULL; if ( Object ) { // If the blueprint is valid, allow it to be added to the list, otherwise log the error. if (Object && Object->SkeletonGeneratedClass && Object->GeneratedClass ) { Blueprints.Add(Object); } else { FFormatNamedArguments Arguments; Arguments.Add(TEXT("ObjectName"), FText::FromString(Object->GetName())); EditorErrors.Error(FText::Format(LOCTEXT("LoadBlueprint_FailedLog", "{ObjectName} could not be loaded because it derives from an invalid class. Check to make sure the parent class for this blueprint hasn't been removed!"), Arguments ) ); } } } if ( Blueprints.Num() > 0 ) { FBlueprintEditorModule& BlueprintEditorModule = FModuleManager::LoadModuleChecked<FBlueprintEditorModule>( "Kismet" ); TSharedRef< IBlueprintEditor > NewBlueprintEditor = BlueprintEditorModule.CreateBlueprintEditor( EToolkitMode::Standalone, TSharedPtr<IToolkitHost>(), Blueprints ); } // Report errors EditorErrors.Notify(LOCTEXT("OpenDefaults_Failed", "Opening Blueprint Defaults Failed!")); }
/** * Fills the Blueprint menu with extra options */ void FillBlueprintOptions(FMenuBuilder& MenuBuilder, TArray<AActor*> SelectedActors) { // Gather Blueprint classes for this actor TArray< FMenuBlueprintClass > BlueprintClasses; GatherBlueprintsForActors( SelectedActors, BlueprintClasses ); MenuBuilder.BeginSection("ActorBlueprint", LOCTEXT("BlueprintsHeading", "Blueprints") ); // Adds the "Create Blueprint..." menu option if valid. { int NumBlueprintableActors = 0; bool IsBlueprintBased = BlueprintClasses.Num() > 1; if(!BlueprintClasses.Num()) { for(auto It(SelectedActors.CreateIterator());It;++It) { AActor* Actor = *It; if( FKismetEditorUtilities::CanCreateBlueprintOfClass(Actor->GetClass())) { NumBlueprintableActors++; } } } const bool bCanHarvestComponentsForBlueprint = (!IsBlueprintBased && (NumBlueprintableActors > 0)); if(bCanHarvestComponentsForBlueprint) { AActor* ActorOverride = nullptr; FUIAction CreateBlueprintAction( FExecuteAction::CreateStatic( &FCreateBlueprintFromActorDialog::OpenDialog, true, ActorOverride ) ); MenuBuilder.AddMenuEntry(LOCTEXT("CreateBlueprint", "Create Blueprint..."), LOCTEXT("CreateBlueprint_Tooltip", "Harvest Components from Selected Actors and create Blueprint"), FSlateIcon(FEditorStyle::GetStyleSetName(), "Kismet.HarvestBlueprintFromActors"), CreateBlueprintAction); } } // Check to see if we have any classes with functions to display if( BlueprintClasses.Num() > 0 ) { { UBlueprint* FirstBlueprint = Cast<UBlueprint>(BlueprintClasses[0].Blueprint.Get()); // Determine if the selected objects that have blueprints are all of the same class, and if they are all up to date bool bAllAreSameType = true; bool bAreAnyNotUpToDate = false; for (int32 ClassIndex = 0; ClassIndex < BlueprintClasses.Num(); ++ClassIndex) { UBlueprint* CurrentBlueprint = Cast<UBlueprint>(BlueprintClasses[ClassIndex].Blueprint.Get()); bAllAreSameType = bAllAreSameType && (CurrentBlueprint == FirstBlueprint); if (CurrentBlueprint != NULL) { bAreAnyNotUpToDate |= !CurrentBlueprint->IsUpToDate(); } } // For a single selected class, we show a top level item (saves 2 clicks); otherwise we show the full hierarchy if (bAllAreSameType && (FirstBlueprint != NULL)) { // Shortcut to edit the blueprint directly, saves two clicks FUIAction UIAction; UIAction.ExecuteAction.BindStatic( &EditKismetCodeFor, /*Blueprint=*/ TWeakObjectPtr<UBlueprint>(FirstBlueprint) ); const FText Label = LOCTEXT("EditBlueprint", "Edit Blueprint"); const FText Description = FText::Format( LOCTEXT("EditBlueprint_ToolTip", "Opens {0} in the Blueprint editor"), FText::FromString( FirstBlueprint->GetName() ) ); MenuBuilder.AddMenuEntry( Label, Description, FSlateIcon(), UIAction ); } else { // More than one type of blueprint is selected, so add a sub-menu for "Edit Kismet Code" MenuBuilder.AddSubMenu( LOCTEXT("EditBlueprintSubMenu", "Edit Blueprint"), LOCTEXT("EditBlueprintSubMenu_ToolTip", "Shows Blueprints that can be opened for editing"), FNewMenuDelegate::CreateStatic( &FillEditCodeMenu, BlueprintClasses ) ); } // For any that aren't up to date, we offer a compile blueprints button if (bAreAnyNotUpToDate) { // Shortcut to edit the blueprint directly, saves two clicks FUIAction UIAction; UIAction.ExecuteAction.BindStatic(&RecompileOutOfDateKismetForSelection); const FText Label = LOCTEXT("CompileOutOfDateBPs", "Compile Out-of-Date Blueprints"); const FText Description = LOCTEXT("CompileOutOfDateBPs_ToolTip", "Compiles out-of-date blueprints for selected actors"); MenuBuilder.AddMenuEntry( Label, Description, FSlateIcon(), UIAction ); } } } MenuBuilder.EndSection(); }
void FAssetTypeActions_BlueprintGeneratedClass::PerformAssetDiff(UObject* OldAsset, UObject* NewAsset, const FRevisionInfo& OldRevision, const FRevisionInfo& NewRevision) const { UBlueprintGeneratedClass* OldClass = CastChecked<UBlueprintGeneratedClass>(OldAsset); UBlueprint* OldBlueprint = CastChecked<UBlueprint>(OldClass->ClassGeneratedBy); check(OldBlueprint->SkeletonGeneratedClass != NULL); UBlueprintGeneratedClass* NewClass = CastChecked<UBlueprintGeneratedClass>(NewAsset); UBlueprint* NewBlueprint = CastChecked<UBlueprint>(NewClass->ClassGeneratedBy); check(NewBlueprint->SkeletonGeneratedClass != NULL); const TSharedPtr<SWindow> Window = SNew(SWindow) .Title( FText::Format( LOCTEXT("Blueprint Diff", "{0} - Blueprint Diff"), FText::FromString( NewBlueprint->GetName() ) ) ) .ClientSize(FVector2D(1000,800)); Window->SetContent(SNew(SBlueprintDiff) .BlueprintOld(OldBlueprint) .BlueprintNew(NewBlueprint) .OldRevision(OldRevision) .NewRevision(NewRevision) .OpenInDefaults(const_cast<FAssetTypeActions_BlueprintGeneratedClass*>(this), &FAssetTypeActions_BlueprintGeneratedClass::OpenInDefaults) ); FSlateApplication::Get().AddWindow( Window.ToSharedRef(), true ); }
//------------------------------------------------------------------------------ UEdGraphNode* FBlueprintNodeTemplateCache::GetNodeTemplate(UBlueprintNodeSpawner const* NodeSpawner, UEdGraph* TargetGraph) { using namespace BlueprintNodeTemplateCacheImpl; bool bIsOverMemCap = false; auto LogCacheFullMsg = [&bIsOverMemCap]() { if (!bIsOverMemCap) { static int32 LoggedCapSize = -1; int32 const CurrentCacheSize = GetCacheCapSize(); // log only once for each cap size change if (LoggedCapSize != CurrentCacheSize) { UE_LOG(LogBlueprintNodeCache, Display, TEXT("The blueprint template-node cache is full. As a result, you may experience interactions which are slower than normal. To avoid this, increase the cache's cap in the blueprint editor prefences.")); LoggedCapSize = CurrentCacheSize; } bIsOverMemCap = true; } }; UEdGraphNode* TemplateNode = nullptr; if (UEdGraphNode** FoundNode = NodeTemplateCache.Find(NodeSpawner)) { TemplateNode = *FoundNode; } else if (NodeSpawner->NodeClass != nullptr) { UEdGraphNode* NodeCDO = NodeSpawner->NodeClass->GetDefaultObject<UEdGraphNode>(); check(NodeCDO != nullptr); UBlueprint* TargetBlueprint = nullptr; TSubclassOf<UBlueprint> BlueprintClass; bool const bHasTargetGraph = (TargetGraph != nullptr); if (bHasTargetGraph) { // by the time we're asking for a prototype for this spawner, we should // be sure that it is compatible with the TargetGraph //check(IsCompatible(NodeCDO, TargetGraph)); TargetBlueprint = FBlueprintEditorUtils::FindBlueprintForGraph(TargetGraph); check(TargetBlueprint != nullptr); BlueprintClass = TargetBlueprint->GetClass(); // check used to help identify user interactable graphs (as opposed to // intermediate/transient graphs). auto IsCompatibleUserGraph = [](UEdGraph* Graph)->bool { return !Graph->HasAnyFlags(RF_Transient); }; TargetGraph = FindCompatibleGraph(TargetBlueprint, NodeCDO, IsCompatibleUserGraph); check(TargetGraph != nullptr); } UBlueprint* CompatibleBlueprint = nullptr; UEdGraph* CompatibleOuter = nullptr; // find a compatible outer (don't want to have to create a new one if we don't have to) for (UBlueprint* Blueprint : TemplateOuters) { CompatibleOuter = FindCompatibleGraph(Blueprint, NodeCDO); if (CompatibleOuter != nullptr) { MarkGraphForTemplateUse(CompatibleOuter); } if (CompatibleOuter != nullptr) { CompatibleBlueprint = Blueprint; break; } else if ((BlueprintClass != nullptr) && Blueprint->GetClass()->IsChildOf(BlueprintClass)) { CompatibleBlueprint = Blueprint; } } // reset ActiveMemFootprint, so calls to CacheBlueprintOuter()/CacheTemplateNode() // use the most up-to-date value (users could have since modified the // nodes, so they could have grown in size... like with AllocateDefaultPins) // // @TODO: GetEstimateCacheSize() is (most likely) inaccurate, seeing as // external systems mutate template-nodes (such as calling // AllocateDefaultPins), and this returns a size estimate from // when the node was first spawned (it is too slow to recalculate // the size of the object hierarchy here) ActiveMemFootprint = GetEstimateCacheSize(); int32 const CacheCapSize = GetCacheCapSize(); if (ActiveMemFootprint > CacheCapSize) { LogCacheFullMsg(); // @TODO: evict nodes until we're back under the cap (in case the cap // was changed at runtime, or external user modified node sizes) } // if a TargetGraph was supplied, and we couldn't find a suitable outer // for this template-node, then attempt to emulate that graph if (bHasTargetGraph) { if (CompatibleBlueprint == nullptr) { // if the cache is near full, attempt to predict if this // impending cache will fail (if so, we don't want to waste the // cycles on allocating a temp blueprint) if (!bIsOverMemCap && ((AverageBlueprintSize == 0) || (ActiveMemFootprint + AverageBlueprintSize <= CacheCapSize))) { TSubclassOf<UBlueprintGeneratedClass> GeneratedClassType = UBlueprintGeneratedClass::StaticClass(); if (TargetBlueprint->GeneratedClass != nullptr) { GeneratedClassType = TargetBlueprint->GeneratedClass->GetClass(); } CompatibleBlueprint = MakeCompatibleBlueprint(BlueprintClass, TargetBlueprint->ParentClass, GeneratedClassType); if (!CacheBlueprintOuter(CompatibleBlueprint)) { LogCacheFullMsg(); } // this graph may come default with a compatible graph CompatibleOuter = FindCompatibleGraph(CompatibleBlueprint, NodeCDO); if (CompatibleOuter != nullptr) { MarkGraphForTemplateUse(CompatibleOuter); } } else { CompatibleBlueprint = TargetBlueprint; CompatibleOuter = FindCompatibleGraph(TargetBlueprint, NodeCDO, &BlueprintNodeTemplateCacheImpl::IsTemplateOuter); LogCacheFullMsg(); } } if (CompatibleOuter == nullptr) { CompatibleOuter = AddGraph(CompatibleBlueprint, TargetGraph->Schema); ensureMsgf( CompatibleOuter->Schema != nullptr, TEXT("Invalid schema for template graph (from '%s :: %s')."), *TargetBlueprint->GetName(), *TargetGraph->GetName() ); if (CompatibleBlueprint != TargetBlueprint) { int32 const ApproxGraphSize = ApproximateMemFootprint(CompatibleOuter); ActiveMemFootprint += ApproxGraphSize; ApproximateObjectMem += ApproxGraphSize; } } } if (CompatibleOuter != nullptr) { TemplateNode = NodeSpawner->Invoke(CompatibleOuter, IBlueprintNodeBinder::FBindingSet(), FVector2D::ZeroVector); if (!bIsOverMemCap && !CacheTemplateNode(NodeSpawner, TemplateNode)) { LogCacheFullMsg(); } } } return TemplateNode; }