How to use Share API in macOS and Qt Quick: Difference between revisions
No edit summary |
No edit summary |
||
Line 9: | Line 9: | ||
= Classes with Share API support. = | = Classes with Share API support. = | ||
First you need to create class with all methods in Objective-C/C++ to use Share API. To do this you need follow a few steps: | First you need to create class with all methods in Objective-C/C++ to use Share API. To do this you need follow a few steps: | ||
# Create a new class and rename .cpp file to .mm. | |||
# Add .h file to .pro of your project in section "OBJECTIVE_HEADERS" and .mm to "OBJECTIVE_SOURCES". | |||
# Change .h file content to this code: | |||
<code>#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
#import <Foundation/Foundation.h> | #import <Foundation/Foundation.h> | ||
#import <Social/Social.h> | |||
/** </code>typedef QfSharePickerItemClicked | /** </code>typedef QfSharePickerItemClicked | ||
* <code>param sharingService Selected type of sharing. | |||
* </code>author Andrew Shapovelov*/ | |||
typedef void(<sup>QfSharePickerItemClicked)(NSSharingService* sharingService); | |||
/** <code>class QfSharePicker | |||
< | * </code>brief Object to show share menu. | ||
< | * <code>author Andrew Shapovalov*/ | ||
< | </code>interface QfSharePicker : NSObject | ||
/** <code>brief Create a new object. | |||
* </code>param view View on what will show share menu. | |||
* <code>param frame Rect to show share window. | |||
* </code>param datas Datas items to share. | |||
* <code>param block Block of code to select item. | |||
* </code>author Andrew Shapovalov*/ | |||
- (instancetype)initWithView:(NSView*)view frame:(NSRect)frame datasArray:(NSArray*)datas onItemClicked:(QfSharePickerItemClicked)block; | |||
<code>end | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
< | </code> | ||
# Change .mm file content to this code: | |||
<code> | |||
#import "qfsharepicker.h" | |||
#include <QtCore> | |||
/** </code>brief The private methods and properties of QfSharePicker class. | |||
* <code>author Andrew Shapovalov*/ | |||
</code>interface QfSharePicker () <NSSharingServicePickerDelegate, NSSharingServiceDelegate> | |||
/** Sharing service picker.*/ | |||
<code>property (nonatomic, retain) NSSharingServicePicker''' picker; | |||
/** Block of code to select item.*/ | |||
</code>property (nonatomic, copy) QfSharePickerItemClicked onItemClicked; | |||
<code>end | |||
shareCurrentContent();< | |||
</code>implementation QfSharePicker | |||
#pragma mark - Init methods | |||
- (instancetype)initWithView:(NSView''')view frame:(NSRect)frame datasArray:(NSArray*)datas onItemClicked:(QfSharePickerItemClicked)block | |||
{ | |||
self = [super init]; | |||
if(self) | |||
{ | |||
self.onItemClicked = block; | |||
self.picker = [[NSSharingServicePicker alloc] initWithItems: datas]; | |||
self.picker.delegate = self; | |||
[self.picker showRelativeToRect:frame ofView:view preferredEdge:NSMinXEdge]; | |||
} | |||
return self; | |||
} | |||
#pragma mark - NSSharingServicePickerDelegate methods | |||
- (void)sharingServicePicker:(NSSharingServicePicker ''')sharingServicePicker didChooseSharingService:(NSSharingService''')service | |||
{ | |||
if(self.picker == sharingServicePicker) | |||
{ | |||
if(self.onItemClicked) | |||
{ | |||
self.onItemClicked(service); | |||
} | |||
} | |||
} | |||
- (id <NSSharingServiceDelegate>)sharingServicePicker:(NSSharingServicePicker ''')sharingServicePicker delegateForSharingService:(NSSharingService''')sharingService | |||
{ | |||
Q_UNUSED(sharingService); | |||
if(self.picker == sharingServicePicker) | |||
{ | |||
} | |||
return self; | |||
} | |||
#pragma mark - NSSharingServiceDelegate methods | |||
- (void)sharingService:(NSSharingService ''')sharingService willShareItems:(NSArray''')items | |||
{ | |||
Q_UNUSED(sharingService); | |||
Q_UNUSED(items); | |||
//Some code here | |||
} | |||
- (void)sharingService:(NSSharingService ''')sharingService didFailToShareItems:(NSArray''')items error:(NSError ''')error | |||
{ | |||
Q_UNUSED(sharingService); | |||
Q_UNUSED(items); | |||
Q_UNUSED(error); | |||
//Some code here | |||
} | |||
- (void)sharingService:(NSSharingService''')sharingService didShareItems:(NSArray ''')items | |||
{ | |||
Q_UNUSED(sharingService); | |||
Q_UNUSED(items); | |||
//Some code here | |||
} | |||
#pragma mark - Clear memory | |||
- (void)dealloc | |||
{ | |||
[super dealloc]; | |||
[self.picker autorelease]; | |||
[self.onItemClicked release]; | |||
self.onItemClicked = nil; | |||
} | |||
<code>end | |||
</code> | |||
p. More information you can find in official Apple "documentation":https://developer.apple.com/library/mac/DOCUMENTATION/AppKit/Reference/NSSharingServicePicker_Class/index.html. And you need to see information about class "NSSharingServicePickerDelegate":https://developer.apple.com/library/mac/DOCUMENTATION/AppKit/Reference/NSSharingServicePickerDelegate_Protocol/index.html#//apple_ref/occ/intf/NSSharingServicePickerDelegate. | |||
h1. Create QtQuick Item to use Share API from App. | |||
p. Second class which you need to create is a class to call from C+''. This class will call Objective-C/C. To do this you need follow a few steps: | |||
# Create a new C''+ class. | |||
# Rename .cpp file to .mm and added it to "OBJECTIVE_SOURCES". | |||
# Change .h file content to code: | |||
<code> | |||
#include <QtCore> | |||
#include <QtQuick> | |||
/'''* </code>class QfShareItem | |||
* <code>brief Manager to use share logic. | |||
* </code>author Andrew Shapovalov*/ | |||
class QfShareItem : public QQuickPaintedItem | |||
{ | |||
Q_OBJECT | |||
Q_PROPERTY(QString shareString READ getShareString WRITE setShareString NOTIFY shareStringChanged) | |||
Q_PROPERTY(QUrl shareUrl READ getShareUrl WRITE setShareUrl NOTIFY shareUrlChanged) | |||
private: | |||
/** The share string info.*/ | |||
QString m_shareString; | |||
/'''* The share link.*/ | |||
QUrl m_shareUrl; | |||
/'''* <code>brief Strip all HTML tags from string. | |||
* </code>param body The source string. | |||
* <code>return Plain text. | |||
* </code>author Andrew Shapovalov*/ | |||
QString stripHTMLTags(QString body); | |||
/** <code>brief Works with all applications events. | |||
* </code>param obj The object which call event. | |||
* <code>param event The event of call. | |||
* </code>author Andrew Shapovalov*/ | |||
bool eventFilter(QObject* obj, QEvent* event); | |||
/** <code>brief Share current content. | |||
* </code>author Andrew Shapovalov*/ | |||
void shareCurrentContent(); | |||
public: | |||
/** <code>brief Create a new object. | |||
* </code>param parent Parent object. | |||
* <code>author Andrew Shapovalov*/ | |||
explicit QfShareItem(QQuickPaintedItem '''parent = 0); | |||
//Others | |||
/'''* </code>brief Called when current object will redrawing. | |||
* <code>param painter The object for draw data. | |||
* </code>author Andrew Shapovalov*/ | |||
void paint(QPainter '''painter); | |||
//Getters | |||
/'''* <code>brief Get share content string. | |||
* </code>return Share string content. | |||
* <code>author Andrew Shapovalov*/ | |||
inline QString getShareString(){return m_shareString;} | |||
/** </code>brief Get share url. | |||
* <code>return Share url. | |||
* </code>author Andrew Shapovalov*/ | |||
inline QUrl getShareUrl(){return m_shareUrl;} | |||
//Setters | |||
/** <code>brief Set share content string. | |||
* </code>param value Share string content. | |||
* <code>author Andrew Shapovalov*/ | |||
inline void setShareString(QString value){m_shareString = value; emit shareStringChanged(m_shareString);} | |||
/** </code>brief Set share url. | |||
* <code>param value Share url. | |||
* </code>author Andrew Shapovalov*/ | |||
inline void setShareUrl(QUrl value){m_shareUrl = value; emit shareUrlChanged(m_shareUrl);} | |||
/** <code>brief Share content and url. | |||
* </code>param text The text of share. | |||
* <code>param url The url to share. | |||
* </code>author Andrew Shapovalov*/ | |||
Q_INVOKABLE void shareContent(QString text = QString(), QUrl url = QUrl()); | |||
signals: | |||
/** <code>brief Called when share content string was changed. | |||
* </code>param value Share string content. | |||
* <code>author Andrew Shapovalov*/ | |||
void shareStringChanged(QString value); | |||
/** </code>brief Called when share url was changed. | |||
* <code>param value Share url. | |||
* </code>author Andrew Shapovalov*/ | |||
void shareUrlChanged(QUrl value); | |||
/** <code>brief Called when user select share service. | |||
* </code>param serviceName The name of selected service. | |||
* <code>author Andrew Shapovalov*/ | |||
void selectedService(QString serviceName); | |||
public slots: | |||
}; | |||
</code> | |||
# Change .mm file content to code: | |||
<code> | |||
#include "qfshareitem.h" | |||
#include "qfsharepicker.h" | |||
QString QfShareItem::stripHTMLTags(QString body) | |||
{ | |||
body.replace("<br>",""); | |||
body.replace("</br>",""); | |||
body.replace("</p>",""); | |||
body.replace("</td>",""); | |||
body.remove(QRegExp("<head&amp;gt;(.''')</head&amp;gt;")); | |||
body.remove(QRegExp("<form(.''')</form>")); | |||
body.remove(QRegExp( "<(.)[</sup>>]'''>")); | |||
return body.trimmed(); | |||
} | |||
bool QfShareItem::eventFilter(QObject''' obj, QEvent* event) | |||
{ | |||
if(obj == this) | |||
{ | |||
if(parentItem()) | |||
{ | |||
return QObject::eventFilter(parentItem(), event); | |||
} | |||
} | |||
return QObject::eventFilter(obj, event); | |||
} | |||
void QfShareItem::shareCurrentContent() | |||
{ | |||
QQuickItem* parentItem = this->parentItem(); | |||
if(!m_shareString.isEmpty() && parentItem) | |||
{ | |||
QRectF rect = parentItem->mapRectToItem(NULL, parentItem->boundingRect()); | |||
NSView* view = reinterpret_cast<NSView *>(parentItem->window()->winId()); | |||
NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height()); | |||
m_shareString = m_shareString.replace("<style type=quot;text/cssquot;>a {color:#44a51c;text-decoration:none;}</style&amp;gt;", ""); | |||
QString content = stripHTMLTags(m_shareString).trimmed(); | |||
NSMutableArray* datas = [NSMutableArray arrayWithObject: content.toNSString()]; | |||
if(!m_shareUrl.isEmpty()) | |||
{ | |||
NSURL* url = [NSURL URLWithString: m_shareUrl.toString().toNSString()]; | |||
if(url) | |||
{ | |||
[datas addObject: url]; | |||
} | |||
} | |||
QfSharePicker* sharePicker = [[QfSharePicker alloc] initWithView:view frame:frame datasArray:datas onItemClicked:nil]; | |||
[sharePicker autorelease]; | |||
} | |||
} | |||
QfShareItem::QfShareItem(QQuickPaintedItem '''parent) : | |||
QQuickPaintedItem(parent) | |||
{ | |||
m_shareString.clear(); | |||
m_shareUrl.clear(); | |||
connect(this, &QQuickPaintedItem::parentChanged, [this](QQuickItem''' newParent){ | |||
if(newParent) | |||
{ | |||
newParent->setFiltersChildMouseEvents(true); | |||
} | |||
}); | |||
this->installEventFilter(this); | |||
setFlag(QQuickPaintedItem::ItemHasContents, true); | |||
setFlag(QQuickPaintedItem::ItemClipsChildrenToShape, true); | |||
setFlag(QQuickPaintedItem::ItemAcceptsDrops, true); | |||
setRenderTarget(QQuickPaintedItem::InvertedYFramebufferObject); | |||
} | |||
void QfShareItem::paint(QPainter *painter) | |||
{ | |||
try | |||
{ | |||
Q_UNUSED(painter); | |||
} | |||
catch(std::exception&amp; exception) | |||
{ | |||
qDebug()<<"exception: "<<exception.what(); | |||
} | |||
} | |||
void QfShareItem::shareContent(QString text, QUrl url) | |||
{ | |||
if(!text.isEmpty()) | |||
{ | |||
m_shareString = text; | |||
} | |||
if(!url.isEmpty()) | |||
{ | |||
m_shareUrl = url; | |||
} | |||
shareCurrentContent(); | |||
} | |||
</code> | |||
# Register new type to use in QML. | |||
<code> | |||
qmlRegisterType<YourShareItem>(uri, 1, 1, "YourShareItem"); | |||
</code> | |||
= How to use in QML. = | = How to use in QML. = | ||
Import the new type to your QML file where you need to use share logic and add this code: | Import the new type to your QML file where you need to use share logic and add this code: | ||
<code> | |||
Button { | |||
id: btnLink | |||
width: 22 | |||
height: 22 | |||
onClicked: { | onClicked: { | ||
share.shareContent(); | |||
} | |||
QfShareItem { | QfShareItem { | ||
id: share | |||
anchors.fill: btnLink | |||
shareUrl: userPanelView.shareUrl | |||
} | |||
} | |||
</code> | |||
= Summary = | = Summary = |
Revision as of 11:21, 25 February 2015
[toc align_right="yes" depth="2"]
Hi everyone!
In this article I've tried to explain how to use Mac OS X Share API in your Qt Quick app. Share API was implemented in Mac OS 10.10 (Yosemite).
As you know all frameworks in OS X which you could use in your application created with Objective-C/C+. That's why you can't use framework in your C+ classes. You need to rename your .cpp file to .mm and then you can call Objective-C code. But sometimes you need to call methods with arguments with Objective-C. As you know in .h file you can't call Objective-C code. You must create Objective-C class which will call all needed methods to work with target framework.
First you need to create class with all methods in Objective-C/C++ to use Share API. To do this you need follow a few steps:
- Create a new class and rename .cpp file to .mm.
- Add .h file to .pro of your project in section "OBJECTIVE_HEADERS" and .mm to "OBJECTIVE_SOURCES".
- Change .h file content to this code:
#ifdef __cplusplus
extern "C" {
#endif
#import <Foundation/Foundation.h>
#import <Social/Social.h>
/**
typedef QfSharePickerItemClicked *
param sharingService Selected type of sharing.
*
author Andrew Shapovelov*/
typedef void(QfSharePickerItemClicked)(NSSharingService* sharingService);
/**
class QfSharePicker
*
brief Object to show share menu. *
author Andrew Shapovalov*/
interface QfSharePicker : NSObject /**
brief Create a new object.
*
param view View on what will show share menu. *
param frame Rect to show share window.
*
param datas Datas items to share. *
param block Block of code to select item.
*
author Andrew Shapovalov*/
- (instancetype)initWithView:(NSView*)view frame:(NSRect)frame datasArray:(NSArray*)datas onItemClicked:(QfSharePickerItemClicked)block;
end
#ifdef __cplusplus
}
#endif
- Change .mm file content to this code:
#import "qfsharepicker.h"
#include <QtCore>
/**
brief The private methods and properties of QfSharePicker class. *
author Andrew Shapovalov*/
interface QfSharePicker () <NSSharingServicePickerDelegate, NSSharingServiceDelegate>
/** Sharing service picker.*/
property (nonatomic, retain) NSSharingServicePicker''' picker;
/** Block of code to select item.*/
property (nonatomic, copy) QfSharePickerItemClicked onItemClicked;
end
implementation QfSharePicker
- pragma mark - Init methods
- (instancetype)initWithView:(NSView)view frame:(NSRect)frame datasArray:(NSArray*)datas onItemClicked:(QfSharePickerItemClicked)block {
self = [super init];
if(self) { self.onItemClicked = block; self.picker = [[NSSharingServicePicker alloc] initWithItems: datas]; self.picker.delegate = self; [self.picker showRelativeToRect:frame ofView:view preferredEdge:NSMinXEdge]; }
return self;
}
- pragma mark - NSSharingServicePickerDelegate methods
- (void)sharingServicePicker:(NSSharingServicePicker )sharingServicePicker didChooseSharingService:(NSSharingService)service {
if(self.picker == sharingServicePicker) { if(self.onItemClicked) { self.onItemClicked(service); } }
}
- (id <NSSharingServiceDelegate>)sharingServicePicker:(NSSharingServicePicker )sharingServicePicker delegateForSharingService:(NSSharingService)sharingService {
Q_UNUSED(sharingService);
if(self.picker == sharingServicePicker) { }
return self;
}
- pragma mark - NSSharingServiceDelegate methods
- (void)sharingService:(NSSharingService )sharingService willShareItems:(NSArray)items {
Q_UNUSED(sharingService); Q_UNUSED(items);
//Some code here
}
- (void)sharingService:(NSSharingService )sharingService didFailToShareItems:(NSArray)items error:(NSError )error {
Q_UNUSED(sharingService); Q_UNUSED(items); Q_UNUSED(error);
//Some code here
}
- (void)sharingService:(NSSharingService)sharingService didShareItems:(NSArray )items {
Q_UNUSED(sharingService); Q_UNUSED(items);
//Some code here
}
- pragma mark - Clear memory
- (void)dealloc {
[super dealloc];
[self.picker autorelease]; [self.onItemClicked release]; self.onItemClicked = nil;
}
end
p. More information you can find in official Apple "documentation":https://developer.apple.com/library/mac/DOCUMENTATION/AppKit/Reference/NSSharingServicePicker_Class/index.html. And you need to see information about class "NSSharingServicePickerDelegate":https://developer.apple.com/library/mac/DOCUMENTATION/AppKit/Reference/NSSharingServicePickerDelegate_Protocol/index.html#//apple_ref/occ/intf/NSSharingServicePickerDelegate.
h1. Create QtQuick Item to use Share API from App.
p. Second class which you need to create is a class to call from C+. This class will call Objective-C/C. To do this you need follow a few steps:
- Create a new C+ class.
- Rename .cpp file to .mm and added it to "OBJECTIVE_SOURCES".
- Change .h file content to code:
#include <QtCore>
#include <QtQuick>
/'''*
class QfShareItem *
brief Manager to use share logic.
*
author Andrew Shapovalov*/
class QfShareItem : public QQuickPaintedItem {
Q_OBJECT Q_PROPERTY(QString shareString READ getShareString WRITE setShareString NOTIFY shareStringChanged) Q_PROPERTY(QUrl shareUrl READ getShareUrl WRITE setShareUrl NOTIFY shareUrlChanged)
private: /** The share string info.*/ QString m_shareString;
/* The share link.*/ QUrl m_shareUrl;
/*
brief Strip all HTML tags from string.
*
param body The source string. *
return Plain text.
*
author Andrew Shapovalov*/
QString stripHTMLTags(QString body);
/**
brief Works with all applications events.
*
param obj The object which call event. *
param event The event of call.
*
author Andrew Shapovalov*/
bool eventFilter(QObject* obj, QEvent* event);
/**
brief Share current content.
*
author Andrew Shapovalov*/
void shareCurrentContent();
public:
/**
brief Create a new object.
*
param parent Parent object. *
author Andrew Shapovalov*/
explicit QfShareItem(QQuickPaintedItem '''parent = 0);
//Others
/'''*
brief Called when current object will redrawing. *
param painter The object for draw data.
*
author Andrew Shapovalov*/
void paint(QPainter painter);
//Getters
/*
brief Get share content string.
*
return Share string content. *
author Andrew Shapovalov*/
inline QString getShareString(){return m_shareString;}
/**
brief Get share url. *
return Share url.
*
author Andrew Shapovalov*/
inline QUrl getShareUrl(){return m_shareUrl;}
//Setters
/**
brief Set share content string.
*
param value Share string content. *
author Andrew Shapovalov*/
inline void setShareString(QString value){m_shareString = value; emit shareStringChanged(m_shareString);}
/**
brief Set share url. *
param value Share url.
*
author Andrew Shapovalov*/
inline void setShareUrl(QUrl value){m_shareUrl = value; emit shareUrlChanged(m_shareUrl);}
/**
brief Share content and url.
*
param text The text of share. *
param url The url to share.
*
author Andrew Shapovalov*/
Q_INVOKABLE void shareContent(QString text = QString(), QUrl url = QUrl());
signals:
/**
brief Called when share content string was changed.
*
param value Share string content. *
author Andrew Shapovalov*/
void shareStringChanged(QString value);
/**
brief Called when share url was changed. *
param value Share url.
*
author Andrew Shapovalov*/
void shareUrlChanged(QUrl value);
/**
brief Called when user select share service.
*
param serviceName The name of selected service. *
author Andrew Shapovalov*/
void selectedService(QString serviceName);
public slots:
};
- Change .mm file content to code:
#include "qfshareitem.h"
#include "qfsharepicker.h"
QString QfShareItem::stripHTMLTags(QString body)
{
body.replace("<br>","");
body.replace("</br>","");
body.replace("</p>","");
body.replace("</td>","");
body.remove(QRegExp("<head&amp;gt;(.''')</head&amp;gt;"));
body.remove(QRegExp("<form(.''')</form>"));
body.remove(QRegExp( "<(.)[</sup>>]'''>"));
return body.trimmed();
}
bool QfShareItem::eventFilter(QObject''' obj, QEvent* event)
{
if(obj == this)
{
if(parentItem())
{
return QObject::eventFilter(parentItem(), event);
}
}
return QObject::eventFilter(obj, event);
}
void QfShareItem::shareCurrentContent()
{
QQuickItem* parentItem = this->parentItem();
if(!m_shareString.isEmpty() && parentItem)
{
QRectF rect = parentItem->mapRectToItem(NULL, parentItem->boundingRect());
NSView* view = reinterpret_cast<NSView *>(parentItem->window()->winId());
NSRect frame = NSMakeRect(rect.x(), rect.y(), rect.width(), rect.height());
m_shareString = m_shareString.replace("<style type=quot;text/cssquot;>a {color:#44a51c;text-decoration:none;}</style&amp;gt;", "");
QString content = stripHTMLTags(m_shareString).trimmed();
NSMutableArray* datas = [NSMutableArray arrayWithObject: content.toNSString()];
if(!m_shareUrl.isEmpty())
{
NSURL* url = [NSURL URLWithString: m_shareUrl.toString().toNSString()];
if(url)
{
[datas addObject: url];
}
}
QfSharePicker* sharePicker = [[QfSharePicker alloc] initWithView:view frame:frame datasArray:datas onItemClicked:nil];
[sharePicker autorelease];
}
}
QfShareItem::QfShareItem(QQuickPaintedItem '''parent) :
QQuickPaintedItem(parent)
{
m_shareString.clear();
m_shareUrl.clear();
connect(this, &QQuickPaintedItem::parentChanged, [this](QQuickItem''' newParent){
if(newParent)
{
newParent->setFiltersChildMouseEvents(true);
}
});
this->installEventFilter(this);
setFlag(QQuickPaintedItem::ItemHasContents, true);
setFlag(QQuickPaintedItem::ItemClipsChildrenToShape, true);
setFlag(QQuickPaintedItem::ItemAcceptsDrops, true);
setRenderTarget(QQuickPaintedItem::InvertedYFramebufferObject);
}
void QfShareItem::paint(QPainter *painter)
{
try
{
Q_UNUSED(painter);
}
catch(std::exception&amp; exception)
{
qDebug()<<"exception: "<<exception.what();
}
}
void QfShareItem::shareContent(QString text, QUrl url)
{
if(!text.isEmpty())
{
m_shareString = text;
}
if(!url.isEmpty())
{
m_shareUrl = url;
}
shareCurrentContent();
}
- Register new type to use in QML.
qmlRegisterType<YourShareItem>(uri, 1, 1, "YourShareItem");
How to use in QML.
Import the new type to your QML file where you need to use share logic and add this code:
Button {
id: btnLink
width: 22
height: 22
onClicked: {
share.shareContent();
}
QfShareItem {
id: share
anchors.fill: btnLink
shareUrl: userPanelView.shareUrl
}
}