[Libreoffice-commits] core.git: Branch 'feature/gsoc-tiled-rendering' - 24 commits - config_host.mk.in dbaccess/source download.lst external/libetonyek icon-themes/breeze include/LibreOfficeKit libreofficekit/qa libreofficekit/source pyuno/inc pyuno/Library_pyuno.mk pyuno/Module_pyuno.mk pyuno/PythonTest_pytests.mk pyuno/PythonTest_pyuno_pytests_testcollections.mk pyuno/qa pyuno/source RepositoryExternal.mk sc/source sd/source solenv/gbuild sw/qa vcl/inc vcl/unx writerfilter/source
Pranav Kant
pranavk at gnome.org
Fri Jun 26 03:57:31 PDT 2015
Rebased ref, commits from common ancestor:
commit 614485f2778476b45706455ed767114bb2a0f112
Author: Pranav Kant <pranavk at gnome.org>
Date: Wed Jun 24 02:02:39 2015 +0530
lokdocview: Handle DELETE key
Change-Id: I58d0c36decf81c812c108458b449402416ebcc2d
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index ca7167b..62f1e61 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -245,6 +245,9 @@ signalKey (GtkWidget* pWidget, GdkEventKey* pEvent)
case GDK_KEY_BackSpace:
nKeyCode = com::sun::star::awt::Key::BACKSPACE;
break;
+ case GDK_KEY_Delete:
+ nKeyCode = com::sun::star::awt::Key::DELETE;
+ break;
case GDK_KEY_Return:
nKeyCode = com::sun::star::awt::Key::RETURN;
break;
commit 2f6b0216649c07f98088d13a938179003c661bfb
Author: Pranav Kant <pranavk at gnome.org>
Date: Tue Jun 23 14:37:09 2015 +0530
tilebuffer: Add timer to measure paintTile() call
Change-Id: I2645863c7445e17d77e2c4e2dc24e22f8685034e
diff --git a/libreofficekit/source/gtk/tilebuffer.cxx b/libreofficekit/source/gtk/tilebuffer.cxx
index 3f22f98..60aa16f 100644
--- a/libreofficekit/source/gtk/tilebuffer.cxx
+++ b/libreofficekit/source/gtk/tilebuffer.cxx
@@ -91,7 +91,7 @@ Tile& TileBuffer::getTile(int x, int y, float aZoom)
aTileRectangle.x = pixelToTwip(nTileSizePixels, aZoom) * y;
aTileRectangle.y = pixelToTwip(nTileSizePixels, aZoom) * x;
- g_info ("Rendering (%d, %d)", x, y);
+ g_test_timer_start();
m_pLOKDocument->pClass->paintTile(m_pLOKDocument,
pBuffer,
nTileSizePixels, nTileSizePixels,
@@ -99,6 +99,9 @@ Tile& TileBuffer::getTile(int x, int y, float aZoom)
pixelToTwip(nTileSizePixels, aZoom),
pixelToTwip(nTileSizePixels, aZoom));
+ double elapsedTime = g_test_timer_elapsed();
+ g_info ("Rendered (%d, %d) in %f seconds", x, y, elapsedTime);
+
//create a mapping for it
m_mTiles[index].setPixbuf(pPixBuf);
m_mTiles[index].valid = true;
commit c31e0efbf65191e3e92e84347ec223ce4aa87c21
Author: Pranav Kant <pranavk at gnome.org>
Date: Tue Jun 23 02:58:38 2015 +0530
lokdocview: Remove superfluous *_post_key()
Instead directly let LOKDocView handle the input.
Change-Id: I260a460df23c3e2e5c78d8b363bb864ae5c63dab
diff --git a/include/LibreOfficeKit/LibreOfficeKitGtk.h b/include/LibreOfficeKit/LibreOfficeKitGtk.h
index 3a1628b..962f9d9 100644
--- a/include/LibreOfficeKit/LibreOfficeKitGtk.h
+++ b/include/LibreOfficeKit/LibreOfficeKitGtk.h
@@ -74,10 +74,6 @@ void lok_doc_view_post_command (LOKDocView*
const char* pCommand,
const char* pArguments);
-/// Posts a keyboard event to LibreOfficeKit.
-void lok_doc_view_post_key (LOKDocView* pDocView,
- GdkEvent* pEvent);
-
float lok_doc_view_pixel_to_twip (LOKDocView* pDocView,
float fInput);
diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
index c854288..18815d6 100644
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
@@ -191,19 +191,6 @@ static void getVisibleAreaTwips(GdkRectangle* pArea)
#endif
}
-
-/// Handles the key-press-event of the window.
-static gboolean signalKey(GtkWidget* /*pWidget*/, GdkEvent* pEvent, gpointer/* pData*/)
-{
- LOKDocView* pLOKDocView = LOK_DOC_VIEW(pDocView);
- if (!gtk_widget_get_visible(pFindbar) && bool(lok_doc_view_get_edit(pLOKDocView)))
- {
- lok_doc_view_post_key(pLOKDocView, pEvent);
- return TRUE;
- }
- return FALSE;
-}
-
/// Searches for the next or previous text of pFindbarEntry.
static void doSearch(bool bBackwards)
{
@@ -541,10 +528,6 @@ int main( int argc, char* argv[] )
g_signal_connect(pDocView, "part-changed", G_CALLBACK(signalPart), NULL);
g_signal_connect(pDocView, "hyperlink-clicked", G_CALLBACK(signalHyperlink), NULL);
- // Input handling.
- g_signal_connect(pWindow, "key-press-event", G_CALLBACK(signalKey), pDocView);
- g_signal_connect(pWindow, "key-release-event", G_CALLBACK(signalKey), pDocView);
-
// Scrolled window for DocView
pScrolledWindow = gtk_scrolled_window_new(0, 0);
gtk_widget_set_hexpand (pScrolledWindow, TRUE);
@@ -568,6 +551,11 @@ int main( int argc, char* argv[] )
g_signal_connect(G_OBJECT(pPartModeComboBox), "changed", G_CALLBACK(changePartMode), 0);
g_signal_connect(G_OBJECT(pPartSelector), "changed", G_CALLBACK(changePart), 0);
+ // Make only LOKDocView widget as focussable
+ GList *focusChain = NULL;
+ focusChain = g_list_append( focusChain, pDocView );
+ gtk_container_set_focus_chain ( GTK_CONTAINER (pVBox), focusChain );
+
gtk_main();
return 0;
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index 988397a..ca7167b 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -226,24 +226,21 @@ isEmptyRectangle(const GdkRectangle& rRectangle)
return rRectangle.x == 0 && rRectangle.y == 0 && rRectangle.width == 0 && rRectangle.height == 0;
}
-static void
-signalKey (LOKDocView* pDocView, const GdkEvent* pEvent)
+static gboolean
+signalKey (GtkWidget* pWidget, GdkEventKey* pEvent)
{
+ LOKDocView* pDocView = LOK_DOC_VIEW(pWidget);
LOKDocViewPrivate* priv = static_cast<LOKDocViewPrivate*>(lok_doc_view_get_instance_private (pDocView));
int nCharCode = 0;
int nKeyCode = 0;
- guint keyval;
- GdkModifierType state;
- gdk_event_get_keyval (pEvent, &keyval);
- gdk_event_get_state (pEvent, &state);
if (!priv->m_bEdit)
{
g_info("signalKey: not in edit mode, ignore");
- return;
+ return FALSE;
}
- switch (keyval)
+ switch (pEvent->keyval)
{
case GDK_KEY_BackSpace:
nKeyCode = com::sun::star::awt::Key::BACKSPACE;
@@ -270,22 +267,24 @@ signalKey (LOKDocView* pDocView, const GdkEvent* pEvent)
nKeyCode = com::sun::star::awt::Key::RIGHT;
break;
default:
- if (keyval >= GDK_KEY_F1 && keyval <= GDK_KEY_F26)
- nKeyCode = com::sun::star::awt::Key::F1 + (keyval - GDK_KEY_F1);
+ if (pEvent->keyval >= GDK_KEY_F1 && pEvent->keyval <= GDK_KEY_F26)
+ nKeyCode = com::sun::star::awt::Key::F1 + (pEvent->keyval - GDK_KEY_F1);
else
- nCharCode = gdk_keyval_to_unicode(keyval);
+ nCharCode = gdk_keyval_to_unicode(pEvent->keyval);
}
// rsc is not public API, but should be good enough for debugging purposes.
// If this is needed for real, then probably a new param of type
// css::awt::KeyModifier is needed in postKeyEvent().
- if (state & GDK_SHIFT_MASK)
+ if (pEvent->state & GDK_SHIFT_MASK)
nKeyCode |= KEY_SHIFT;
if (pEvent->type == GDK_KEY_RELEASE)
priv->m_pDocument->pClass->postKeyEvent(priv->m_pDocument, LOK_KEYEVENT_KEYUP, nCharCode, nKeyCode);
else
priv->m_pDocument->pClass->postKeyEvent(priv->m_pDocument, LOK_KEYEVENT_KEYINPUT, nCharCode, nKeyCode);
+
+ return FALSE;
}
static gboolean
@@ -1151,6 +1150,8 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass)
pWidgetClass->draw = lok_doc_view_draw;
pWidgetClass->button_press_event = lok_doc_view_signal_button;
pWidgetClass->button_release_event = lok_doc_view_signal_button;
+ pWidgetClass->key_press_event = signalKey;
+ pWidgetClass->key_release_event = signalKey;
pWidgetClass->motion_notify_event = lok_doc_view_signal_motion;
/**
@@ -1431,6 +1432,8 @@ lok_doc_view_open_document (LOKDocView* pDocView, const gchar* pPath)
gtk_widget_set_size_request(GTK_WIDGET(pDocView),
nDocumentWidthPixels,
nDocumentHeightPixels);
+ gtk_widget_set_can_focus(GTK_WIDGET(pDocView), TRUE);
+ gtk_widget_grab_focus(GTK_WIDGET(pDocView));
}
return TRUE;
}
@@ -1579,19 +1582,6 @@ lok_doc_view_post_command (LOKDocView* pDocView,
}
/**
- * lok_doc_view_post_key:
- * @pDocView: the #LOKDocView instance
- * @pEvent: the #GdkEventKey containing information about the event
- *
- * This methods forwards your key events to the LO core.
-*/
-SAL_DLLPUBLIC_EXPORT void
-lok_doc_view_post_key (LOKDocView* pDocView, GdkEvent* pEvent)
-{
- signalKey(pDocView, pEvent);
-}
-
-/**
* lok_doc_view_pixel_to_twip:
* @pDocView: The #LOKDocView instance
* @fInput: The value in pixels to convert to twips
commit 68ddebb31a369b348d497f6ad165b1ebf993be9b
Author: Pranav Kant <pranavk at gnome.org>
Date: Tue Jun 23 01:52:44 2015 +0530
lokdocview: Don't handle hyperlink clicks
Instead emit the signal 'hyperlink-clicked', and let the
application decide how it wants to handle the hyperlink clicks.
Change-Id: Ief72bbd16727e140cacf28b852ad43952c02f7ae
diff --git a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
index a583323..c854288 100644
--- a/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
+++ b/libreofficekit/qa/gtktiledviewer/gtktiledviewer.cxx
@@ -311,6 +311,17 @@ static void signalPart(LOKDocView* /*pLOKDocView*/, int nPart, gpointer /*pData*
g_bPartSelectorBroadcast = true;
}
+static void signalHyperlink(LOKDocView* /*pLOKDocView*/, char* pPayload, gpointer /*pData*/)
+{
+ GError* pError = NULL;
+ gtk_show_uri(NULL, pPayload, GDK_CURRENT_TIME, &pError);
+ if (pError != NULL)
+ {
+ g_warning("Unable to show URI %s : %s", pPayload, pError->message);
+ g_error_free(pError);
+ }
+}
+
/// User clicked on a cmmand button -> inform LOKDocView.
static void toggleToolItem(GtkWidget* pWidget, gpointer /*pData*/)
{
@@ -528,6 +539,7 @@ int main( int argc, char* argv[] )
g_signal_connect(pDocView, "command-changed", G_CALLBACK(signalCommand), NULL);
g_signal_connect(pDocView, "search-not-found", G_CALLBACK(signalSearch), NULL);
g_signal_connect(pDocView, "part-changed", G_CALLBACK(signalPart), NULL);
+ g_signal_connect(pDocView, "hyperlink-clicked", G_CALLBACK(signalHyperlink), NULL);
// Input handling.
g_signal_connect(pWindow, "key-press-event", G_CALLBACK(signalKey), pDocView);
diff --git a/libreofficekit/source/gtk/lokdocview.cxx b/libreofficekit/source/gtk/lokdocview.cxx
index cff02ea..988397a 100644
--- a/libreofficekit/source/gtk/lokdocview.cxx
+++ b/libreofficekit/source/gtk/lokdocview.cxx
@@ -324,6 +324,12 @@ setPart(LOKDocView* pDocView, const std::string& rString)
g_signal_emit(pDocView, doc_view_signals[PART_CHANGED], 0, std::stoi(rString));
}
+static void
+hyperlinkClicked(LOKDocView* pDocView, const std::string& rString)
+{
+ g_signal_emit(pDocView, doc_view_signals[HYPERLINK_CLICKED], 0, rString.c_str());
+}
+
/// Implementation of the global callback handler, invoked by globalCallback();
static gboolean
globalCallback (gpointer pData)
@@ -507,8 +513,7 @@ callback (gpointer pData)
break;
case LOK_CALLBACK_HYPERLINK_CLICKED:
{
- GError* pError = NULL;
- gtk_show_uri(NULL, pCallback->m_aPayload.c_str(), GDK_CURRENT_TIME, &pError);
+ hyperlinkClicked(pDocView, pCallback->m_aPayload);
}
break;
case LOK_CALLBACK_STATE_CHANGED:
@@ -1353,7 +1358,7 @@ static void lok_doc_view_class_init (LOKDocViewClass* pClass)
* @aHyperlink: the URI which the application should handle
*/
doc_view_signals[HYPERLINK_CLICKED] =
- g_signal_new("hyperlinked-clicked",
+ g_signal_new("hyperlink-clicked",
G_TYPE_FROM_CLASS(pGObjectClass),
G_SIGNAL_RUN_FIRST,
0,
commit 1c481fe6522f4c7d883e77a4ac32f855b9bcb323
Author: Katarina Behrens <Katarina.Behrens at cib.de>
Date: Thu Jun 25 09:47:37 2015 +0200
tdf#87905: Use darker background colour for master view
for the area behind the slide, that is
Change-Id: Ie020f43a81e5eaa257c20d0a7b6feffce1614205
Reviewed-on: https://gerrit.libreoffice.org/16466
Tested-by: Jenkins <ci at libreoffice.org>
Reviewed-by: Philippe Jung <phil.jung at free.fr>
diff --git a/sd/source/ui/inc/DrawViewShell.hxx b/sd/source/ui/inc/DrawViewShell.hxx
index d706392..66a6e86 100644
--- a/sd/source/ui/inc/DrawViewShell.hxx
+++ b/sd/source/ui/inc/DrawViewShell.hxx
@@ -388,6 +388,9 @@ public:
OUString GetSidebarContextName() const;
+ const Color& GetAppBackgroundColor() const { return mnAppBackgroundColor; }
+ void SetAppBackgroundColor( Color nNewColor ) { mnAppBackgroundColor = nNewColor; }
+
//move this method to ViewShell.
//void NotifyAccUpdate();
protected:
@@ -519,6 +522,9 @@ private:
::std::unique_ptr< ViewOverlayManager > mpViewOverlayManager;
std::vector<std::unique_ptr<SdrExternalToolEdit>> m_ExternalEdits;
+
+ // The colour of the area behind the slide (used to be called "Wiese")
+ Color mnAppBackgroundColor;
};
} // end of namespace sd
diff --git a/sd/source/ui/view/drviews1.cxx b/sd/source/ui/view/drviews1.cxx
index 109d82c..8b605b0 100644
--- a/sd/source/ui/view/drviews1.cxx
+++ b/sd/source/ui/view/drviews1.cxx
@@ -316,6 +316,7 @@ bool DrawViewShell::PrepareClose( bool bUI )
return true;
}
+
/**
* Set status (enabled/disabled) of menu SfxSlots
*/
@@ -377,6 +378,9 @@ void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive)
GetViewShellBase().GetToolBarManager()->ResetToolBars(ToolBarManager::TBG_COMMON_TASK);
}
+ svtools::ColorConfig aColorConfig;
+ Color aFillColor = Color( aColorConfig.GetColorValue( svtools::APPBACKGROUND ).nColor );
+
if (meEditMode == EM_PAGE)
{
/******************************************************************
@@ -402,6 +406,8 @@ void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive)
maTabControl->SetCurPageId(nActualPageNum + 1);
+ SetAppBackgroundColor( aFillColor );
+
SwitchPage(nActualPageNum);
}
else
@@ -438,6 +444,9 @@ void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive)
}
}
+ aFillColor.DecreaseLuminance( 64 );
+ SetAppBackgroundColor( aFillColor );
+
maTabControl->SetCurPageId(nActualMasterPageNum + 1);
SwitchPage(nActualMasterPageNum);
}
@@ -477,6 +486,7 @@ void DrawViewShell::ChangeEditMode(EditMode eEMode, bool bIsLayerModeActive)
Invalidate( SID_TITLE_MASTERPAGE );
Invalidate( SID_NOTES_MASTERPAGE );
Invalidate( SID_HANDOUT_MASTERPAGE );
+ InvalidateWindows();
SetContextName(GetSidebarContextName());
}
diff --git a/sd/source/ui/view/drviews5.cxx b/sd/source/ui/view/drviews5.cxx
index 1c34b17..f0f9719 100644
--- a/sd/source/ui/view/drviews5.cxx
+++ b/sd/source/ui/view/drviews5.cxx
@@ -406,19 +406,13 @@ void DrawViewShell::PrePaint()
*/
void DrawViewShell::Paint(const Rectangle& rRect, ::sd::Window* pWin)
{
- // Fill var FillColor here to have it available on later call
- svtools::ColorConfig aColorConfig;
- Color aFillColor;
-
- aFillColor = Color( aColorConfig.GetColorValue( svtools::APPBACKGROUND ).nColor );
-
/* This is done before each text edit, so why not do it before every paint.
The default language is only used if the outliner only contains one
character in a symbol font */
GetDoc()->GetDrawOutliner( NULL ).SetDefaultLanguage( GetDoc()->GetLanguage( EE_CHAR_LANGUAGE ) );
// Set Application Background color for usage in SdrPaintView(s)
- mpDrawView->SetApplicationBackgroundColor(aFillColor);
+ mpDrawView->SetApplicationBackgroundColor(GetAppBackgroundColor());
/* This is done before each text edit, so why not do it before every paint.
The default language is only used if the outliner only contains one
diff --git a/sd/source/ui/view/drviewsa.cxx b/sd/source/ui/view/drviewsa.cxx
index 6385349..a1b332e 100644
--- a/sd/source/ui/view/drviewsa.cxx
+++ b/sd/source/ui/view/drviewsa.cxx
@@ -209,6 +209,9 @@ void DrawViewShell::Construct(DrawDocShell* pDocSh, PageKind eInitialPageKind)
mbPastePossible = false;
mbIsLayerModeActive = false;
+ svtools::ColorConfig aColorConfig;
+ mnAppBackgroundColor = Color( aColorConfig.GetColorValue( svtools::APPBACKGROUND ).nColor );
+
mpFrameView->Connect();
OSL_ASSERT (GetViewShell()!=NULL);
commit af8143bc40cf2cfbc12e77c9bb7de01b655f7b30
Author: Matthew J. Francis <mjay.francis at gmail.com>
Date: Mon Jun 1 18:34:04 2015 +0800
Make PyUNO provide more Pythonic behaviour
- Simplifies working with UNO objects by giving the behaviour of
Python lists, dicts and iterators to objects which implement UNO
container interfaces
- Applies a custom behaviour to allow objects which implement
com::sun::star::table::XCellRange to yield cells and cell ranges by
subscript
- When UNO container objects are addressed in the new style,
eliminates the requirement to manually construct Any objects for
contained elements which are typed sequences
- Allows lists and iterators to be passed wherever a UNO method
accepts a sequence
- Relaxes the requirements for initialising UNO structs to allow
some members to be skipped when all initialisers are passed by name
1. Collection interfaces
========================
Objects which implement core UNO collection interfaces are made to
behave in a way that is more natural for Python code.
com::sun::star::container::XIndexAccess
com::sun::star::container::XIndexReplace
com::sun::star::container::XIndexContainer
- Objects provide Python list access semantics
num = len(obj) # Number of elements
val = obj[0] # Access by index
val1,val2 = obj[2:4] # Access by slice
val1,val2 = obj[0:3:2] # Access by extended slice
if val in obj: ... # Test value presence
for val in obj: ... # Implicit iterator (values)
itr = iter(obj) # Named iterator (values)
obj[0] = val # Replace by index
obj[2:4] = val1,val2 # Replace by slice
obj[0:3:2] = val1,val2 # Replace by extended slice
obj[2:3] = val1,val2 # Insert/replace by slice
obj[2:2] = (val,) # Insert by slice
obj[2:4] = (val,) # Replace/delete by slice
obj[2:3] = () # Delete by slice (implicit)
del obj[0] # Delete by index
del obj[2:4] # Delete by slice
com::sun::star::container::XNameAccess
com::sun::star::container::XNameReplace
com::sun::star::container::XNameContainer
- Objects provide Python dict access semantics
num = len(obj) # Number of keys
val = obj[key] # Access by key
if key in obj: ... # Test key presence
for key in obj: ... # Implicit iterator (keys)
itr = iter(obj) # Named iterator (keys)
obj[key] = val # Replace by key
obj[key] = val # Insert by key
del obj[key] # Delete by key
com::sun::star::container::XEnumerationAccess
- Objects provide Python iterable semantics
for val in obj: ... # Implicit iterator
itr = iter(obj) # Named iterator
com::sun::star::container::XEnumeration
- Objects provide Python iterator semantics
for val in itr: ... # Iteration of named iterator
if val in itr: ... # Test value presence
Objects which implement both XIndex* and XName* are supported, and
respond to both integer and string keys. However, iterating over
such an object will return the keys (like a Python dict) rather than
the values (like a Python list).
2. Cell ranges
==============
A custom behaviour is applied to objects which implement
com::sun::star::table::XCellRange to allow their cells and cell
ranges to be addressed by subscript, in the style of a Python list
or dict (read-only). This is applicable to Calc spreadsheet sheets,
Writer text tables and cell ranges created upon these.
cell = cellrange[0,0] # Access cell by indices
rng = cellrange[0,1:2] # Access cell range by index,slice
rng = cellrange[1:2,0] # Access cell range by slice,index
rng = cellrange[0:1,2:3] # Access cell range by slices
rng = cellrange['A1:B2'] # Access cell range by descriptor
rng = cellrange['Name'] # Access cell range by name
Note that the indices used are in Python/C order, and differ from
the arguments to methods provided by XCellRange.
- The statement cellrange[r,c], which returns the cell from row r
and column c, is equivalent to calling
XCellRange::getCellByPosition(c,r)
- The statement cellrange[t:b,l:r], which returns a cell range
covering rows t to b(non-inclusive) and columns l to r(non-
inclusive), is equivalent to calling
XCellRange::getCellRangeByPosition(l,t,r-1,b-1).
In contrast to the handling of objects implementing XIndex*,
extended slice syntax is not supported. Negative indices (from-end
addresses) are supported only for objects which also implement
com::sun::star::table::XColumnRowRange (currently Calc spreadsheet
sheets and cell ranges created upon these). For such objects, the
following syntax is also available:
rng = cellrange[0] # Access cell range by row index
rng = cellrange[0,:] # Access cell range by row index
rng = cellrange[:,0] # Access cell range by column index
3. Elimination of explicit Any
==============================
PyUNO has not previously been able to cope with certain method
arguments which are typed as Any but require a sequence of specific
type to be passed. This is a particular issue for container
interfaces such as XIndexContainer and XNameContainer.
The existing solution to dealing with such methods is to use a
special method to pass an explicitly typed Any, giving code such as:
index = doc.createInstance("com.sun.star.text.ContentIndex");
...
uno.invoke( index.LevelParagraphStyles , "replaceByIndex",
(0, uno.Any("[]string", ('Caption',))) )
The new Pythonic container access is able to correctly infer the
expected type of the sequences required by these arguments. In the
new style, the above call to .replaceByIndex() can instead be
written:
index.LevelParagraphStyles[0] = ('Caption',)
4. List and iterator arguments
==============================
Wherever a UNO API expects a sequence, a Python list or iterator can
now be passed. This enables the use of list comprehensions and
generator expressions for method calls and property assignments.
Example:
tbl = doc.createInstance('com.sun.star.text.TextTable')
tbl.initialize(10,10)
# ... insert table ...
# Assign numbers 0..99 to the cells using a generator expression
tbl.Data = ((y for y in range(10*x,10*x + 10)) for x in range(10))
5. Tolerant struct initialisation
=================================
Previously, a UNO struct could be created fully uninitialised, or by
passing a combination of positional and/or named arguments to its
constructor. However, if any arguments were passed, all members were
required to be initialised or an exception was thrown.
This requirement is relaxed such that when all arguments passed to a
struct constructor are by name, some may be omitted. The existing
requirement that all members must be explicitly initialised when
some constructor arguments are unnamed (positional) is not affected.
Example:
from com.sun.star.beans import PropertyValue
prop = PropertyValue(Name='foo', Value='bar')
Change-Id: Id29bff10a18099b1a00af1abee1a6c1bc58b3978
Reviewed-on: https://gerrit.libreoffice.org/16272
Tested-by: Jenkins <ci at libreoffice.org>
Reviewed-by: Matthew Francis <mjay.francis at gmail.com>
diff --git a/pyuno/Library_pyuno.mk b/pyuno/Library_pyuno.mk
index 013765d..3bf08cc 100644
--- a/pyuno/Library_pyuno.mk
+++ b/pyuno/Library_pyuno.mk
@@ -45,6 +45,7 @@ $(eval $(call gb_Library_add_exception_objects,pyuno,\
pyuno/source/module/pyuno_except \
pyuno/source/module/pyuno_adapter \
pyuno/source/module/pyuno_gc \
+ pyuno/source/module/pyuno_iterator \
))
# vim:set noet sw=4 ts=4:
diff --git a/pyuno/Module_pyuno.mk b/pyuno/Module_pyuno.mk
index ac09d98..4179a73 100644
--- a/pyuno/Module_pyuno.mk
+++ b/pyuno/Module_pyuno.mk
@@ -71,6 +71,7 @@ endif
ifneq (,$(filter PythonTest_pytests,$(MAKECMDGOALS)))
$(eval $(call gb_Module_add_targets,pyuno, \
PythonTest_pytests \
+ PythonTest_pyuno_pytests_testcollections \
PythonTest_pyuno_pytests_insertremovecells \
))
endif
diff --git a/pyuno/PythonTest_pytests.mk b/pyuno/PythonTest_pytests.mk
index 177195f..71255b6 100644
--- a/pyuno/PythonTest_pytests.mk
+++ b/pyuno/PythonTest_pytests.mk
@@ -24,6 +24,7 @@
$(eval $(call gb_PythonTest_PythonTest,pytests))
$(call gb_PythonTest_get_target,pytests) : \
+ $(call gb_PythonTest_get_target,pyuno_pytests_testcollections) \
$(call gb_PythonTest_get_target,pyuno_pytests_insertremovecells) \
$(call gb_PythonTest_get_target,pyuno_pytests_ssl) \
diff --git a/pyuno/PythonTest_pyuno_pytests_testcollections.mk b/pyuno/PythonTest_pyuno_pytests_testcollections.mk
new file mode 100644
index 0000000..ba8fe2e
--- /dev/null
+++ b/pyuno/PythonTest_pyuno_pytests_testcollections.mk
@@ -0,0 +1,26 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_PythonTest_PythonTest,pyuno_pytests_testcollections))
+
+$(eval $(call gb_PythonTest_add_modules,pyuno_pytests_testcollections,$(SRCDIR)/pyuno/qa/pytests,\
+ testcollections_XIndexAccess \
+ testcollections_XIndexReplace \
+ testcollections_XIndexContainer \
+ testcollections_XNameAccess \
+ testcollections_XNameReplace \
+ testcollections_XNameContainer \
+ testcollections_XEnumerationAccess \
+ testcollections_XEnumeration \
+ testcollections_XCellRange \
+ testcollections_mixednameindex \
+ testcollections_misc \
+))
+
+# vim: set noet sw=4 ts=4:
diff --git a/pyuno/inc/pyuno/pyuno.hxx b/pyuno/inc/pyuno/pyuno.hxx
index c83beb9..825fa93 100644
--- a/pyuno/inc/pyuno/pyuno.hxx
+++ b/pyuno/inc/pyuno/pyuno.hxx
@@ -171,6 +171,12 @@ enum ConversionMode { ACCEPT_UNO_ANY, REJECT_UNO_ANY };
class LO_DLLPUBLIC_PYUNO Runtime
{
RuntimeImpl *impl;
+
+ /**
+ Safely unpacks a Python iterator into a sequence, then
+ stores it in an Any. Used internally by pyObject2Any
+ */
+ bool pyIterUnpack( PyObject *const, com::sun::star::uno::Any & ) const;
public:
~Runtime( );
diff --git a/pyuno/qa/pytests/testcollections_XCellRange.py b/pyuno/qa/pytests/testcollections_XCellRange.py
new file mode 100644
index 0000000..ad8819b
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XCellRange.py
@@ -0,0 +1,365 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+from com.sun.star.table import CellAddress
+
+
+# Tests behaviour of objects implementing XCellRange using the new-style
+# collection accessors
+
+class TestXCellRange(CollectionsTestBase):
+
+ # TODO negative indices
+
+ # Tests syntax:
+ # cell = cellrange[0,0] # Access cell by indices
+ # For:
+ # Spreadsheet
+ # Cell at Row 0, Col 0
+ def test_XCellRange_Spreadsheet_Cell_00(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ cell = sht[0,0]
+
+ # Then
+ self.assertEqual(0, cell.CellAddress.Sheet)
+ self.assertEqual(0, cell.CellAddress.Row)
+ self.assertEqual(0, cell.CellAddress.Column)
+
+ # Tests syntax:
+ # cell = cellrange[0,0] # Access cell by indices
+ # For:
+ # Text table
+ # Cell at Row 0, Col 0
+ def test_XCellRange_Table_Cell_00(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance('com.sun.star.text.TextTable')
+ textTable.initialize(10,10)
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+ tbl = doc.TextTables.getByIndex(0)
+
+ # When
+ cell = tbl[0,0]
+
+ # Then
+ self.assertEqual('A1', cell.CellName)
+
+ # Tests syntax:
+ # cell = cellrange[0,0] # Access cell by indices
+ # For:
+ # Spreadsheet
+ # Cell at Row 3, Col 7
+ def test_XCellRange_Spreadsheet_Cell_37(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[3,7]
+
+ # Then
+ self.assertEqual(0, rng.CellAddress.Sheet)
+ self.assertEqual(3, rng.CellAddress.Row)
+ self.assertEqual(7, rng.CellAddress.Column)
+
+ # Tests syntax:
+ # cell = cellrange[0,0] # Access cell by indices
+ # For:
+ # Text table
+ # Cell at Row 3, Col 7
+ def test_XCellRange_Table_Cell_37(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance('com.sun.star.text.TextTable')
+ textTable.initialize(10,10)
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+ tbl = doc.TextTables.getByIndex(0)
+
+ # When
+ cell = tbl[3,7]
+
+ # Then
+ self.assertEqual('H4', cell.CellName)
+
+ # Tests syntax:
+ # rng = cellrange[0,1:2] # Access cell range by index,slice
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_Index_Slice(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[0,1:3]
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(0, rng.RangeAddress.StartRow)
+ self.assertEqual(1, rng.RangeAddress.StartColumn)
+ self.assertEqual(0, rng.RangeAddress.EndRow)
+ self.assertEqual(2, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange[0,1:2] # Access cell range by index,slice
+ # For:
+ # Text table
+ def test_XCellRange_Table_Range_Index_Slice(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance('com.sun.star.text.TextTable')
+ textTable.initialize(10,10)
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+ tbl = doc.TextTables.getByIndex(0)
+ doc.lockControllers()
+ tbl.DataArray = tuple(tuple(str(100 + y) for y in range(10*x,10*x + 10)) for x in range(10))
+ doc.unlockControllers()
+
+ # When
+ rng = tbl[0,1:3]
+
+ # Then
+ self.assertEqual((('101', '102'),), rng.DataArray)
+
+ # Tests syntax:
+ # rng = cellrange[1:2,0] # Access cell range by slice,index
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_Slice_Index(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[1:3,0]
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(1, rng.RangeAddress.StartRow)
+ self.assertEqual(0, rng.RangeAddress.StartColumn)
+ self.assertEqual(2, rng.RangeAddress.EndRow)
+ self.assertEqual(0, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange[1:2,0] # Access cell range by index,slice
+ # For:
+ # Text table
+ def test_XCellRange_Table_Range_Slice_Index(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance('com.sun.star.text.TextTable')
+ textTable.initialize(10,10)
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+ tbl = doc.TextTables.getByIndex(0)
+ doc.lockControllers()
+ tbl.DataArray = tuple(tuple(str(100 + y) for y in range(10*x,10*x + 10)) for x in range(10))
+ doc.unlockControllers()
+
+ # When
+ rng = tbl[1:3,0]
+
+ # Then
+ self.assertEqual((('110',), ('120',)), rng.DataArray)
+
+ # Tests syntax:
+ # rng = cellrange[0:1,2:3] # Access cell range by slices
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_Slices(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[1:3,3:5]
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(1, rng.RangeAddress.StartRow)
+ self.assertEqual(3, rng.RangeAddress.StartColumn)
+ self.assertEqual(2, rng.RangeAddress.EndRow)
+ self.assertEqual(4, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange[0:1,2:3] # Access cell range by slices
+ # For:
+ # Spreadsheet
+ # Zero rows/columns
+ def test_XCellRange_Spreadsheet_Range_Slices_Invalid(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When / Then
+ with self.assertRaises(KeyError):
+ rng = sht[1:1,3:5]
+ with self.assertRaises(KeyError):
+ rng = sht[1:3,3:3]
+
+ # Tests syntax:
+ # rng = cellrange[0:1,2:3] # Access cell range by slices
+ # For:
+ # Text table
+ def test_XCellRange_Table_Range_Slices(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance('com.sun.star.text.TextTable')
+ textTable.initialize(10,10)
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+ tbl = doc.TextTables.getByIndex(0)
+ doc.lockControllers()
+ tbl.DataArray = tuple(tuple(str(100 + y) for y in range(10*x,10*x + 10)) for x in range(10))
+ doc.unlockControllers()
+
+ # When
+ rng = tbl[1:3,3:5]
+
+ # Then
+ self.assertEqual((('113', '114'), ('123', '124')), rng.DataArray)
+
+
+ # Tests syntax:
+ # rng = cellrange['A1:B2'] # Access cell range by descriptor
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_Descriptor(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht['A3:B4']
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(2, rng.RangeAddress.StartRow)
+ self.assertEqual(0, rng.RangeAddress.StartColumn)
+ self.assertEqual(3, rng.RangeAddress.EndRow)
+ self.assertEqual(1, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange['A1:B2'] # Access cell range by descriptor
+ # For:
+ # Table
+ def test_XCellRange_Table_Range_Descriptor(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance('com.sun.star.text.TextTable')
+ textTable.initialize(10,10)
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+ tbl = doc.TextTables.getByIndex(0)
+ doc.lockControllers()
+ tbl.DataArray = tuple(tuple(str(100 + y) for y in range(10*x,10*x + 10)) for x in range(10))
+ doc.unlockControllers()
+
+ # When
+ rng = tbl['A3:B4']
+
+ # Then
+ self.assertEqual((('120', '121'), ('130', '131')), rng.DataArray)
+
+ # Tests syntax:
+ # rng = cellrange['Name'] # Access cell range by name
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_Name(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+ expr = '$' + sht.Name + '.$C2:F10'
+ addr = CellAddress(Sheet=0,Row=1,Column=2)
+ sht.NamedRanges.addNewByName('foo', expr, addr, 0)
+
+ # When
+ rng = sht['foo']
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(1, rng.RangeAddress.StartRow)
+ self.assertEqual(2, rng.RangeAddress.StartColumn)
+ self.assertEqual(9, rng.RangeAddress.EndRow)
+ self.assertEqual(5, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange[0] # Access cell range by row index
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_RowIndex(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[0]
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(0, rng.RangeAddress.StartRow)
+ self.assertEqual(0, rng.RangeAddress.StartColumn)
+ self.assertEqual(0, rng.RangeAddress.EndRow)
+ self.assertEqual(1023, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange[0,:] # Access cell range by row index
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_RowIndex_FullSlice(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[0,:]
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(0, rng.RangeAddress.StartRow)
+ self.assertEqual(0, rng.RangeAddress.StartColumn)
+ self.assertEqual(0, rng.RangeAddress.EndRow)
+ self.assertEqual(1023, rng.RangeAddress.EndColumn)
+
+ # Tests syntax:
+ # rng = cellrange[:,0] # Access cell range by column index
+ # For:
+ # Spreadsheet
+ def test_XCellRange_Spreadsheet_Range_FullSlice_ColumnIndex(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ sht = spr.Sheets.getByIndex(0)
+
+ # When
+ rng = sht[:,0]
+
+ # Then
+ self.assertEqual(0, rng.RangeAddress.Sheet)
+ self.assertEqual(0, rng.RangeAddress.StartRow)
+ self.assertEqual(0, rng.RangeAddress.StartColumn)
+ self.assertEqual(1048575, rng.RangeAddress.EndRow)
+ self.assertEqual(0, rng.RangeAddress.EndColumn)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XEnumeration.py b/pyuno/qa/pytests/testcollections_XEnumeration.py
new file mode 100644
index 0000000..9be1a60
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XEnumeration.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XEnumeration using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXEnumeration(CollectionsTestBase):
+
+ # Tests syntax:
+ # for val in itr: ... # Iteration of named iterator
+ # For:
+ # 1 element
+ def test_XEnumeration_ForIn(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ paragraphs = []
+ itr = iter(doc.Text.createEnumeration())
+ for para in itr:
+ paragraphs.append(para)
+
+ # Then
+ self.assertEqual(1, len(paragraphs))
+
+ # Tests syntax:
+ # if val in itr: ... # Test value presence
+ # For:
+ # Present value
+ def test_XEnumeration_IfIn_Present(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ paragraph = doc.Text.createEnumeration().nextElement()
+ itr = iter(doc.Text.createEnumeration())
+ result = paragraph in itr
+
+ # Then
+ self.assertTrue(result)
+
+ # Tests syntax:
+ # if val in itr: ... # Test value presence
+ # For:
+ # Absent value
+ def test_XEnumeration_IfIn_Absent(self):
+ # Given
+ doc1 = self.createBlankTextDocument()
+ doc2 = self.createBlankTextDocument()
+
+ # When
+ paragraph = doc2.Text.createEnumeration().nextElement()
+ itr = iter(doc1.Text.createEnumeration())
+ result = paragraph in itr
+
+ # Then
+ self.assertFalse(result)
+
+ # Tests syntax:
+ # if val in itr: ... # Test value presence
+ # For:
+ # None
+ def test_XEnumeration_IfIn_None(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ itr = iter(doc.Text.createEnumeration())
+ result = None in itr
+
+ # Then
+ self.assertFalse(result)
+
+ # Tests syntax:
+ # if val in itr: ... # Test value presence
+ # For:
+ # Invalid value (string)
+ # Note: Ideally this would raise TypeError in the same manner as for
+ # XEnumerationAccess, but an XEnumeration doesn't know the type of its
+ # values
+ def test_XEnumeration_IfIn_String(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ itr = iter(doc.Text.createEnumeration())
+ result = 'foo' in itr
+
+ # Then
+ self.assertFalse(result)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XEnumerationAccess.py b/pyuno/qa/pytests/testcollections_XEnumerationAccess.py
new file mode 100644
index 0000000..1ad7a08
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XEnumerationAccess.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XEnumerationAccess using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXEnumerationAccess(CollectionsTestBase):
+
+ # Tests syntax:
+ # for val in obj: ... # Implicit iterator
+ # For:
+ # 1 element
+ def test_XEnumerationAccess_ForIn(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ paragraphs = []
+ for para in doc.Text:
+ paragraphs.append(para)
+
+ # Then
+ self.assertEqual(1, len(paragraphs))
+
+ # Tests syntax:
+ # itr = iter(obj) # Named iterator
+ # For:
+ # 1 element
+ def test_XEnumerationAccess_Iter(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ itr = iter(doc.Text)
+
+ # Then
+ self.assertIsNotNone(next(itr))
+ with self.assertRaises(StopIteration):
+ next(itr)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Present value
+ def test_XEnumerationAccess_IfIn_Present(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ paragraph = doc.Text.createEnumeration().nextElement()
+ result = paragraph in doc.Text
+
+ # Then
+ self.assertTrue(result)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Absent value
+ def test_XEnumerationAccess_IfIn_Absent(self):
+ # Given
+ doc1 = self.createBlankTextDocument()
+ doc2 = self.createBlankTextDocument()
+
+ # When
+ paragraph = doc2.Text.createEnumeration().nextElement()
+ result = paragraph in doc1.Text
+
+ # Then
+ self.assertFalse(result)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # None
+ def test_XEnumerationAccess_IfIn_None(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ result = None in doc.Text
+
+ # Then
+ self.assertFalse(result)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Invalid value (string)
+ def test_XEnumerationAccess_IfIn_String(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ result = 'foo' in doc.Text
+
+ # Then
+ self.assertFalse(result)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Invalid value (dict)
+ def test_XEnumerationAccess_IfIn_String(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ result = {} in doc.Text
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XIndexAccess.py b/pyuno/qa/pytests/testcollections_XIndexAccess.py
new file mode 100644
index 0000000..753373b
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XIndexAccess.py
@@ -0,0 +1,299 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from inspect import isclass
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XIndexAccess using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXIndexAccess(CollectionsTestBase):
+
+ def insertTestFootnotes(self, doc, count):
+ cursor = doc.Text.createTextCursor()
+ for i in range(count):
+ footnote = doc.createInstance("com.sun.star.text.Footnote")
+ footnote.Label = 'n'+str(i)
+ doc.Text.insertTextContent(cursor, footnote, 0)
+
+ def readValuesTestFixture(self, doc, count, key, expected):
+ # Given
+ doc.Text.setString('')
+ self.insertTestFootnotes(doc, count)
+
+ # When
+ captured = None
+ try:
+ actual = doc.Footnotes[key]
+ except Exception as e:
+ captured = e
+
+ # Then
+ if isclass(expected) and issubclass(expected, Exception):
+ # expected is exception
+ self.assertNotEqual(None, captured)
+ self.assertEqual(expected.__name__, type(captured).__name__)
+ elif type(expected) is tuple:
+ # expected is tuple
+ self.assertEqual(None, captured)
+ self.assertTrue(type(actual) is tuple)
+ self.assertEqual(len(expected), len(actual))
+ for i in range(len(expected)):
+ self.assertEqual('n'+str(expected[i]), actual[i].Label)
+ else:
+ # expected is value
+ self.assertEqual(None, captured)
+ self.assertTrue(type(actual) is not tuple)
+ self.assertEqual('n'+str(expected), actual.Label)
+
+ # Tests syntax:
+ # num = len(obj) # Number of elements
+ # For:
+ # length = 0
+ def test_XIndexAccess_Len_0(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ count = len(doc.Footnotes)
+
+ # Then
+ self.assertEqual(0, count)
+
+ # Tests syntax:
+ # num = len(obj) # Number of elements
+ # For:
+ # length = 1
+ def test_XIndexAccess_Len_1(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ cursor = doc.Text.createTextCursor()
+ footnote = doc.createInstance("com.sun.star.text.Footnote")
+ doc.Text.insertTextContent(cursor, footnote, 0)
+
+ # When
+ count = len(doc.Footnotes)
+
+ # Then
+ self.assertEqual(1, count)
+
+ # Tests syntax:
+ # val = obj[0] # Access by index
+ # For:
+ # Single indices
+ def test_XIndexAccess_ReadIndex_Single(self):
+ doc = self.createBlankTextDocument()
+ self.readValuesTestFixture(doc, 0, -1, IndexError)
+ self.readValuesTestFixture(doc, 0, 0, IndexError)
+ self.readValuesTestFixture(doc, 0, 1, IndexError)
+ self.readValuesTestFixture(doc, 1, -3, IndexError)
+ self.readValuesTestFixture(doc, 1, -2, IndexError)
+ self.readValuesTestFixture(doc, 1, -1, 0)
+ self.readValuesTestFixture(doc, 1, 0, 0)
+ self.readValuesTestFixture(doc, 1, 1, IndexError)
+ self.readValuesTestFixture(doc, 1, 2, IndexError)
+ self.readValuesTestFixture(doc, 2, -4, IndexError)
+ self.readValuesTestFixture(doc, 2, -3, IndexError)
+ self.readValuesTestFixture(doc, 2, -2, 0)
+ self.readValuesTestFixture(doc, 2, -1, 1)
+ self.readValuesTestFixture(doc, 2, 0, 0)
+ self.readValuesTestFixture(doc, 2, 1, 1)
+ self.readValuesTestFixture(doc, 2, 2, IndexError)
+ self.readValuesTestFixture(doc, 2, 3, IndexError)
+
+ def test_XIndexAccess_ReadIndex_Single_Invalid(self):
+ doc = self.createBlankTextDocument()
+ self.readValuesTestFixture(doc, 0, None, TypeError)
+ self.readValuesTestFixture(doc, 0, 'foo', TypeError)
+ self.readValuesTestFixture(doc, 0, 12.34, TypeError)
+ self.readValuesTestFixture(doc, 0, (0,1), TypeError)
+ self.readValuesTestFixture(doc, 0, [0,1], TypeError)
+ self.readValuesTestFixture(doc, 0, {'a': 'b'}, TypeError)
+
+ # Tests syntax:
+ # val1,val2 = obj[2:4] # Access by slice
+ def test_XIndexAccess_ReadSlice(self):
+ doc = self.createBlankTextDocument()
+ testMax = 4
+ for i in range(testMax):
+ t = tuple(range(i))
+ for j in [x for x in range(-testMax-2,testMax+3)] + [None]:
+ for k in [x for x in range(-testMax-2,testMax+3)] + [None]:
+ key = slice(j,k)
+ expected = t[key]
+ self.readValuesTestFixture(doc, i, key, expected)
+
+ # Tests syntax:
+ # val1,val2 = obj[0:3:2] # Access by extended slice
+ def test_XIndexAccess_ReadExtendedSlice(self):
+ doc = self.createBlankTextDocument()
+ testMax = 4
+ for i in range(testMax):
+ t = tuple(range(i))
+ for j in [x for x in range(-testMax-2,testMax+3)] + [None]:
+ for k in [x for x in range(-testMax-2,testMax+3)] + [None]:
+ for l in [-2,-1,2]:
+ key = slice(j,k,l)
+ expected = t[key]
+ self.readValuesTestFixture(doc, i, key, expected)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Present element
+ def test_XIndexAccess_In_Present(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ cursor = doc.Text.createTextCursor()
+ footnote = doc.createInstance("com.sun.star.text.Footnote")
+ footnote.setLabel('foo')
+ doc.Text.insertTextContent(cursor, footnote, 0)
+ footnote = doc.Footnotes.getByIndex(0);
+
+ # When
+ present = footnote in doc.Footnotes
+
+ # Then
+ self.assertTrue(present)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # None
+ def test_XIndexAccess_In_None(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ present = None in doc.Footnotes
+
+ # Then
+ self.assertFalse(present)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Absent element (string)
+ def test_XIndexAccess_In_String(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ present = "foo" in doc.Footnotes
+
+ # Then
+ self.assertFalse(present)
+
+ # Tests syntax:
+ # if val in obj: ... # Test value presence
+ # For:
+ # Absent element (dict)
+ def test_XIndexAccess_In_Dict(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ present = {} in doc.Footnotes
+
+ # Tests syntax:
+ # for val in obj: ... # Implicit iterator (values)
+ # For:
+ # 0 elements
+ def test_XIndexAccess_ForIn_0(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When
+ readFootnotes = []
+ for f in doc.Footnotes:
+ readFootnotes.append(f)
+
+ # Then
+ self.assertEqual(0, len(readFootnotes))
+
+ # Tests syntax:
+ # for val in obj: ... # Implicit iterator (values)
+ # For:
+ # 1 element
+ def test_XIndexAccess_ForIn_1(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ cursor = doc.Text.createTextCursor()
+ footnote = doc.createInstance("com.sun.star.text.Footnote")
+ footnote.setLabel('foo')
+ doc.Text.insertTextContent(cursor, footnote, 0)
+
+ # When
+ readFootnotes = []
+ for f in doc.Footnotes:
+ readFootnotes.append(f)
+
+ # Then
+ self.assertEqual(1, len(readFootnotes))
+ self.assertEqual('foo', readFootnotes[0].Label)
+
+ # Tests syntax:
+ # for val in obj: ... # Implicit iterator (values)
+ # For:
+ # 2 elements
+ def test_XIndexAccess_ForIn_2(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ cursor = doc.Text.createTextCursor()
+ footnote1 = doc.createInstance("com.sun.star.text.Footnote")
+ footnote2 = doc.createInstance("com.sun.star.text.Footnote")
+ footnote1.setLabel('foo')
+ footnote2.setLabel('bar')
+ doc.Text.insertTextContent(cursor, footnote1, 0)
+ doc.Text.insertTextContent(cursor, footnote2, 0)
+
+ # When
+ readFootnotes = []
+ for f in doc.Footnotes:
+ readFootnotes.append(f)
+
+ # Then
+ self.assertEqual(2, len(readFootnotes))
+ self.assertEqual('foo', readFootnotes[0].Label)
+ self.assertEqual('bar', readFootnotes[1].Label)
+
+ # Tests syntax:
+ # itr = iter(obj) # Named iterator (values)
+ # For:
+ # 1 element
+ def test_XIndexAccess_Iter_0(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ cursor = doc.Text.createTextCursor()
+ footnote = doc.createInstance("com.sun.star.text.Footnote")
+ footnote.setLabel('foo')
+ doc.Text.insertTextContent(cursor, footnote, 0)
+
+ # When
+ itr = iter(doc.Footnotes)
+
+ # Then
+ self.assertIsNotNone(next(itr))
+ with self.assertRaises(StopIteration):
+ next(itr)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XIndexContainer.py b/pyuno/qa/pytests/testcollections_XIndexContainer.py
new file mode 100644
index 0000000..aad9b84
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XIndexContainer.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XIndexContainer using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXIndexContainer(CollectionsTestBase):
+
+ def generateTestPropertyValues(self, count):
+ sm = self.context.ServiceManager
+ values = sm.createInstanceWithContext("com.sun.star.document.IndexedPropertyValues", self.context)
+ for i in range(count):
+ properties = (PropertyValue(Name='n'+str(i), Value='v'+str(i)),)
+ uno.invoke (values, "insertByIndex", (i, uno.Any("[]com.sun.star.beans.PropertyValue", properties)))
+ return values
+
+ def generateTestTuple(self, values):
+ properties = []
+ for i in values:
+ properties.append((PropertyValue(Name='n'+str(i), Value='v'+str(i)),))
+ return tuple(properties)
+
+ def assignValuesTestFixture(self, count, key, values, expected):
+ # Given
+ propertyValues = self.generateTestPropertyValues(count)
+ if type(values) is list:
+ toAssign = self.generateTestTuple(values)
+ else:
+ toAssign = values
+ if not (isinstance(expected, Exception)):
+ toCompare = self.generateTestTuple(expected)
+
+ # When
+ captured = None
+ try:
+ propertyValues[key] = toAssign
+ except Exception as e:
+ captured = e
+
+ # Then
+ if isinstance(expected, Exception):
+ # expected is exception
+ self.assertNotEqual(None, captured)
+ self.assertEqual(type(expected).__name__, type(captured).__name__)
+ else:
+ # expected is list
+ self.assertEqual(None, captured)
+ self.assertEqual(len(expected), propertyValues.getCount())
+ for i in range(propertyValues.getCount()):
+ self.assertEqual(toCompare[i][0].Name, propertyValues.getByIndex(i)[0].Name)
+
+ def deleteValuesTestFixture(self, count, key, expected):
+ # Given
+ propertyValues = self.generateTestPropertyValues(count)
+ if not (isinstance(expected, Exception)):
+ toCompare = self.generateTestTuple(expected)
+
+ # When
+ captured = None
+ try:
+ del propertyValues[key]
+ except Exception as e:
+ captured = e
+
+ # Then
+ if isinstance(expected, Exception):
+ # expected is exception
+ self.assertNotEqual(None, captured)
+ self.assertEqual(type(expected).__name__, type(captured).__name__)
+ else:
+ # expected is list
+ self.assertEqual(None, captured)
+ self.assertEqual(len(expected), propertyValues.getCount())
+ for i in range(propertyValues.getCount()):
+ self.assertEqual(toCompare[i][0].Name, propertyValues.getByIndex(i)[0].Name)
+
+
+ # Tests syntax:
+ # obj[2:4] = val1,val2 # Replace by slice
+ # obj[2:3] = val1,val2 # Insert/replace by slice
+ # obj[2:2] = (val,) # Insert by slice
+ # obj[2:4] = (val,) # Replace/delete by slice
+ # obj[2:3] = () # Delete by slice (implicit)
+ # For:
+ # Cases requiring sequence type coercion
+ def test_XIndexContainer_AssignSlice(self):
+ baseMax = 5
+ assignMax = 5
+ for i in range(baseMax):
+ for j in [x for x in range(-baseMax-2,baseMax+3)] + [None]:
+ for k in [x for x in range(-baseMax-2,baseMax+3)] + [None]:
+ key = slice(j,k)
+ for l in range(assignMax):
+ assign = [y+100 for y in range(l)]
+ expected = list(range(i))
+ expected[key] = assign
+ self.assignValuesTestFixture(i, key, assign, expected)
+
+ # Tests syntax:
+ # obj[2:4] = val1,val2 # Replace by slice
+ # obj[2:3] = val1,val2 # Insert/replace by slice
+ # obj[2:2] = (val,) # Insert by slice
+ # For:
+ # Cases not requiring sequence type coercion
+ # Invalid values
+ def test_XIndexContainer_AssignSlice_Invalid(self):
+ self.assignValuesTestFixture(2, slice(0,2), None, TypeError())
+ self.assignValuesTestFixture(2, slice(0,2), 'foo', TypeError())
+ self.assignValuesTestFixture(2, slice(0,2), 12.34, TypeError())
+ self.assignValuesTestFixture(2, slice(0,2), {'a':'b'}, TypeError())
+ self.assignValuesTestFixture(2, slice(0,2), ('foo',), TypeError())
+ self.assignValuesTestFixture(2, slice(0,2), ('foo','foo'), TypeError())
+
+ # Tests syntax:
+ # obj[2:2] = (val,) # Insert by slice
+ # For:
+ # Cases not requiring sequence type coercion
+ def test_XIndexContainer_AssignSlice_NoCoercion(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ form = doc.createInstance("com.sun.star.form.component.DataForm")
+ form.Name = 'foo'
+
+ # When
+ doc.DrawPage.Forms[0:0] = (form,)
+
+ # Then
+ self.assertEqual('foo', doc.DrawPage.Forms[0].Name)
+
+ # Tests syntax:
+ # obj[0:3:2] = val1,val2 # Replace by extended slice
+ # For:
+ # Cases requiring sequence type coercion
+ def test_XIndexContainer_AssignExtendedSlice(self):
+ baseMax = 5
+ assignMax = 5
+ for i in range(baseMax):
+ for j in [x for x in range(-baseMax-2,baseMax+3)] + [None]:
+ for k in [x for x in range(-baseMax-2,baseMax+3)] + [None]:
+ for l in [-2,-1,1,2]:
+ key = slice(j,k,l)
+ for m in range(assignMax):
+ assign = [y+100 for y in range(m)]
+ expected = list(range(i))
+ try:
+ expected[key] = assign
+ except Exception as e:
+ expected = e
+ self.assignValuesTestFixture(i, key, assign, expected)
+
+ # Tests syntax:
+ # del obj[0] # Delete by index
+ def test_XIndexContainer_DelIndex(self):
+ baseMax = 5
+ for i in range(baseMax):
+ for j in [x for x in range(-baseMax-2,baseMax+3)]:
+ expected = list(range(i))
+ try:
+ del expected[j]
+ except Exception as e:
+ expected = e
+ self.deleteValuesTestFixture(i, j, expected)
+
+ # Tests syntax:
+ # del obj[2:4] # Delete by slice
+ def test_XIndexContainer_DelSlice(self):
+ baseMax = 5
+ for i in range(baseMax):
+ for j in [x for x in range(-baseMax-2,baseMax+3)] + [None]:
+ for k in [x for x in range(-baseMax-2,baseMax+3)] + [None]:
+ key = slice(j,k)
+ expected = list(range(i))
+ try:
+ del expected[key]
+ except Exception as e:
+ expected = e
+ self.deleteValuesTestFixture(i, key, expected)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XIndexReplace.py b/pyuno/qa/pytests/testcollections_XIndexReplace.py
new file mode 100644
index 0000000..b8e0da5
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XIndexReplace.py
@@ -0,0 +1,219 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XIndexReplace using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXIndexReplace(CollectionsTestBase):
+
+ def generateTestContentIndex(self, doc):
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+ for i in range(10):
+ styles = ('n'+str(i),)
+ uno.invoke (index.LevelParagraphStyles, "replaceByIndex", (i, uno.Any("[]string", styles)))
+ return index
+
+ def generateTestTuple(self, values):
+ properties = []
+ for i in values:
+ properties.append(('n'+str(i),),)
+ return tuple(properties)
+
+ def assignValuesTestFixture(self, doc, key, values, expected):
+ # Given
+ index = self.generateTestContentIndex(doc)
+ toAssign = self.generateTestTuple(values)
+ if not (isinstance(expected, Exception)):
+ toCompare = self.generateTestTuple(expected)
+
+ # When
+ captured = None
+ try:
+ index.LevelParagraphStyles[key] = toAssign
+ except Exception as e:
+ captured = e
+
+ # Then
+ if isinstance(expected, Exception):
+ # expected is exception
+ self.assertNotEqual(None, captured)
+ self.assertEqual(type(expected).__name__, type(captured).__name__)
+ else:
+ # expected is list
+ self.assertEqual(None, captured)
+ for i in range(10):
+ self.assertEqual(toCompare[i][0], index.LevelParagraphStyles.getByIndex(i)[0])
+
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Cases requiring sequence type coercion
+ def test_XIndexReplace_ReplaceIndex(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When
+ index.LevelParagraphStyles[0] = ('Caption',)
+
+ # Then
+ self.assertEqual(('Caption',), index.LevelParagraphStyles[0])
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Invalid value (None)
+ def test_XIndexReplace_ReplaceIndex_Invalid_None(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0] = None
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Invalid value (String)
+ def test_XIndexReplace_ReplaceIndex_Invalid_String(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0] = 'foo'
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Invalid value (Float)
+ def test_XIndexReplace_ReplaceIndex_Invalid_Float(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0] = 12.34
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Invalid value (List)
+ def test_XIndexReplace_ReplaceIndex_Invalid_List(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0] = [0,1]
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Invalid value (Dict)
+ def test_XIndexReplace_ReplaceIndex_Invalid_Dict(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0] = {'a': 'b'}
+
+ # Tests syntax:
+ # obj[0] = val # Replace by index
+ # For:
+ # Invalid value (inconsistently typed tuple)
+ def test_XIndexReplace_ReplaceIndex_Invalid_InconsistentTuple(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0] = ('Caption', ())
+
+ # Tests syntax:
+ # obj[2:4] = val1,val2 # Replace by slice
+ # For:
+ # Cases requiring sequence type coercion
+ def test_XIndexReplace_ReplaceSlice(self):
+ assignMax = 12
+ doc = self.createBlankTextDocument()
+ t = tuple(range(10))
+ for j in [x for x in range(-12,13)] + [None]:
+ for k in [x for x in range(-12,13)] + [None]:
+ key = slice(j,k)
+ for l in range(assignMax):
+ assign = [y+100 for y in range(l)]
+ expected = list(range(10))
+ try:
+ expected[key] = assign
+ except Exception as e:
+ expected = e
+ if (len(expected) != 10):
+ expected = ValueError()
+ self.assignValuesTestFixture(doc, key, assign, expected)
+
+ # Tests syntax:
+ # obj[2:4] = val1,val2 # Replace by slice
+ # For:
+ # Invalid values (inconsistently value types in tuple)
+ def test_XIndexReplace_ReplaceSlice_Invalid_InconsistentTuple(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ index = doc.createInstance("com.sun.star.text.ContentIndex");
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ index.LevelParagraphStyles[0:2] = (
+ ('Caption',),
+ 12.34
+ )
+
+ # Tests syntax:
+ # obj[0:3:2] = val1,val2 # Replace by extended slice
+ # For:
+ # Cases requiring sequence type coercion
+ def test_XIndexReplace_ReplaceExtendedSlice(self):
+ assignMax = 12
+ doc = self.createBlankTextDocument()
+ t = tuple(range(10))
+ for j in [x for x in range(-12,13)] + [None]:
+ for k in [x for x in range(-12,13)] + [None]:
+ for l in [-2,-1,2]:
+ key = slice(j,k,l)
+ for m in range(assignMax):
+ assign = [y+100 for y in range(m)]
+ expected = list(range(10))
+ try:
+ expected[key] = assign
+ except Exception as e:
+ expected = e
+ self.assignValuesTestFixture(doc, key, assign, expected)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XNameAccess.py b/pyuno/qa/pytests/testcollections_XNameAccess.py
new file mode 100644
index 0000000..f123641
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XNameAccess.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XNameAccess using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXNameAccess(CollectionsTestBase):
+
+ # Tests syntax:
+ # num = len(obj) # Number of keys
+ # For:
+ # 2 elements
+ def test_XNameAccess_Len(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When
+ length = len (drw.Links)
+
+ # Then
+ self.assertEqual(2, length)
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # 1/2 elements
+ def test_XNameAccess_ReadKey(self):
+ # Given
+ drw = self.createBlankDrawing()
+ drw.DrawPages.getByIndex(0).Name = 'foo'
+
+ # When
+ link = drw.Links['foo']
+
+ # Then
+ self.assertEqual('foo', link.getName())
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # Missing key
+ def test_XNameAccess_ReadKey_Missing(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When / Then
+ with self.assertRaises(KeyError):
+ link = drw.Links['foo']
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # Invalid key type (None)
+ def test_XNameAccess_ReadKey_Invalid_None(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ link = drw.Links[None]
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # Invalid key type (float)
+ def test_XNameAccess_ReadKey_Invalid_Float(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ link = drw.Links[12.34]
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # Invalid key type (tuple)
+ def test_XNameAccess_ReadKey_Invalid_Tuple(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ link = drw.Links[(1,2)]
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # Invalid key type (list)
+ def test_XNameAccess_ReadKey_Invalid_List(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ link = drw.Links[[1,2]]
+
+ # Tests syntax:
+ # val = obj[key] # Access by key
+ # For:
+ # Invalid key type (dict)
+ def test_XNameAccess_ReadKey_Invalid_Dict(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ link = drw.Links[{'a':'b'}]
+
+ # Tests syntax:
+ # if key in obj: ... # Test key presence
+ # For:
+ # 1/2 elements
+ def test_XNameAccess_In(self):
+ # Given
+ drw = self.createBlankDrawing()
+ drw.DrawPages.getByIndex(0).Name = 'foo'
+
+ # When
+ present = 'foo' in drw.Links
+
+ # Then
+ self.assertTrue(present)
+
+
+ # Tests syntax:
+ # for key in obj: ... # Implicit iterator (keys)
+ # For:
+ # 2 elements
+ def test_XNameAccess_ForIn(self):
+ # Given
+ drw = self.createBlankDrawing()
+ i = 0
+ for name in drw.Links.getElementNames():
+ drw.Links.getByName(name).Name = 'foo' + str(i)
+ i += 1
+
+ # When
+ readLinks = []
+ for link in drw.Links:
+ readLinks.append(link)
+
+ # Then
+ self.assertEqual(['foo0','foo1'], readLinks)
+
+ # Tests syntax:
+ # itr = iter(obj) # Named iterator (keys)
+ # For:
+ # 2 elements
+ def test_XNameAccess_Iter(self):
+ # Given
+ drw = self.createBlankDrawing()
+
+ # When
+ itr = iter(drw.Links)
+
+ # Then
+ self.assertIsNotNone(next(itr))
+ self.assertIsNotNone(next(itr))
+ with self.assertRaises(StopIteration):
+ next(itr)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XNameContainer.py b/pyuno/qa/pytests/testcollections_XNameContainer.py
new file mode 100644
index 0000000..80b6046
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XNameContainer.py
@@ -0,0 +1,116 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XNameContainer using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXNameContainer(CollectionsTestBase):
+
+ # Tests syntax:
+ # obj[key] = val # Insert by key
+ # For:
+ # 0->1 element
+ def test_XNameContainer_InsertName(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ ranges = spr.createInstance("com.sun.star.sheet.SheetCellRanges")
+ newRange = spr.Sheets.getByIndex(0).getCellRangeByPosition( 1, 2, 1, 2 )
+
+ # When
+ ranges['foo'] = newRange
+
+ # Then
+ self.assertEqual(1, len(ranges.ElementNames))
+
+ # Tests syntax:
+ # obj[key] = val # Insert by key
+ # For:
+ # Invalid key
+ def test_XNameContainer_InsertName_Invalid(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ ranges = spr.createInstance("com.sun.star.sheet.SheetCellRanges")
+ newRange = spr.Sheets.getByIndex(0).getCellRangeByPosition( 1, 2, 1, 2 )
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ ranges[12.34] = newRange
+
+ # Tests syntax:
+ # obj[key] = val # Replace by key
+ def test_XNameContainer_ReplaceName(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ ranges = spr.createInstance("com.sun.star.sheet.SheetCellRanges")
+ newRange1 = spr.Sheets.getByIndex(0).getCellRangeByPosition( 1, 2, 1, 2 )
+ newRange2 = spr.Sheets.getByIndex(0).getCellRangeByPosition( 6, 6, 6, 6 )
+
+ # When
+ ranges['foo'] = newRange1
+ ranges['foo'] = newRange2
+
+ # Then
+ self.assertEqual(1, len(ranges.ElementNames))
+ readRange = ranges['foo']
+ self.assertEqual(6, readRange.CellAddress.Column)
+
+ # Tests syntax:
+ # del obj[key] # Delete by key
+ # For:
+ # 1/2 elements
+ def test_XNameContainer_DelKey(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+ spr.Sheets.insertNewByName('foo', 1)
+
+ # When
+ del spr.Sheets['foo']
+
+ # Then
+ self.assertEqual(1, len(spr.Sheets))
+ self.assertFalse('foo' in spr.Sheets)
+
+ # Tests syntax:
+ # del obj[key] # Delete by key
+ # For:
+ # Missing key
+ def test_XNameContainer_DelKey_Missing(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+
+ # When / Then
+ with self.assertRaises(KeyError):
+ del spr.Sheets['foo']
+
+ # Tests syntax:
+ # del obj[key] # Delete by key
+ # For:
+ # Invalid key (float)
+ def test_XNameContainer_DelKey_Invalid(self):
+ # Given
+ spr = self.createBlankSpreadsheet()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ del spr.Sheets[12.34]
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_XNameReplace.py b/pyuno/qa/pytests/testcollections_XNameReplace.py
new file mode 100644
index 0000000..6223114
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_XNameReplace.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing XNameReplace using the new-style
+# collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestXNameReplace(CollectionsTestBase):
+
+ # Tests syntax:
+ # obj[key] = val # Replace by key
+ # For:
+ # 1 element
+ def test_XNameReplace_ReplaceName(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ scriptName = 'macro://Standard.Module1.MySave()'
+ eventProperties = (PropertyValue(Name='Script', Value=scriptName),)
+
+ # When
+ doc.Events['OnSave'] = eventProperties
+
+ # Then
+ onSave = [p.Value for p in doc.Events['OnSave'] if p.Name == 'Script'][0]
+ self.assertEqual(scriptName, onSave)
+
+ # Tests syntax:
+ # obj[key] = val # Replace by key
+ # For:
+ # Invalid key
+ def test_XNameReplace_ReplaceName_Invalid(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ scriptName = 'macro://Standard.Module1.MySave()'
+ eventProperties = (PropertyValue(Name='Script', Value=scriptName),)
+
+ # When / Then
+ with self.assertRaises(KeyError):
+ doc.Events['qqqqq'] = eventProperties
+
+ # Tests syntax:
+ # obj[key] = val # Replace by key
+ # For:
+ # Invalid key type
+ def test_XNameReplace_ReplaceName_Invalid(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ scriptName = 'macro://Standard.Module1.MySave()'
+ eventProperties = (PropertyValue(Name='Script', Value=scriptName),)
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ doc.Events[12.34] = eventProperties
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_base.py b/pyuno/qa/pytests/testcollections_base.py
new file mode 100644
index 0000000..2efb6f4
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_base.py
@@ -0,0 +1,58 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from org.libreoffice.unotest import pyuno
+from com.sun.star.beans import PropertyValue
+
+class CollectionsTestBase(unittest.TestCase):
+
+ @classmethod
+ def setUpClass(cls):
+ cls.context = pyuno.getComponentContext()
+ pyuno.private_initTestEnvironment()
+
+ def setUp(self):
+ self._components = []
+
+ def tearDown(self):
+ for component in self._components:
+ try:
+ component.close(True)
+ except Exception:
+ pass
+
+ def createHiddenWindow(self, url):
+ serviceManager = self.context.ServiceManager
+ desktop = serviceManager.createInstanceWithContext('com.sun.star.frame.Desktop', self.context)
+ loadProps = (
+ PropertyValue(Name='Hidden', Value=True),
+ PropertyValue(Name='ReadOnly', Value=False)
+ )
+ component = desktop.loadComponentFromURL(url, '_blank', 0, loadProps)
+ return component
+
+ def createBlankTextDocument(self):
+ component = self.createHiddenWindow('private:factory/swriter')
+ self._components.append(component)
+ return component
+
+ def createBlankSpreadsheet(self):
+ component = self.createHiddenWindow('private:factory/scalc')
+ self._components.append(component)
+ return component
+
+ def createBlankDrawing(self):
+ component = self.createHiddenWindow('private:factory/sdraw')
+ self._components.append(component)
+ return component
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_misc.py b/pyuno/qa/pytests/testcollections_misc.py
new file mode 100644
index 0000000..c66f6f4
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_misc.py
@@ -0,0 +1,75 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Miscellaneous tests of the behaviour of UNO objects using the new-style
+# collection accessors
+
+class TestMisc(CollectionsTestBase):
+
+ # Tests syntax:
+ # for val in obj: ... # Implicit iterator
+ # For:
+ # Invalid type
+ def test_misc_IterateInvalidType(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ for val in doc.UIConfigurationManager:
+ pass
+
+ # Tests syntax:
+ # if val in itr: ... # Test value presence
+ # For:
+ # Invalid type
+ def test_misc_InInvalidType(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ foo = "bar" in doc.UIConfigurationManager
+
+ # Tests syntax:
+ # num = len(obj) # Number of elements
+ # For:
+ # Invalid type
+ def test_misc_LenInvalidType(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ len(doc.UIConfigurationManager)
+
+ # Tests syntax:
+ # val = obj[0] # Access by index
+ # For:
+ # Invalid type
+ def test_misc_SubscriptInvalidType(self):
+ # Given
+ doc = self.createBlankTextDocument()
+
+ # When / Then
+ with self.assertRaises(TypeError):
+ doc.UIConfigurationManager[0]
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/qa/pytests/testcollections_mixednameindex.py b/pyuno/qa/pytests/testcollections_mixednameindex.py
new file mode 100644
index 0000000..cf4c9e1
--- /dev/null
+++ b/pyuno/qa/pytests/testcollections_mixednameindex.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+import unittest
+import uno
+
+from testcollections_base import CollectionsTestBase
+from com.sun.star.beans import PropertyValue
+
+
+# Tests behaviour of objects implementing both XIndexAccess and XNameAccess
+# using the new-style collection accessors
+# The objects chosen have no special meaning, they just happen to implement the
+# tested interfaces
+
+class TestMixedNameIndex(CollectionsTestBase):
+
+ # Tests:
+ # Ability to access a dual XName*/XIndex* object by both name and index
+ def testWriterTextTableNameAndIndex(self):
+ # Given
+ doc = self.createBlankTextDocument()
+ textTable = doc.createInstance("com.sun.star.text.TextTable")
+ textTable.initialize(2,2)
+ textTable.Name = 'foo'
+ cursor = doc.Text.createTextCursor()
+ doc.Text.insertTextContent(cursor, textTable, False)
+
+ # When
+ tableByName = doc.TextTables['foo']
+ tableByIndex = doc.TextTables[0]
+
+ # Then
+ self.assertEqual('foo', tableByName.Name)
+ self.assertEqual('foo', tableByIndex.Name)
+ self.assertEqual(tableByName,tableByIndex)
+
+
+if __name__ == '__main__':
+ unittest.main()
+
+# vim:set shiftwidth=4 softtabstop=4 expandtab:
\ No newline at end of file
diff --git a/pyuno/source/module/pyuno.cxx b/pyuno/source/module/pyuno.cxx
index 8622037..ce9983e 100644
--- a/pyuno/source/module/pyuno.cxx
+++ b/pyuno/source/module/pyuno.cxx
@@ -19,6 +19,7 @@
#include <sal/config.h>
+#include <algorithm>
#include <cassert>
#include "pyuno_impl.hxx"
@@ -28,10 +29,21 @@
#include <osl/thread.h>
+#include <typelib/typedescription.hxx>
+
#include <com/sun/star/lang/XServiceInfo.hpp>
#include <com/sun/star/lang/XTypeProvider.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/beans/XMaterialHolder.hpp>
+#include <com/sun/star/container/XElementAccess.hpp>
+#include <com/sun/star/container/XEnumeration.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/container/XIndexContainer.hpp>
+#include <com/sun/star/container/XIndexReplace.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XNameReplace.hpp>
using com::sun::star::uno::Sequence;
using com::sun::star::uno::Reference;
@@ -41,6 +53,7 @@ using com::sun::star::uno::makeAny;
using com::sun::star::uno::UNO_QUERY;
using com::sun::star::uno::Type;
using com::sun::star::uno::TypeClass;
+using com::sun::star::uno::TypeDescription;
using com::sun::star::uno::RuntimeException;
using com::sun::star::uno::Exception;
using com::sun::star::uno::XComponentContext;
@@ -50,6 +63,15 @@ using com::sun::star::lang::XTypeProvider;
using com::sun::star::script::XTypeConverter;
using com::sun::star::script::XInvocation2;
using com::sun::star::beans::XMaterialHolder;
+using com::sun::star::container::XElementAccess;
+using com::sun::star::container::XEnumeration;
+using com::sun::star::container::XEnumerationAccess;
+using com::sun::star::container::XIndexAccess;
+using com::sun::star::container::XIndexContainer;
+using com::sun::star::container::XIndexReplace;
+using com::sun::star::container::XNameAccess;
+using com::sun::star::container::XNameContainer;
+using com::sun::star::container::XNameReplace;
namespace pyuno
{
@@ -293,6 +315,57 @@ OUString val2str( const void * pVal, typelib_TypeDescriptionReference * pTypeRef
return buf.makeStringAndClear();
}
+sal_Int32 lcl_PyNumber_AsSal_Int32( PyObject *pObj )
+{
+ // Check object is an index
+ PyRef rIndex( PyNumber_Index( pObj ), SAL_NO_ACQUIRE );
+ if ( !rIndex.is() )
+ return -1;
+
+ // Convert Python number to platform long, then check actual value against
+ // bounds of sal_Int32
+ int nOverflow;
+ long nResult = PyLong_AsLongAndOverflow( pObj, &nOverflow );
+ if ( nOverflow || nResult > SAL_MAX_INT32 || nResult < SAL_MIN_INT32) {
+ PyErr_SetString( PyExc_IndexError, "Python int too large to convert to UNO long" );
+ return -1;
+ }
+
+ return nResult;
+}
+
+int lcl_PySlice_GetIndicesEx( PyObject *pObject, sal_Int32 nLen, sal_Int32 *nStart, sal_Int32 *nStop, sal_Int32 *nStep, sal_Int32 *nSliceLength )
+{
+ Py_ssize_t nStart_ssize, nStop_ssize, nStep_ssize, nSliceLength_ssize;
+
+ int nResult = PySlice_GetIndicesEx( (PySliceObject_t*)pObject, nLen, &nStart_ssize, &nStop_ssize, &nStep_ssize, &nSliceLength_ssize );
+ if (nResult == -1)
+ return -1;
+
+ if ( nStart_ssize > SAL_MAX_INT32 || nStart_ssize < SAL_MIN_INT32
+ || nStop_ssize > SAL_MAX_INT32 || nStop_ssize < SAL_MIN_INT32
+ || nStep_ssize > SAL_MAX_INT32 || nStep_ssize < SAL_MIN_INT32
+ || nSliceLength_ssize > SAL_MAX_INT32 || nSliceLength_ssize < SAL_MIN_INT32 )
+ {
+ PyErr_SetString( PyExc_IndexError, "Python int too large to convert to UNO long" );
+ return -1;
+ }
+
+ *nStart = (sal_Int32)nStart_ssize;
+ *nStop = (sal_Int32)nStop_ssize;
+ *nStep = (sal_Int32)nStep_ssize;
+ *nSliceLength = (sal_Int32)nSliceLength_ssize;
+ return 0;
+}
+
+bool lcl_hasInterfaceByName( Any &object, OUString interfaceName )
+{
+ Reference< XInterface > xInterface( object, UNO_QUERY );
+ TypeDescription typeDesc( interfaceName );
+ Any aInterface = xInterface->queryInterface( typeDesc.get()->pWeakRef );
+
+ return aInterface.hasValue();
+}
PyObject *PyUNO_repr( PyObject * self )
{
@@ -451,6 +524,880 @@ PyObject* PyUNO_dir (PyObject* self)
return member_list;
}
+sal_Int32 lcl_detach_getLength( PyUNO *me )
+{
+ PyThreadDetach antiguard;
+
+ // If both XIndexContainer and XNameContainer are implemented, it is
+ // assumed that getCount() gives the same result as the number of names
+ // returned by getElementNames(), or the user may be surprised.
+
+ // For XIndexContainer
+ Reference< XIndexAccess > xIndexAccess( me->members->wrappedObject, UNO_QUERY );
+ if ( xIndexAccess.is() )
+ {
+ return xIndexAccess->getCount();
+ }
+
+ // For XNameContainer
+ // Not terribly efficient - get the count of all the names
+ Reference< XNameAccess > xNameAccess( me->members->wrappedObject, UNO_QUERY );
+ if ( xNameAccess.is() )
+ {
+ return xNameAccess->getElementNames().getLength();
+ }
+
+ return -1;
+}
+
+int PyUNO_bool( PyObject* self )
+{
+ PyUNO* me = reinterpret_cast<PyUNO*>(self);
+
+ try
+ {
+ int nLen = lcl_detach_getLength( me );
+ if (nLen >= 0)
+ return !!nLen;
+
+ // Anything which doesn't have members is a scalar object and therefore true
+ return 1;
+ }
+ catch( const ::com::sun::star::uno::RuntimeException &e )
+ {
+ raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
+ }
+
+ return -1;
+}
+
+Py_ssize_t PyUNO_len( PyObject* self )
+{
+ PyUNO* me = reinterpret_cast<PyUNO*>(self);
+
+ try
+ {
+ int nLen = lcl_detach_getLength( me );
+ if (nLen >= 0)
+ return nLen;
+
+ PyErr_SetString( PyExc_TypeError, "object has no len()" );
+ }
+ catch( const ::com::sun::star::uno::RuntimeException &e )
+ {
+ raisePyExceptionWithAny( com::sun::star::uno::makeAny( e ) );
+ }
+
+ return -1;
+}
+
+void lcl_getRowsColumns( PyUNO* me, sal_Int32& nRows, sal_Int32& nColumns )
+{
+ Sequence<short> aOutParamIndex;
+ Sequence<Any> aOutParam;
+ Sequence<Any> aParams;
+ Any aRet;
+
+ aRet = me->members->xInvocation->invoke ( "getRows", aParams, aOutParamIndex, aOutParam );
+ Reference< XIndexAccess > xIndexAccessRows( aRet, UNO_QUERY );
+ nRows = xIndexAccessRows->getCount();
+ aRet = me->members->xInvocation->invoke ( "getColumns", aParams, aOutParamIndex, aOutParam );
+ Reference< XIndexAccess > xIndexAccessCols( aRet, UNO_QUERY );
+ nColumns = xIndexAccessCols->getCount();
+}
+
+PyRef lcl_indexToSlice( PyRef rIndex )
+{
+ Py_ssize_t nIndex = PyNumber_AsSsize_t( rIndex.get(), PyExc_IndexError );
+ if (nIndex == -1 && PyErr_Occurred())
+ return NULL;
+ PyRef rStart( PyLong_FromSsize_t( nIndex ), SAL_NO_ACQUIRE );
+ PyRef rStop( PyLong_FromSsize_t( nIndex+1 ), SAL_NO_ACQUIRE );
+ PyRef rStep( PyLong_FromLong( 1 ), SAL_NO_ACQUIRE );
+ PyRef rSlice( PySlice_New( rStart.get(), rStop.get(), rStep.get() ), SAL_NO_ACQUIRE );
+
+ return rSlice;
+}
+
+PyObject* lcl_getitem_XCellRange( PyUNO* me, PyObject* pKey )
+{
+ Runtime runtime;
+
+ Sequence<short> aOutParamIndex;
+ Sequence<Any> aOutParam;
+ Sequence<Any> aParams;
+ Any aRet;
+
+ // Single string key is sugar for getCellRangeByName()
+ if ( PyStr_Check( pKey ) ) {
+
+ aParams.realloc (1);
+ aParams[0] <<= pyString2ustring( pKey );
+ {
+ PyThreadDetach antiguard;
+ aRet = me->members->xInvocation->invoke (
+ "getCellRangeByName", aParams, aOutParamIndex, aOutParam );
+ }
... etc. - the rest is truncated
More information about the Libreoffice-commits
mailing list