summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKohei Yoshida <kohei.yoshida@suse.com>2012-01-05 22:13:52 -0500
committerKohei Yoshida <kohei.yoshida@suse.com>2012-01-05 22:23:20 -0500
commita6dc4b7a1e2fcbe478bc7feae06bc9ff24b26aaf (patch)
tree92ee81e63dff16bc6c9428153d591d2d74a076b6
parent4b6f8b09e6823dfb237a4b9ea5c2abc21ccf030a (diff)
fdo#36851, bnc#737190: Make the data validation popup more reliable.
Previously, the data validation message popup was not sticking on reliably on Linux, and flickers very bad on Windows. That was due to the painting conflict between the top-most frame window and the grid window. By making the message popup window a child window of the grid window, it paints more reliably.
-rw-r--r--sc/source/ui/inc/tabview.hxx9
-rw-r--r--sc/source/ui/view/tabview.cxx9
-rw-r--r--sc/source/ui/view/tabview3.cxx199
-rw-r--r--sc/source/ui/view/tabview5.cxx2
4 files changed, 163 insertions, 56 deletions
diff --git a/sc/source/ui/inc/tabview.hxx b/sc/source/ui/inc/tabview.hxx
index c3563798728d..09244bb10fd9 100644
--- a/sc/source/ui/inc/tabview.hxx
+++ b/sc/source/ui/inc/tabview.hxx
@@ -36,6 +36,9 @@
#include "viewutil.hxx"
#include "select.hxx"
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+
class ScEditEngineDefaulter;
class ScGridWindow;
class ScOutlineWindow;
@@ -89,7 +92,7 @@ public:
// ---------------------------------------------------------------------------
-class ScTabView
+class ScTabView : boost::noncopyable
{
private:
enum BlockMode { None = 0, Normal = 1, Own = 2 };
@@ -129,7 +132,7 @@ private:
ScCornerButton aTopButton;
ScrollBarBox aScrollBarBox;
- ScHintWindow* pInputHintWindow; // Eingabemeldung bei Gueltigkeit
+ boost::scoped_ptr<ScHintWindow> mpInputHintWindow; // popup window for data validation
ScPageBreakData* pPageBreakData; // fuer Seitenumbruch-Modus
std::vector<ScHighlightEntry> maHighlightRanges;
@@ -243,7 +246,7 @@ public:
void HideListBox();
- bool HasHintWindow() const { return pInputHintWindow != NULL; }
+ bool HasHintWindow() const;
void RemoveHintWindow();
void TestHintWindow();
diff --git a/sc/source/ui/view/tabview.cxx b/sc/source/ui/view/tabview.cxx
index bba84cd9321c..6d1652f7c982 100644
--- a/sc/source/ui/view/tabview.cxx
+++ b/sc/source/ui/view/tabview.cxx
@@ -142,6 +142,7 @@
#include "AccessibilityHints.hxx"
#include "appoptio.hxx"
#include "attrib.hxx"
+#include "hintwin.hxx"
#include <com/sun/star/sheet/DataPilotFieldOrientation.hpp>
@@ -307,7 +308,7 @@ ScTabView::ScTabView( Window* pParent, ScDocShell& rDocSh, ScTabViewShell* pView
aCornerButton( pFrameWin, &aViewData, false ),
aTopButton( pFrameWin, &aViewData, sal_True ),
aScrollBarBox( pFrameWin, WB_SIZEABLE ),
- pInputHintWindow( NULL ),
+ mpInputHintWindow( NULL ),
pPageBreakData( NULL ),
pBrushDocument( NULL ),
pDrawBrushSet( NULL ),
@@ -390,7 +391,7 @@ void ScTabView::DoResize( const Point& rOffset, const Size& rSize, bool bInner )
{
HideListBox();
- bool bHasHint = ( pInputHintWindow != NULL );
+ bool bHasHint = HasHintWindow();
if (bHasHint)
RemoveHintWindow();
@@ -1300,7 +1301,7 @@ IMPL_LINK( ScTabView, ScrollHdl, ScrollBar*, pScroll )
void ScTabView::ScrollX( long nDeltaX, ScHSplitPos eWhich, bool bUpdBars )
{
- sal_Bool bHasHint = ( pInputHintWindow != NULL );
+ bool bHasHint = HasHintWindow();
if (bHasHint)
RemoveHintWindow();
@@ -1389,7 +1390,7 @@ void ScTabView::ScrollX( long nDeltaX, ScHSplitPos eWhich, bool bUpdBars )
void ScTabView::ScrollY( long nDeltaY, ScVSplitPos eWhich, bool bUpdBars )
{
- sal_Bool bHasHint = ( pInputHintWindow != NULL );
+ bool bHasHint = HasHintWindow();
if (bHasHint)
RemoveHintWindow();
diff --git a/sc/source/ui/view/tabview3.cxx b/sc/source/ui/view/tabview3.cxx
index 556d3bf33a09..a8fd507e629a 100644
--- a/sc/source/ui/view/tabview3.cxx
+++ b/sc/source/ui/view/tabview3.cxx
@@ -359,7 +359,6 @@ void ScTabView::CellContentChanged()
rBindings.Invalidate( SID_HYPERLINK_GETLINK );
InvalidateAttribs(); // Attribut-Updates
- TestHintWindow(); // Eingabemeldung (Gueltigkeit)
aViewData.GetViewShell()->UpdateInputHandler();
}
@@ -470,6 +469,135 @@ void ScTabView::CursorPosChanged()
aViewData.SetTabStartCol( SC_TABSTART_NONE );
}
+namespace {
+
+Point calcHintWindowPosition(
+ const Point& rCellPos, const Size& rCellSize, const Size& rFrameWndSize, const Size& rHintWndSize)
+{
+ const long nMargin = 20;
+
+ long nMLeft = rCellPos.X();
+ long nMRight = rFrameWndSize.Width() - rCellPos.X() - rCellSize.Width();
+ long nMTop = rCellPos.Y();
+ long nMBottom = rFrameWndSize.Height() - rCellPos.Y() - rCellSize.Height();
+
+ // First, see if we can fit the entire hint window in the visible region.
+
+ if (nMRight - nMargin >= rHintWndSize.Width())
+ {
+ // Right margin is wide enough.
+ if (rFrameWndSize.Height() >= rHintWndSize.Height())
+ {
+ // The frame has enough height. Take it.
+ Point aPos = rCellPos;
+ aPos.X() += rCellSize.Width() + nMargin;
+ if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
+ {
+ // Push the hint window up a bit to make it fit.
+ aPos.Y() = rFrameWndSize.Height() - rHintWndSize.Height();
+ }
+ return aPos;
+ }
+ }
+
+ if (nMBottom - nMargin >= rHintWndSize.Height())
+ {
+ // Bottom margin is high enough.
+ if (rFrameWndSize.Width() >= rHintWndSize.Width())
+ {
+ // The frame has enough width. Take it.
+ Point aPos = rCellPos;
+ aPos.Y() += rCellSize.Height() + nMargin;
+ if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
+ {
+ // Move the hint window to the left to make it fit.
+ aPos.X() = rFrameWndSize.Width() - rHintWndSize.Width();
+ }
+ return aPos;
+ }
+ }
+
+ if (nMLeft - nMargin >= rHintWndSize.Width())
+ {
+ // Left margin is wide enough.
+ if (rFrameWndSize.Height() >= rHintWndSize.Height())
+ {
+ // The frame is high enough. Take it.
+ Point aPos = rCellPos;
+ aPos.X() -= rHintWndSize.Width() + nMargin;
+ if (aPos.Y() + rHintWndSize.Height() > rFrameWndSize.Height())
+ {
+ // Push the hint window up a bit to make it fit.
+ aPos.Y() = rFrameWndSize.Height() - rHintWndSize.Height();
+ }
+ return aPos;
+ }
+ }
+
+ if (nMTop - nMargin >= rHintWndSize.Height())
+ {
+ // Top margin is high enough.
+ if (rFrameWndSize.Width() >= rHintWndSize.Width())
+ {
+ // The frame is wide enough. Take it.
+ Point aPos = rCellPos;
+ aPos.Y() -= rHintWndSize.Height() + nMargin;
+ if (aPos.X() + rHintWndSize.Width() > rFrameWndSize.Width())
+ {
+ // Move the hint window to the left to make it fit.
+ aPos.X() = rFrameWndSize.Width() - rHintWndSize.Width();
+ }
+ return aPos;
+ }
+ }
+
+ // The popup doesn't fit in any direction in its entirety. Do our best.
+
+ if (nMRight - nMargin >= rHintWndSize.Width())
+ {
+ // Right margin is good enough.
+ Point aPos = rCellPos;
+ aPos.X() += nMargin;
+ aPos.Y() = 0;
+ return aPos;
+ }
+
+ if (nMBottom - nMargin >= rHintWndSize.Height())
+ {
+ // Bottom margin is good enough.
+ Point aPos = rCellPos;
+ aPos.Y() += nMargin + rCellSize.Height();
+ aPos.X() = 0;
+ return aPos;
+ }
+
+ if (nMLeft - nMargin >= rHintWndSize.Width())
+ {
+ // Left margin is good enough.
+ Point aPos = rCellPos;
+ aPos.X() -= rHintWndSize.Width() + nMargin;
+ aPos.Y() = 0;
+ return aPos;
+ }
+
+ if (nMTop - nMargin >= rHintWndSize.Height())
+ {
+ // Top margin is good enough.
+ Point aPos = rCellPos;
+ aPos.Y() -= rHintWndSize.Height() + nMargin;
+ aPos.X() = 0;
+ return aPos;
+ }
+
+ // None of the above. Hopeless. At least try not to cover the current
+ // cell.
+ Point aPos = rCellPos;
+ aPos.X() += rCellSize.Width();
+ return aPos;
+}
+
+}
+
void ScTabView::TestHintWindow()
{
// show input help window and list drop-down button for validity
@@ -492,10 +620,10 @@ void ScTabView::TestHintWindow()
{
//! Abfrage, ob an gleicher Stelle !!!!
- DELETEZ(pInputHintWindow);
+ mpInputHintWindow.reset();
ScSplitPos eWhich = aViewData.GetActivePart();
- Window* pWin = pGridWin[eWhich];
+ ScGridWindow* pWin = pGridWin[eWhich];
SCCOL nCol = aViewData.GetCurX();
SCROW nRow = aViewData.GetCurY();
Point aPos = aViewData.GetScrPos( nCol, nRow, eWhich );
@@ -505,52 +633,23 @@ void ScTabView::TestHintWindow()
nRow >= aViewData.GetPosY(WhichV(eWhich)) &&
aPos.X() < aWinSize.Width() && aPos.Y() < aWinSize.Height() )
{
- aPos += pWin->GetPosPixel(); // Position auf Frame
- long nSizeXPix;
- long nSizeYPix;
- aViewData.GetMergeSizePixel( nCol, nRow, nSizeXPix, nSizeYPix );
-
// HintWindow anlegen, bestimmt seine Groesse selbst
- pInputHintWindow = new ScHintWindow( pFrameWin, aTitle, aMessage );
- Size aHintSize = pInputHintWindow->GetSizePixel();
- Size aFrameWinSize = pFrameWin->GetOutputSizePixel();
-
- // passende Position finden
- // erster Versuch: unter dem Cursor
- Point aHintPos( aPos.X() + nSizeXPix / 2, aPos.Y() + nSizeYPix + 3 );
- if ( aHintPos.Y() + aHintSize.Height() > aFrameWinSize.Height() )
- {
- // zweiter Versuch: rechts vom Cursor
- aHintPos = Point( aPos.X() + nSizeXPix + 3, aPos.Y() + nSizeYPix / 2 );
- if ( aHintPos.X() + aHintSize.Width() > aFrameWinSize.Width() )
- {
- // dritter Versuch: ueber dem Cursor
- aHintPos = Point( aPos.X() + nSizeXPix / 2,
- aPos.Y() - aHintSize.Height() - 3 );
- if ( aHintPos.Y() < 0 )
- {
- // oben und unten kein Platz - dann Default und abschneiden
- aHintPos = Point( aPos.X() + nSizeXPix / 2, aPos.Y() + nSizeYPix + 3 );
- aHintSize.Height() = aFrameWinSize.Height() - aHintPos.Y();
- pInputHintWindow->SetSizePixel( aHintSize );
- }
- }
- }
-
- // X anpassen
- if ( aHintPos.X() + aHintSize.Width() > aFrameWinSize.Width() )
- aHintPos.X() = aFrameWinSize.Width() - aHintSize.Width();
- // Y anpassen
- if ( aHintPos.Y() + aHintSize.Height() > aFrameWinSize.Height() )
- aHintPos.Y() = aFrameWinSize.Height() - aHintSize.Height();
-
- pInputHintWindow->SetPosPixel( aHintPos );
- pInputHintWindow->ToTop();
- pInputHintWindow->Show();
+ mpInputHintWindow.reset(new ScHintWindow(pWin, aTitle, aMessage));
+ Size aHintWndSize = mpInputHintWindow->GetSizePixel();
+ long nCellSizeX = 0;
+ long nCellSizeY = 0;
+ aViewData.GetMergeSizePixel(nCol, nRow, nCellSizeX, nCellSizeY);
+
+ Point aHintPos = calcHintWindowPosition(
+ aPos, Size(nCellSizeX,nCellSizeY), aWinSize, aHintWndSize);
+
+ mpInputHintWindow->SetPosPixel( aHintPos );
+ mpInputHintWindow->ToTop();
+ mpInputHintWindow->Show();
}
}
else
- DELETEZ(pInputHintWindow);
+ mpInputHintWindow.reset();
// list drop-down button
if ( pData && pData->HasSelectionList() )
@@ -560,16 +659,21 @@ void ScTabView::TestHintWindow()
}
}
else
- DELETEZ(pInputHintWindow);
+ mpInputHintWindow.reset();
for ( sal_uInt16 i=0; i<4; i++ )
if ( pGridWin[i] && pGridWin[i]->IsVisible() )
pGridWin[i]->UpdateListValPos( bListValButton, aListValPos );
}
+bool ScTabView::HasHintWindow() const
+{
+ return mpInputHintWindow.get() != NULL;
+}
+
void ScTabView::RemoveHintWindow()
{
- DELETEZ(pInputHintWindow);
+ mpInputHintWindow.reset();
}
@@ -938,6 +1042,7 @@ void ScTabView::MoveCursorAbs( SCsCOL nCurX, SCsROW nCurY, ScFollowMode eMode,
}
ShowAllCursors();
+ TestHintWindow();
}
void ScTabView::MoveCursorRel( SCsCOL nMovX, SCsROW nMovY, ScFollowMode eMode,
diff --git a/sc/source/ui/view/tabview5.cxx b/sc/source/ui/view/tabview5.cxx
index a20f78ac9f29..bd1a979e202f 100644
--- a/sc/source/ui/view/tabview5.cxx
+++ b/sc/source/ui/view/tabview5.cxx
@@ -170,8 +170,6 @@ ScTabView::~ScTabView()
aViewData.KillEditView(); // solange GridWin's noch existieren
- DELETEZ(pInputHintWindow);
-
if (pDrawView)
{
for (i=0; i<4; i++)