void FLevelModel::MakeLevelCurrent() { if (LevelCollectionModel.IsReadOnly()) { return; } if (!IsLoaded()) { // Load level from disk FLevelModelList LevelsList; LevelsList.Add(this->AsShared()); LevelCollectionModel.LoadLevels(LevelsList); } ULevel* Level = GetLevelObject(); if (Level == NULL) { return; } // Locked levels can't be made current. if (!FLevelUtils::IsLevelLocked(Level)) { // Make current. if (LevelCollectionModel.GetWorld()->SetCurrentLevel(Level)) { FEditorDelegates::NewCurrentLevel.Broadcast(); // Deselect all selected builder brushes. bool bDeselectedSomething = false; for (FSelectionIterator It(Editor->GetSelectedActorIterator()); It; ++It) { AActor* Actor = static_cast<AActor*>(*It); checkSlow(Actor->IsA(AActor::StaticClass())); ABrush* Brush = Cast< ABrush >( Actor ); if (Brush && FActorEditorUtils::IsABuilderBrush(Brush)) { Editor->SelectActor(Actor, /*bInSelected=*/ false, /*bNotify=*/ false); bDeselectedSomething = true; } } // Send a selection change callback if necessary. if (bDeselectedSomething) { Editor->NoteSelectionChange(); } } // Force the current level to be visible. SetVisible(true); } else { FMessageDialog::Open(EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "Error_OperationDisallowedOnLockedLevelMakeLevelCurrent", "MakeLevelCurrent: The requested operation could not be completed because the level is locked.")); } Update(); }
FReply SWorldHierarchyItem::OnSave() { FLevelModelList LevelList; LevelList.Add(LevelModel); WorldModel->SaveLevels(LevelList); return FReply::Handled(); }
void FLevelCollectionModel::UnloadLevels(const FLevelModelList& InLevelList) { if (InLevelList.Num() == 0) { return; } // If matinee is opened, and if it belongs to the level being removed, close it if (GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_InterpEdit)) { TArray<ULevel*> LevelsToRemove = GetLevelObjectList(InLevelList); const FEdModeInterpEdit* InterpEditMode = (const FEdModeInterpEdit*)GLevelEditorModeTools().GetActiveMode(FBuiltinEditorModes::EM_InterpEdit); if (InterpEditMode && InterpEditMode->MatineeActor && LevelsToRemove.Contains(InterpEditMode->MatineeActor->GetLevel())) { GLevelEditorModeTools().ActivateDefaultMode(); } } else if(GLevelEditorModeTools().IsModeActive(FBuiltinEditorModes::EM_Landscape)) { GLevelEditorModeTools().ActivateDefaultMode(); } // Remove each level! // Take a copy of the list rather than using a reference to the selected levels list, as this will be modified in the loop below const FLevelModelList LevelListCopy = InLevelList; for (auto It = LevelListCopy.CreateConstIterator(); It; ++It) { TSharedPtr<FLevelModel> LevelModel = (*It); ULevel* Level = LevelModel->GetLevelObject(); if (Level != NULL && !LevelModel->IsPersistent()) { // Unselect all actors before removing the level // This avoids crashing in areas that rely on getting a selected actors level. The level will be invalid after its removed. for (auto ActorIt = Level->Actors.CreateIterator(); ActorIt; ++ActorIt) { Editor->SelectActor((*ActorIt), /*bInSelected=*/ false, /*bSelectEvenIfHidden=*/ false); } { FUnmodifiableObject ImmuneWorld(CurrentWorld.Get()); EditorLevelUtils::RemoveLevelFromWorld(Level); } } } Editor->ResetTransaction( LOCTEXT("RemoveLevelTransReset", "Removing Levels from World") ); // Collect garbage to clear out the destroyed level CollectGarbage( GARBAGE_COLLECTION_KEEPFLAGS ); PopulateLevelsList(); }
/** Updates all the items in the grid view */ void RefreshView() { RemoveAllNodes(); FLevelModelList AllLevels = WorldModel->GetAllLevels(); for (auto It = AllLevels.CreateConstIterator(); It; ++It) { AddItem(StaticCastSharedPtr<FWorldTileModel>(*It)); } }
FLevelModelList FLevelCollectionModel::GetLoadedLevels(const FLevelModelList& InList) { FLevelModelList ResultList; for (auto It = InList.CreateConstIterator(); It; ++It) { if ((*It)->IsLoaded()) { ResultList.Add(*It); } } return ResultList; }
void FLevelCollectionModel::InvertSelection_Executed() { FLevelModelList InvertedLevels; for (auto It = FilteredLevelsList.CreateIterator(); It; ++It) { if (!SelectedLevelsList.Contains(*It)) { InvertedLevels.Add(*It); } } SetSelectedLevels(InvertedLevels); }
void FLevelCollectionModel::SetSelectedLevelsFromWorld() { TArray<ULevel*>& SelectedLevelObjects = CurrentWorld->GetSelectedLevels(); FLevelModelList LevelsToSelect; for (ULevel* LevelObject : SelectedLevelObjects) { TSharedPtr<FLevelModel> LevelModel = FindLevelModel(LevelObject); if (LevelModel.IsValid()) { LevelsToSelect.Add(LevelModel); } } SetSelectedLevels(LevelsToSelect); }
FReply SWorldHierarchyItem::OnToggleVisibility() { FLevelModelList LevelList; LevelList.Add(LevelModel); if (LevelModel->IsVisible()) { WorldModel->HideLevels(LevelList); } else { WorldModel->ShowLevels(LevelList); } return FReply::Handled(); }
FReply SWorldHierarchyItem::OnToggleLock() { FLevelModelList LevelList; LevelList.Add(LevelModel); if (LevelModel->IsLocked()) { WorldModel->UnlockLevels(LevelList); } else { WorldModel->LockLevels(LevelList); } return FReply::Handled(); }
void FStreamingLevelCollectionModel::UnloadLevels(const FLevelModelList& InLevelList) { if (IsReadOnly()) { return; } // Persistent level cannot be unloaded if (InLevelList.Num() == 1 && InLevelList[0]->IsPersistent()) { return; } bool bHaveDirtyLevels = false; for (auto It = InLevelList.CreateConstIterator(); It; ++It) { if ((*It)->IsDirty() && !(*It)->IsLocked() && !(*It)->IsPersistent()) { // this level is dirty and can be removed from the world bHaveDirtyLevels = true; break; } } // Depending on the state of the level, create a warning message FText LevelWarning = LOCTEXT("RemoveLevel_Undo", "Removing levels cannot be undone. Proceed?"); if (bHaveDirtyLevels) { LevelWarning = LOCTEXT("RemoveLevel_Dirty", "Removing levels cannot be undone. Any changes to these levels will be lost. Proceed?"); } // Ask the user if they really wish to remove the level(s) FSuppressableWarningDialog::FSetupInfo Info( LevelWarning, LOCTEXT("RemoveLevel_Message", "Remove Level"), "RemoveLevelWarning" ); Info.ConfirmText = LOCTEXT( "RemoveLevel_Yes", "Yes"); Info.CancelText = LOCTEXT( "RemoveLevel_No", "No"); FSuppressableWarningDialog RemoveLevelWarning( Info ); if (RemoveLevelWarning.ShowModal() == FSuppressableWarningDialog::Cancel) { return; } // This will remove streaming levels from a persistent world, so we need to re-populate levels list FLevelCollectionModel::UnloadLevels(InLevelList); PopulateLevelsList(); }
void FWorldTileModel::OnDrop(const TSharedPtr<FLevelDragDropOp>& Op) { FLevelModelList LevelModelList; for (auto It = Op->LevelsToDrop.CreateConstIterator(); It; ++It) { ULevel* Level = (*It).Get(); TSharedPtr<FLevelModel> LevelModel = LevelCollectionModel.FindLevelModel(Level); if (LevelModel.IsValid()) { LevelModelList.Add(LevelModel); } } if (LevelModelList.Num()) { LevelCollectionModel.AssignParent(LevelModelList, this->AsShared()); } }
void FLevelCollectionModel::AssignParent(const FLevelModelList& InLevels, TSharedPtr<FLevelModel> InParent) { // Attach levels to the new parent for (auto It = InLevels.CreateConstIterator(); It; ++It) { (*It)->AttachTo(InParent); } OnLevelsHierarchyChanged(); }
void FStreamingLevelCollectionModel::SetStreamingLevelsClass_Executed(UClass* InClass) { // First prompt to save the selected levels, as changing the streaming method will unload/reload them SaveSelectedLevels_Executed(); // Stash off a copy of the original array, as changing the streaming method can destroy the selection FLevelModelList SelectedLevelsCopy = GetSelectedLevels(); // Apply the new streaming method to the selected levels for (auto It = SelectedLevelsCopy.CreateIterator(); It; ++It) { TSharedPtr<FStreamingLevelModel> TargetModel = StaticCastSharedPtr<FStreamingLevelModel>(*It); TargetModel->SetStreamingClass(InClass); } SetSelectedLevels(SelectedLevelsCopy); // Force a cached level list rebuild PopulateLevelsList(); }
void FWorldTileModel::OnParentPackageNamePropertyChanged() { if (GetLevelObject() && !TileDetails->bAlwaysLoaded) { TSharedPtr<FLevelModel> NewParent = LevelCollectionModel.FindLevelModel(TileDetails->ParentPackageName); // Assign to a root level if new parent is not found if (!NewParent.IsValid()) { NewParent = static_cast<FWorldTileCollectionModel&>(LevelCollectionModel).GetWorldRootModel(); } FLevelModelList LevelList; LevelList.Add(this->AsShared()); LevelCollectionModel.AssignParent(LevelList, NewParent); return; } // Restore original parent FWorldTileInfo Info = LevelCollectionModel.GetWorld()->WorldComposition->GetTileInfo(TileDetails->PackageName); TileDetails->ParentPackageName = FName(*Info.ParentTilePackageName); }
void FLevelCollectionModel::LockLevels(const FLevelModelList& InLevelList) { if (IsReadOnly()) { return; } for (auto It = InLevelList.CreateConstIterator(); It; ++It) { (*It)->SetLocked(true); } }
void FWorldTileModel::OnPositionPropertyChanged() { FWorldTileInfo Info = LevelCollectionModel.GetWorld()->WorldComposition->GetTileInfo(TileDetails->PackageName); if (GetLevelObject()) { // Get the delta FIntPoint Delta = TileDetails->Position - Info.Position; // Snap the delta FLevelModelList LevelsList; LevelsList.Add(this->AsShared()); FVector2D SnappedDelta = LevelCollectionModel.SnapTranslationDelta(LevelsList, FVector2D(Delta), 0.f); // Set new level position SetLevelPosition(Info.AbsolutePosition + FIntPoint(SnappedDelta.X, SnappedDelta.Y)); return; } // Restore original value TileDetails->Position = Info.Position; }
void FLevelCollectionModel::UpdateTranslationDelta(const FLevelModelList& InLevelList, FVector2D InTranslationDelta, bool bBoundsSnapping, float InSnappingValue) { FLevelModelList EditableLevels; // Only editable levels could be moved for (auto It = InLevelList.CreateConstIterator(); It; ++It) { if ((*It)->IsEditable()) { EditableLevels.Add(*It); } } // Snap translation delta if (InTranslationDelta != FVector2D::ZeroVector) { InTranslationDelta = SnapTranslationDelta(EditableLevels, InTranslationDelta, bBoundsSnapping, InSnappingValue); } for (auto It = EditableLevels.CreateIterator(); It; ++It) { (*It)->SetLevelTranslationDelta(InTranslationDelta); } }
void FLevelCollectionModel::SCCHistory(const FLevelModelList& InList) { // This is odd, why SCC needs package names, instead of filenames? TArray<FString> PackageNames; for (auto It = InList.CreateConstIterator(); It; ++It) { if ((*It)->HasValidPackage()) { PackageNames.Add((*It)->GetLongPackageName().ToString()); } } FSourceControlWindows::DisplayRevisionHistory(PackageNames); }
void FLevelCollectionModel::HideLevels(const FLevelModelList& InLevelList) { if (IsReadOnly()) { return; } for (auto It = InLevelList.CreateConstIterator(); It; ++It) { (*It)->SetVisible(false); } RequestUpdateAllLevels(); }
TArray<FString> FLevelCollectionModel::GetFilenamesList(const FLevelModelList& InList) { TArray<FString> ResultList; for (auto It = InList.CreateConstIterator(); It; ++It) { if ((*It)->HasValidPackage()) { ResultList.Add((*It)->GetPackageFileName()); } } return ResultList; }
FBox FLevelCollectionModel::GetLevelsBoundingBox(const FLevelModelList& InList, bool bIncludeChildren) { FBox TotalBounds(0); for (auto It = InList.CreateConstIterator(); It; ++It) { if (bIncludeChildren) { TotalBounds+= GetVisibleLevelsBoundingBox((*It)->GetChildren(), bIncludeChildren); } TotalBounds+= (*It)->GetLevelBounds(); } return TotalBounds; }
TArray<ULevel*> FLevelCollectionModel::GetLevelObjectList(const FLevelModelList& InList) { TArray<ULevel*> ResultList; for (auto It = InList.CreateConstIterator(); It; ++It) { ULevel* Level = (*It)->GetLevelObject(); if (Level) { ResultList.Add(Level); } } return ResultList; }
FLevelModelList FLevelCollectionModel::GetLevelsHierarchy(const FLevelModelList& InList) { struct FHierarchyCollector : public FLevelModelVisitor { virtual void Visit(FLevelModel& Item) override { ResultList.AddUnique(Item.AsShared()); } FLevelModelList ResultList; }; FHierarchyCollector HierarchyCollector; for (auto It = InList.CreateConstIterator(); It; ++It) { (*It)->Accept(HierarchyCollector); } return HierarchyCollector.ResultList; }
void FLevelCollectionModel::LoadLevels(const FLevelModelList& InLevelList) { if (IsReadOnly()) { return; } GWarn->BeginSlowTask(LOCTEXT("LoadWorldTiles", "Loading levels"), true); OnPreLoadLevels(InLevelList); int32 LevelIdx = 0; for (TSharedPtr<FLevelModel> LevelModel : InLevelList) { GWarn->StatusUpdate(LevelIdx++, InLevelList.Num(), FText::Format(LOCTEXT("LoadingWorldTiles", "Loading: {0}..." ), FText::FromString(LevelModel->GetLongPackageName().ToString())) ); LevelModel->LoadLevel(); } GWarn->EndSlowTask(); }
void FLevelCollectionModel::SaveLevels(const FLevelModelList& InLevelList) { if (IsReadOnly()) { return; } FLevelModelList LevelModelsToSave; TArray<ULevel*> LevelsToSave; for (auto It = InLevelList.CreateConstIterator(); It; ++It) { if ((*It)->GetLevelObject()) { if (!(*It)->IsVisible()) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveInvisibleLevels", "Save aborted. Levels must be made visible before they can be saved.") ); return; } else if ((*It)->IsLocked()) { FMessageDialog::Open( EAppMsgType::Ok, NSLOCTEXT("UnrealEd", "UnableToSaveLockedLevels", "Save aborted. Level must be unlocked before it can be saved.") ); return; } LevelModelsToSave.Add(*It); LevelsToSave.Add((*It)->GetLevelObject()); } } TArray< UPackage* > PackagesNotNeedingCheckout; // Prompt the user to check out the levels from source control before saving if (FEditorFileUtils::PromptToCheckoutLevels(false, LevelsToSave, &PackagesNotNeedingCheckout)) { for (auto It = LevelsToSave.CreateIterator(); It; ++It) { FEditorFileUtils::SaveLevel(*It); } } else if (PackagesNotNeedingCheckout.Num() > 0) { // The user canceled the checkout dialog but some packages didn't need to be checked out in order to save // For each selected level if the package its in didn't need to be saved, save the level! for (int32 LevelIdx = 0; LevelIdx < LevelsToSave.Num(); ++LevelIdx) { ULevel* Level = LevelsToSave[LevelIdx]; if (PackagesNotNeedingCheckout.Contains(Level->GetOutermost())) { FEditorFileUtils::SaveLevel(Level); } else { //remove it from the list, so that only successfully saved levels are highlighted when saving is complete LevelModelsToSave.RemoveAt(LevelIdx); LevelsToSave.RemoveAt(LevelIdx); } } } // Select tiles that were saved successfully SetSelectedLevels(LevelModelsToSave); }
void FLevelCollectionModel::SCCDiffAgainstDepot(const FLevelModelList& InList, UEditorEngine* InEditor) { // Load the asset registry module FAssetToolsModule& AssetToolsModule = FModuleManager::GetModuleChecked<FAssetToolsModule>("AssetTools"); ISourceControlProvider& SourceControlProvider = ISourceControlModule::Get().GetProvider(); // Iterate over each selected asset for (auto It = InList.CreateConstIterator(); It; ++It) { ULevel* Level = (*It)->GetLevelObject(); if (Level == NULL) { return; } UPackage* OriginalPackage = Level->GetOutermost(); FString PackageName = OriginalPackage->GetName(); // Make sure our history is up to date auto UpdateStatusOperation = ISourceControlOperation::Create<FUpdateStatus>(); UpdateStatusOperation->SetUpdateHistory(true); SourceControlProvider.Execute(UpdateStatusOperation, OriginalPackage); // Get the SCC state FSourceControlStatePtr SourceControlState = SourceControlProvider.GetState( OriginalPackage, EStateCacheUsage::Use ); // If the level is in SCC. if (SourceControlState.IsValid() && SourceControlState->IsSourceControlled()) { // Get the file name of package FString RelativeFileName; if(FPackageName::DoesPackageExist(PackageName, NULL, &RelativeFileName)) { if (SourceControlState->GetHistorySize() > 0) { auto Revision = SourceControlState->GetHistoryItem(0); check(Revision.IsValid()); // Get the head revision of this package from source control FString AbsoluteFileName = FPaths::ConvertRelativePathToFull(RelativeFileName); FString TempFileName; if (Revision->Get(TempFileName)) { // Forcibly disable compile on load in case we are loading old blueprints that might try to update/compile TGuardValue<bool> DisableCompileOnLoad(GForceDisableBlueprintCompileOnLoad, true); // Try and load that package FText NotMapReason; UPackage* OldPackage = LoadPackage(NULL, *TempFileName, LOAD_None); if(OldPackage != NULL && InEditor->PackageIsAMapFile(*TempFileName, NotMapReason)) { /* Set the revision information*/ UPackage* Package = OriginalPackage; FRevisionInfo OldRevision; OldRevision.Changelist = Revision->GetCheckInIdentifier(); OldRevision.Date = Revision->GetDate(); OldRevision.Revision = Revision->GetRevision(); FRevisionInfo NewRevision; NewRevision.Revision = TEXT(""); // Dump assets to temp text files FString OldTextFilename = AssetToolsModule.Get().DumpAssetToTempFile(OldPackage); FString NewTextFilename = AssetToolsModule.Get().DumpAssetToTempFile(OriginalPackage); FString DiffCommand = GetDefault<UEditorLoadingSavingSettings>()->TextDiffToolPath.FilePath; AssetToolsModule.Get().CreateDiffProcess(DiffCommand, OldTextFilename, NewTextFilename); AssetToolsModule.Get().DiffAssets(OldPackage, OriginalPackage, OldRevision, NewRevision); } } } } } } }