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();
}
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::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();	
}