summaryrefslogtreecommitdiff
path: root/sw/source/uibase/shells/textsh1.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/uibase/shells/textsh1.cxx')
-rw-r--r--sw/source/uibase/shells/textsh1.cxx501
1 files changed, 498 insertions, 3 deletions
diff --git a/sw/source/uibase/shells/textsh1.cxx b/sw/source/uibase/shells/textsh1.cxx
index 8d7c07e104ca..6f51980d6d0d 100644
--- a/sw/source/uibase/shells/textsh1.cxx
+++ b/sw/source/uibase/shells/textsh1.cxx
@@ -102,7 +102,16 @@
#include <xmloff/odffields.hxx>
#include <bookmark.hxx>
#include <linguistic/misc.hxx>
+#include <comphelper/sequenceashashmap.hxx>
+#include <comphelper/scopeguard.hxx>
#include <authfld.hxx>
+#include <translatelangselect.hxx>
+#include <svtools/deeplcfg.hxx>
+#include <translatehelper.hxx>
+#include <IDocumentContentOperations.hxx>
+#include <IDocumentUndoRedo.hxx>
+#include <fmtcntnt.hxx>
+#include <fmtrfmrk.hxx>
using namespace ::com::sun::star;
using namespace com::sun::star::beans;
@@ -375,6 +384,373 @@ OUString GetLocalURL(const SwWrtShell& rSh)
return rLocalURL;
}
+void UpdateSections(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ OUString aSectionNamePrefix;
+ const SfxStringItem* pSectionNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pSectionNamePrefix)
+ {
+ aSectionNamePrefix = pSectionNamePrefix->GetValue();
+ }
+
+ uno::Sequence<beans::PropertyValues> aSections;
+ const SfxUnoAnyItem* pSections = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2);
+ if (pSections)
+ {
+ pSections->GetValue() >>= aSections;
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSSECTION, nullptr);
+ rWrtSh.StartAction();
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ sal_Int32 nSectionIndex = 0;
+ const SwSectionFormats& rFormats = pDoc->GetSections();
+ IDocumentContentOperations& rIDCO = pDoc->getIDocumentContentOperations();
+ for (size_t i = 0; i < rFormats.size(); ++i)
+ {
+ const SwSectionFormat* pFormat = rFormats[i];
+ if (!pFormat->GetName().startsWith(aSectionNamePrefix))
+ {
+ continue;
+ }
+
+ if (nSectionIndex >= aSections.getLength())
+ {
+ break;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aSections[nSectionIndex++]);
+ OUString aSectionName = aMap["RegionName"].get<OUString>();
+ if (aSectionName != pFormat->GetName())
+ {
+ const_cast<SwSectionFormat*>(pFormat)->SetName(aSectionName, /*bBroadcast=*/true);
+ SwSectionData aSectionData(*pFormat->GetSection());
+ aSectionData.SetSectionName(aSectionName);
+ pDoc->UpdateSection(i, aSectionData);
+ }
+
+ const SwFormatContent& rContent = pFormat->GetContent();
+ const SwNodeIndex* pContentNodeIndex = rContent.GetContentIdx();
+ if (pContentNodeIndex)
+ {
+ SwPaM aSectionStart(SwPosition{*pContentNodeIndex});
+ aSectionStart.Move(fnMoveForward, GoInContent);
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aSectionStart;
+ rWrtSh.EndOfSection(/*bSelect=*/true);
+ rIDCO.DeleteAndJoin(*pCursorPos);
+ rWrtSh.EndSelect();
+
+ OUString aSectionText = aMap["Content"].get<OUString>();
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aSectionText.toUtf8(), true);
+ }
+ }
+
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSSECTION, nullptr);
+}
+
+void DeleteSections(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ OUString aSectionNamePrefix;
+ const SfxStringItem* pSectionNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pSectionNamePrefix)
+ {
+ aSectionNamePrefix = pSectionNamePrefix->GetValue();
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELSECTION, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELSECTION, nullptr);
+ });
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ SwSectionFormats& rFormats = pDoc->GetSections();
+ std::vector<SwSectionFormat*> aRemovals;
+ for (size_t i = 0; i < rFormats.size(); ++i)
+ {
+ SwSectionFormat* pFormat = rFormats[i];
+
+ if (!aSectionNamePrefix.isEmpty())
+ {
+ if (!pFormat->GetName().startsWith(aSectionNamePrefix))
+ {
+ continue;
+ }
+ }
+
+ aRemovals.push_back(pFormat);
+ }
+
+ for (const auto& pFormat : aRemovals)
+ {
+ // Just delete the format, not the content of the section.
+ pDoc->DelSectionFormat(pFormat);
+ }
+}
+
+void UpdateBookmarks(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+ {
+ return;
+ }
+
+ OUString aBookmarkNamePrefix;
+ const SfxStringItem* pBookmarkNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pBookmarkNamePrefix)
+ {
+ aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+ }
+
+ uno::Sequence<beans::PropertyValues> aBookmarks;
+ const SfxUnoAnyItem* pBookmarks = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2);
+ if (pBookmarks)
+ {
+ pBookmarks->GetValue() >>= aBookmarks;
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+
+ IDocumentMarkAccess& rIDMA = *rWrtSh.GetDoc()->getIDocumentMarkAccess();
+ sal_Int32 nBookmarkIndex = 0;
+ bool bSortMarks = false;
+ for (auto it = rIDMA.getBookmarksBegin(); it != rIDMA.getBookmarksEnd(); ++it)
+ {
+ auto pMark = dynamic_cast<sw::mark::Bookmark*>(*it);
+ assert(pMark);
+ if (!pMark->GetName().startsWith(aBookmarkNamePrefix))
+ {
+ continue;
+ }
+
+ if (aBookmarks.getLength() <= nBookmarkIndex)
+ {
+ continue;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aBookmarks[nBookmarkIndex++]);
+ if (aMap["Bookmark"].get<OUString>() != pMark->GetName())
+ {
+ rIDMA.renameMark(pMark, aMap["Bookmark"].get<OUString>());
+ }
+
+ OUString aBookmarkText = aMap["BookmarkText"].get<OUString>();
+
+ // Insert markers to remember where the paste positions are.
+ SwPaM aMarkers(pMark->GetMarkEnd());
+ IDocumentContentOperations& rIDCO = rWrtSh.GetDoc()->getIDocumentContentOperations();
+ bool bSuccess = rIDCO.InsertString(aMarkers, "XY");
+ if (bSuccess)
+ {
+ SwPaM aPasteEnd(pMark->GetMarkEnd());
+ aPasteEnd.Move(fnMoveForward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aBookmarkText.toUtf8(), true);
+
+ // Update the bookmark to point to the new content.
+ SwPaM aPasteStart(pMark->GetMarkEnd());
+ aPasteStart.Move(fnMoveForward, GoInContent);
+ SwPaM aStartMarker(pMark->GetMarkStart(), *aPasteStart.GetPoint());
+ SwPaM aEndMarker(*aPasteEnd.GetPoint(), *aPasteEnd.GetPoint());
+ aEndMarker.GetMark()->nContent += 1;
+ pMark->SetMarkPos(*aPasteStart.GetPoint());
+ pMark->SetOtherMarkPos(*aPasteEnd.GetPoint());
+ bSortMarks = true;
+
+ // Remove markers. the start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+ }
+ }
+ if (bSortMarks)
+ {
+ rIDMA.assureSortedMarkContainers();
+ }
+
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+}
+
+void UpdateBookmark(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+ {
+ return;
+ }
+
+ OUString aBookmarkNamePrefix;
+ const SfxStringItem* pBookmarkNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pBookmarkNamePrefix)
+ {
+ aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+ }
+
+ uno::Sequence<beans::PropertyValue> aBookmark;
+ const SfxUnoAnyItem* pBookmarks = rReq.GetArg<SfxUnoAnyItem>(FN_PARAM_2);
+ if (pBookmarks)
+ {
+ pBookmarks->GetValue() >>= aBookmark;
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::INSBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::INSBOOKMARK, nullptr);
+ });
+
+ IDocumentMarkAccess& rIDMA = *rWrtSh.GetDoc()->getIDocumentMarkAccess();
+ SwPosition& rCursor = *rWrtSh.GetCursor()->GetPoint();
+ auto pBookmark = dynamic_cast<sw::mark::Bookmark*>(rIDMA.getBookmarkFor(rCursor));
+ if (!pBookmark || !pBookmark->GetName().startsWith(aBookmarkNamePrefix))
+ {
+ return;
+ }
+
+ comphelper::SequenceAsHashMap aMap(aBookmark);
+ if (aMap["Bookmark"].get<OUString>() != pBookmark->GetName())
+ {
+ rIDMA.renameMark(pBookmark, aMap["Bookmark"].get<OUString>());
+ }
+
+ OUString aBookmarkText = aMap["BookmarkText"].get<OUString>();
+
+ // Insert markers to remember where the paste positions are.
+ SwPaM aMarkers(pBookmark->GetMarkEnd());
+ IDocumentContentOperations& rIDCO = rWrtSh.GetDoc()->getIDocumentContentOperations();
+ if (!rIDCO.InsertString(aMarkers, "XY"))
+ {
+ return;
+ }
+
+ SwPaM aPasteEnd(pBookmark->GetMarkEnd());
+ aPasteEnd.Move(fnMoveForward, GoInContent);
+
+ // Paste HTML content.
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
+ *pCursorPos = aPasteEnd;
+ SwTranslateHelper::PasteHTMLToPaM(rWrtSh, pCursorPos, aBookmarkText.toUtf8(), true);
+
+ // Update the bookmark to point to the new content.
+ SwPaM aPasteStart(pBookmark->GetMarkEnd());
+ aPasteStart.Move(fnMoveForward, GoInContent);
+ SwPaM aStartMarker(pBookmark->GetMarkStart(), *aPasteStart.GetPoint());
+ SwPaM aEndMarker(*aPasteEnd.GetPoint(), *aPasteEnd.GetPoint());
+ aEndMarker.GetMark()->nContent += 1;
+ pBookmark->SetMarkPos(*aPasteStart.GetPoint());
+ pBookmark->SetOtherMarkPos(*aPasteEnd.GetPoint());
+
+ // Remove markers. the start marker includes the old content as well.
+ rIDCO.DeleteAndJoin(aStartMarker);
+ rIDCO.DeleteAndJoin(aEndMarker);
+ rIDMA.assureSortedMarkContainers();
+}
+
+void DeleteBookmarks(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ if (rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
+ {
+ return;
+ }
+
+ OUString aBookmarkNamePrefix;
+ const SfxStringItem* pBookmarkNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (pBookmarkNamePrefix)
+ {
+ aBookmarkNamePrefix = pBookmarkNamePrefix->GetValue();
+ }
+
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELBOOKMARK, nullptr);
+ });
+
+ IDocumentMarkAccess* pMarkAccess = rWrtSh.GetDoc()->getIDocumentMarkAccess();
+ std::vector<sw::mark::IMark*> aRemovals;
+ for (auto it = pMarkAccess->getBookmarksBegin(); it != pMarkAccess->getBookmarksEnd(); ++it)
+ {
+ auto pBookmark = dynamic_cast<sw::mark::Bookmark*>(*it);
+ assert(pBookmark);
+
+ if (!aBookmarkNamePrefix.isEmpty())
+ {
+ if (!pBookmark->GetName().startsWith(aBookmarkNamePrefix))
+ {
+ continue;
+ }
+ }
+
+ aRemovals.push_back(pBookmark);
+ }
+
+ for (const auto& pMark : aRemovals)
+ {
+ pMarkAccess->deleteMark(pMark);
+ }
+}
+
+void DeleteFields(SfxRequest& rReq, SwWrtShell& rWrtSh)
+{
+ const SfxStringItem* pTypeName = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ if (!pTypeName || pTypeName->GetValue() != "SetRef")
+ {
+ // This is implemented so far only for reference marks.
+ return;
+ }
+
+ OUString aNamePrefix;
+ const SfxStringItem* pNamePrefix = rReq.GetArg<SfxStringItem>(FN_PARAM_2);
+ if (pNamePrefix)
+ {
+ aNamePrefix = pNamePrefix->GetValue();
+ }
+
+ SwDoc* pDoc = rWrtSh.GetDoc();
+ pDoc->GetIDocumentUndoRedo().StartUndo(SwUndoId::DELBOOKMARK, nullptr);
+ rWrtSh.StartAction();
+ comphelper::ScopeGuard g(
+ [&rWrtSh]
+ {
+ rWrtSh.EndAction();
+ rWrtSh.GetDoc()->GetIDocumentUndoRedo().EndUndo(SwUndoId::DELBOOKMARK, nullptr);
+ });
+
+ std::vector<const SwFormatRefMark*> aRemovals;
+ for (sal_uInt16 i = 0; i < pDoc->GetRefMarks(); ++i)
+ {
+ const SwFormatRefMark* pRefMark = pDoc->GetRefMark(i);
+ if (!aNamePrefix.isEmpty())
+ {
+ if (!pRefMark->GetRefName().startsWith(aNamePrefix))
+ {
+ continue;
+ }
+ }
+
+ aRemovals.push_back(pRefMark);
+ }
+
+ for (const auto& pMark : aRemovals)
+ {
+ pDoc->DeleteFormatRefMark(pMark);
+ }
+}
}
void SwTextShell::Execute(SfxRequest &rReq)
@@ -690,10 +1066,52 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
case FN_INSERT_BOOKMARK:
{
+ const SfxStringItem* pBookmarkText = rReq.GetArg<SfxStringItem>(FN_PARAM_1);
+ SwPaM* pCursorPos = rWrtSh.GetCursor();
if ( pItem )
{
+ rWrtSh.StartAction();
OUString sName = static_cast<const SfxStringItem*>(pItem)->GetValue();
+
+ if (pBookmarkText)
+ {
+ OUString aBookmarkText = pBookmarkText->GetValue();
+ // Split node to remember where the start position is.
+ bool bSuccess = rWrtSh.GetDoc()->getIDocumentContentOperations().SplitNode(
+ *pCursorPos->GetPoint(), /*bChkTableStart=*/false);
+ if (bSuccess)
+ {
+ SwPaM aBookmarkPam(*pCursorPos->GetPoint());
+ aBookmarkPam.Move(fnMoveBackward, GoInContent);
+
+ // Paste HTML content.
+ SwTranslateHelper::PasteHTMLToPaM(
+ rWrtSh, pCursorPos, aBookmarkText.toUtf8(), /*bSetSelection=*/true);
+ if (pCursorPos->GetPoint()->nContent == 0)
+ {
+ // The paste created a last empty text node, remove it.
+ SwPaM aPam(*pCursorPos->GetPoint());
+ aPam.SetMark();
+ aPam.Move(fnMoveBackward, GoInContent);
+ rWrtSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(aPam);
+ }
+
+ // Undo the above SplitNode().
+ aBookmarkPam.SetMark();
+ aBookmarkPam.Move(fnMoveForward, GoInContent);
+ rWrtSh.GetDoc()->getIDocumentContentOperations().DeleteAndJoin(
+ aBookmarkPam);
+ *aBookmarkPam.GetMark() = *pCursorPos->GetPoint();
+ *pCursorPos = aBookmarkPam;
+ }
+ }
+
rWrtSh.SetBookmark( vcl::KeyCode(), sName );
+ if (pBookmarkText)
+ {
+ pCursorPos->DeleteMark();
+ }
+ rWrtSh.EndAction();
}
else
{
@@ -706,8 +1124,22 @@ void SwTextShell::Execute(SfxRequest &rReq)
break;
}
+ case FN_UPDATE_BOOKMARKS:
+ {
+ // This updates all bookmarks in the document that match the conditions specified in
+ // rReq.
+ UpdateBookmarks(rReq, rWrtSh);
+ break;
+ }
+ case FN_UPDATE_BOOKMARK:
+ {
+ // This updates the bookmark under the cursor.
+ UpdateBookmark(rReq, rWrtSh);
+ break;
+ }
case FN_DELETE_BOOKMARK:
{
+ // This deletes a bookmark with the specified name.
if (pItem && !rWrtSh.getIDocumentSettingAccess().get(DocumentSettingId::PROTECT_BOOKMARKS))
{
IDocumentMarkAccess* const pMarkAccess = rWrtSh.getIDocumentMarkAccess();
@@ -715,6 +1147,30 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
break;
}
+ case FN_DELETE_BOOKMARKS:
+ {
+ // This deletes all bookmarks in the document matching a specified prefix.
+ DeleteBookmarks(rReq, rWrtSh);
+ break;
+ }
+ case FN_DELETE_FIELDS:
+ {
+ // This deletes all fields in the document matching a specified type & prefix.
+ DeleteFields(rReq, rWrtSh);
+ break;
+ }
+ case FN_UPDATE_SECTIONS:
+ {
+ UpdateSections(rReq, rWrtSh);
+ break;
+ }
+ case FN_DELETE_SECTIONS:
+ {
+ // This deletes all sections in the document matching a specified prefix. Note that the
+ // section is deleted, but not its contents.
+ DeleteSections(rReq, rWrtSh);
+ break;
+ }
case FN_SET_REMINDER:
{
// collect and sort navigator reminder names
@@ -1503,6 +1959,32 @@ void SwTextShell::Execute(SfxRequest &rReq)
}
}
break;
+ case SID_FM_TRANSLATE:
+ {
+ const SfxPoolItem* pTargetLangStringItem = nullptr;
+ if (pArgs && SfxItemState::SET == pArgs->GetItemState(SID_ATTR_TARGETLANG_STR, false, &pTargetLangStringItem))
+ {
+ SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ SAL_WARN("translate", "API options are not set");
+ break;
+ }
+ const OString aAPIUrl = OUStringToOString(OUString(rDeeplOptions.getAPIUrl() + "?tag_handling=html"), RTL_TEXTENCODING_UTF8).trim();
+ const OString aAuthKey = OUStringToOString(rDeeplOptions.getAuthKey(), RTL_TEXTENCODING_UTF8).trim();
+ OString aTargetLang = OUStringToOString(static_cast<const SfxStringItem*>(pTargetLangStringItem)->GetValue(), RTL_TEXTENCODING_UTF8);
+ SwTranslateHelper::TranslateAPIConfig aConfig({aAPIUrl, aAuthKey, aTargetLang});
+ SwTranslateHelper::TranslateDocument(rWrtSh, aConfig);
+ }
+ else
+ {
+ SwAbstractDialogFactory* pFact = SwAbstractDialogFactory::Create();
+ std::shared_ptr<AbstractSwTranslateLangSelectDlg> pAbstractDialog(pFact->CreateSwTranslateLangSelectDlg(GetView().GetFrameWeld(), rWrtSh));
+ std::shared_ptr<weld::DialogController> pDialogController(pAbstractDialog->getDialogController());
+ weld::DialogController::runAsync(pDialogController, [] (sal_Int32 /*nResult*/) { });
+ }
+ }
+ break;
case SID_SPELLCHECK_IGNORE:
{
SwPaM *pPaM = rWrtSh.GetCursor();
@@ -1536,9 +2018,12 @@ void SwTextShell::Execute(SfxRequest &rReq)
SwPaM *pPaM = rWrtSh.GetCursor();
if (pPaM)
SwEditShell::IgnoreGrammarErrorAt( *pPaM );
- // refresh the layout of all paragraphs (workaround to launch a dictionary event)
- xDictionary->setActive(false);
- xDictionary->setActive(true);
+ if (xDictionary.is())
+ {
+ // refresh the layout of all paragraphs (workaround to launch a dictionary event)
+ xDictionary->setActive(false);
+ xDictionary->setActive(true);
+ }
}
catch( const uno::Exception& )
{
@@ -1973,6 +2458,16 @@ void SwTextShell::GetState( SfxItemSet &rSet )
}
break;
+ case SID_FM_TRANSLATE:
+ {
+ const SvxDeeplOptions& rDeeplOptions = SvxDeeplOptions::Get();
+ if (rDeeplOptions.getAPIUrl().isEmpty() || rDeeplOptions.getAuthKey().isEmpty())
+ {
+ rSet.DisableItem(nWhich);
+ }
+ }
+ break;
+
case SID_HYPERLINK_DIALOG:
if( GetView().GetDocShell()->IsReadOnly()
|| ( !GetView().GetViewFrame()->HasChildWindow(nWhich)