QtWebkit custom dns setting without system settings - qt

I want to change my dns for every one of my request for some reasons! I work with Qt 5.3 and QtWebkit! I do search but i can not find anything that can help me!
Actually QDnsLookup can't force QtWebkit to set its load() function to use specific look up and it use the system Dns setting at the end!
Any idea?!

Create you own QNAM subclass and QWebPage subclass. Implement you DNS resolver there. Then set it for each QWebPage you create. This way you will get full network control of what happens in WebKit.
To be sure all WebPages will get your QNAM, subclass QWebView too and set your QWebPage subclass as page in constructor. Also overload createWindow function so all new QWebView pages(like popups) will be created as your QWebView subclass.
YourWebView::YourWebView(QWidget *parent):QWebView(parent)
{
this->setPage(new YourWebPageSubclass());
...
QWebView * YourWebView::createWindow(QWebPage::WebWindowType type)
{
YourWebView * view = Q_NULLPTR;
switch(type)
{
case QWebPage::WebBrowserWindow:
view = new YourWebView(0);
break;
case QWebPage::WebModalDialog:
view = new YourWebView(0);
view->setWindowModality(Qt::ApplicationModal);
break;
}
return view;
}
YourWebPageSubclass::YourWebPageSubclass(QObject *parent):QWebPage(parent)
{
this->setNetworkAccessManager(new YourQNAM(this));
...

Related

How to turn off Motion Controller line pointer

That's it, I'll step on my pride!
I'm using MRTK v2 and working fine except that at some point I want to turn off the line extending from the Motion Controller to the object and that provides input. After looking around and trying to find it in the MRTK documentation (it's gotta be easy, right?), I'm still banging my head on the wall and it's starting to hurt....
The MRTK documentation explains quite well how to configure it here:
https://github.com/microsoft/MixedRealityToolkit-Unity/blob/mrtk_release/Documentation/Input/Pointers.md
But I'm looking to do this in script, enabling and disabling it as I need it in my application.
Any clue how to do this?
Many thanks!
Answered my own question. Simple:
PointerUtils.SetMotionControllerRayPointerBehavior(PointerBehavior.AlwaysOff);
See documentation here: https://github.com/microsoft/MixedRealityToolkit-Unity/blob/mrtk_release/Documentation/Input/Pointers.md
Great question! Here's one way to do this that has worked for me. You can see my solution at this repository: https://github.com/julenka/MixedRealityToolkit-Unity/tree/so/linepointer_off. Open the scene Assets/TurnOffLinePointerTest.unity and then use hand simulation to press the buttons. The code to turn the pointers on/off is in Assets/PointerConfigurationExample.cs.
Note: the reason you need to use this approach of modifying the mediator instead of directly setting myPointer.IsActive = false is because the default mediator overwrites these values every frame. Luckily, you can customize this behavior.
Step 1: Update MRTK a bit so that PointerMediator can be accessed
Apply the changes from this commit to your MRTK clone. This change updates the FocusProvider in MRTK to make the PointerMediator publicly accessible, and makes the DefaultPointerMediator extensible by updating fields to be protected instead of private, and making methods virtual. See this pull request that implements this change directly into MRTK.
Step 2: Create a custom PointerMediator that will turn off far pointers
Create a custom Pointer Mediator like the one from this commit.
using System.Collections.Generic;
using Microsoft.MixedReality.Toolkit.Input;
public class CustomPointerMediator : DefaultPointerMediator
{
public bool FarPointersDisabled {get; set;}
public override void UpdatePointers()
{
base.UpdatePointers();
if (FarPointersDisabled)
{
foreach(var pointer in farInteractPointers)
{
pointer.IsActive = false;
}
}
}
}
Note that this mediator extends DefaultPointerMediator so it adapts almost all the default mediator logic. Make sure you have fully applied the changes from the first commit otherwise you will not be able to extend DefaultPointerMediator.
Step 3: Tell MRTK to use your custom pointer mediator
In your pointer profile, configure MRTK to use the custom pointer mediator instead of the default pointer mediator. Notice in the picture that I've created a custom pointer profile as part of a custom input system (don't modify the default profile otherwise your changes might get overwritten when you update MRTK).
Step 4: Component that uses custom mediator to turn line pointers on / off
You can now write your component which will use your custom mediator to turn the line pointers on and off.
public class PointerConfigurationExample : MonoBehaviour
{
/* Turns off all far interaction pointers */
public void TurnOffFarPointers()
{
Debug.Log("Line pointers off");
SetFarPointersDisabled(true);
}
public void TurnOnFarPointers()
{
Debug.Log("Line pointers on");
SetFarPointersDisabled(false);
}
private void SetFarPointersDisabled(bool isDisabled)
{
FocusProvider focusProvider = (FocusProvider) MixedRealityToolkit.InputSystem.FocusProvider;
if (focusProvider != null)
{
foreach(var mediator in focusProvider.PointerMediators)
{
// Note: you could check here to make sure you only disable pointers for hands
CustomPointerMediator myMediator = (CustomPointerMediator) (mediator.Value);
if (myMediator != null)
{
myMediator.FarPointersDisabled = isDisabled;
}
}
}
}
}

Using CEFSharp ILifeSpanHandler interface to Handle Popups

I have an issue with handling popups. I have implemented ILifeSpanHandler and OnBeforeBrowse (amoungst others) from the IRequestHandler.
How do I know in the ILifeSpanHandler what URL is being called? I am unable to get it in either the OnAfterCreated or OnBeforePopup. Currently I see it first in OnBeforeBrowse.
I have no code as my question is a "How to". In OnBeforePopup I have checked targetUrl however it seems to be there for decoration as I have read that it is not implemented anyway. I have also looked at the browner/chromiumWebBrowser objects, browser and newBroswer seem to be nothing. One would expect in OnAfterCreated chromiumWebBrowser would return an object but it is nothing in my case.
I am testing with the following
Public Sub OnAfterCreated(chromiumWebBrowser As IWebBrowser, browser As IBrowser) Implements ILifeSpanHandler.OnAfterCreated
Try
Debug.Print(vbNewLine)
Debug.Print("OnAfterCreated")
Debug.Print(String.Concat("OnAfterCreated - MainFrame.Url "), browser.MainFrame.Url)
Debug.Print("OnAfterCreated")
Debug.Print(vbNewLine)
Catch ex As Exception
End Try
End Sub
And I have the following
Public Function OnBeforePopup(chromiumWebBrowser As IWebBrowser, browser As IBrowser, frame As IFrame, targetUrl As String, targetFrameName As String, targetDisposition As WindowOpenDisposition, userGesture As Boolean, popupFeatures As IPopupFeatures, windowInfo As IWindowInfo, browserSettings As IBrowserSettings, ByRef noJavascriptAccess As Boolean, ByRef newBrowser As IWebBrowser) As Boolean Implements ILifeSpanHandler.OnBeforePopup
Try
Debug.Print(vbNewLine)
Debug.Print("OnBeforePopup")
Debug.Print(String.Concat("OnBeforePopup - targetUrl "), targetUrl)
Debug.Print(String.Concat("OnBeforePopup - browser.MainFrame.Url "), browser.MainFrame.Url)
Debug.Print(String.Concat("OnBeforePopup - chromiumWebBrowser.Address "), chromiumWebBrowser.Address)
Debug.Print("OnBeforePopup")
Debug.Print(vbNewLine)
Catch ex As Exception
End Try
Return False
End Function
I have seen different approaches in handling popups using ILifeSpanHandler interface. One approach that I've seen also here in Stack Overflow and was accepted as the correct answer to that particular question is to return true in the OnBeforePopup implementation of ILifeSpanHandler then pass the targetURL argument to a handler that creates the popup.
This approach is very unideal because you are destroying the link between the page that actually opened the popup and the popup itself. If you access via JavaScript the opener property of the window object inside the popup you would notice that it is null. And the page that opened the popup would never know that the popup was actually opened because returning true cancels the creation.
The other approach is to let Cef create the popup and the programmer just decides whether to show the browser as a popup window or a child to control (like in tabbed browsing). This is error-free and almost ideal. But the problem with this approach is that you are not able to listen to events such as FrameLoadStart, FrameLoadEnd, AddressChanged, TitleChanged, etc.
One approach that is tagged experimental by the Cef developers is to return a new IWebBrowser instance via newWebBrowser out parameter. This has so many many side effects. The page that opened the popup would, of course, recognize the popup as his although it was not the original browser (IBrowser) that it created. The page may just ignore it like btcclicks.com and in that case, there'd be no problem. But there are websites like drops.xyz that is so particular with his stuff and will discard everything that is not originally his. So this is a problem.
So what is the correct approach?
The ChromeWebBrowser control
Now I'm going to share with you an undocumented approach in handling popups. Speaking of ChromeWebBrowser control, it is very much of help that we know how it creates the webbrowser which, in reality, it doesn't. The control just hosts the webbrowser window handle. It has a private field called managedCefBrowserAdapter (ManagedCefBrowserAdapter class) that handles the actual creation of the web browser. ChromiumWEbBrowser implements the IWebBrowserInternal that has a method OnAfterBrowserCreated with a single parameter of type IBrowser. The control then invokes browser.GetHost().GetWindowHandle() to get the actual window handle (HWND) of the webbrowser it is being hosted. It is quite good.
The problem of the ChromeWebBrowser is that it won't have a constructor that accepts an IBrowser as an argument. It only has constructor that accepts HtmlString, string and IRequestContext arguments. These control waits for the
invocation of OnHandleCreated (a base class override) where it calls the managedCefBrowserAdapter.CreateBrowser after which it waits till its implementation of IWebBrowserInternal's OnAfterBrowserCreated is invoked.
Again, what is the approach that works?
Now, this approach that actually works is a product of long series of trial and error. One caution though is that I don't know why and how it works but I know it works.
First, I did not use ChromeWebBrowser. But I copied its code omitting the part where it creates .net control. In this case, I am targeting the browser's window handle (HWND) to be host by any object that exposes a HWND. Obviously I created a class (NativeCefWebBrowser) that uses the modified code. The ChromeWebBrowser orignal constructors were still there untouched becuase they are used to the create the parent webrowser. But I added one constructor that accept the following arguments: ICefBrowserParent parent (an interface I've created and IBrowser browser that receives the browser argument in the ILifeSpanHandler's OnBeforePopup. I also added a public method AttachBrowser that has a single parameter IBrowser that recieves the IBrowser argument in the ILifeSpanHandler's OnAfterCreated. It the browser that will be kept by CefNativeWebBrowser class.
Why didn't I keep the browser instance received form ILifeSpanHandler.OnBeforePopup but used the instance received from ILifeSpanHandler.OnAfterCreated when they are the same browser instance? This is one of those parts that I don't know why. One thing I noticed is that when I called browser.GetHost().GetWindowHandle() during ILiffeSpanHandler.OnBeforePopup, the first window handle I received was the different compared to when I invoked the method during ILifeSpanHandler.OnAfterCreatd. Because of that, I store the browser instance from the latter that I passed to the NativeCefWebBrowser.AttachBrowser for its safekeeping.
In the NativeCefWebBrowser(ICefBrowserParent parent, IBrowser browser) contructor, I set the private following fields to true: browsercreated, browserinitialized (chromewebbrwoser orginal fields) and isAttachingBrowser (added private field). You don't call the ManagedCefBrowserAdapter's CreateBrowser in this contructor in instead call its OnAfterBrowserCreated passing the browser instance. You don't much in this constructor as you will wait the ILifeSpanHandler implementor to pass you the browser instance it will receive during its OnAfterCreated method. Take note that when calling the ManagedCefBrowserAdapter's OnAfterBrowserCreated method, ManagedCefBrowserAdapter will still invoke IWebBrowserInternal implementation of OnAfterBrowserCreated that when happens you have to exit immediately when isAttachingBrowser is true as the following code will no sense no more.
After calling the NativeCefWebBrowser(ICefBrowserParent, IBroser) construct, you can normally set event listeners as you will normally do.
And that's it.
The following are parts of the code that I wrote
The ICefBrowserParent interface
public interface ICefBrowserParent
{
IntPtr Handle { get; }
Size ClientSize { get; }
bool Disposing { get; }
bool IsDisposed { get; }
bool InvokeRequired { get; }
IAsyncResult BeginInvoke(Delegate d);
object Invoke(Delegate d);
event EventHandler Resize;
}
As you would notice, the methods, properties and events in this interface are already implemented by the System.Windowns.Forms.Control class. So if you implementing this from class inhering Control class, you would not need to implement this anymore. This interface is only for non-Control class.
class NativeCefWebBrowser
{
public NativeCefWebBrowser(ICefBrowserParent, IBroser)
{
requestContext = browser.GetHost().RequestContext;
this.parent = parent; // added field
HasParent = true; // IWebBrowserInternal. I don't know what's this for
mustSetBounds = true; // added field
browserCreated = true;
isAttachingBrowser = true; // added field
InitializeFieldsAndCefIfRequired();
managedCefBrowserAdapter.OnAfterBrowserCreated(browser);
}
}
ILifeSpanHandler.OnBeforePopup(..., out IWebBrowser newWebBrowser)
{
CefNativeWebBrowser b = new CefNativeWebBrowser
(
parent, // defined else where
browser
);
// Attach event handlers
b.TitleChanged...;
newWebBrowser = b;
}
ILifeSpanHandler.OnAfterCreated(...)
{
((CefNativeWebBrowser)webBrowser).AttachBrowser(browser);
}

Qt/QML: Display an indicator depending on if something is downloaded or not

I'm wondering what might be the best approach to the following situation:
I have a QML file that is load from a HTTP server to a Qt/QML android app to display the UI.
The user can tap on thumbnails of catalogs and make the app download another QML file for each catalog. The catalog QML is downloaded and stored on the device for offline use.
This means I have a number of directories that have a unique ID to store the catalog QML and assets. Something like this:
/my/app_data_path/catalogs/CATALOG_001
/my/app_data_path/catalogs/CATALOG_007
/my/app_data_path/catalogs/CATALOG_010
In the UI I'd like to show an indicator that tells if a catalog has been downloaded already to the device. What would be the best approach within QML to show/hide an indicator depending on that?
Rectangle {
id: indicator
visible: MyApp.catalogIsLoaded('some ID here')
}
This is something that came to my mind, but I don't think it's the best way to do this since I'd need a method to pass the catalog ID in order to check if the data directory exists. Also I'd have to figure out a way to re-evaluate the visible state/call the catalogIsLoaded method from time to time - especially after downloading or deleting catalogs.
Is there a better/cleaner approach to this?
A better way would be to associate your indicator visibility with a property binding.
As you wish to find a catalog by its id, provide an invokable method on your 'MyApp' class to return a catalog reference.
Q_INVOKABLE Catalog* findCatalogById(const QString& id);
Catalog will be a QObject, expose a isLoaded property to QML.
class Catalog : public QObject {
Q_OBJECT
Q_PROPERTY(bool isLoaded READ isLoaded NOTIFY isLoadedChanged)
public:
Catalog(QObject* parent = 0) : QObject(parent) {
}
bool isLoaded() const { return m_isLoaded; }
void setIsLoaded(bool loaded) {
if (m_isLoaded != loaded) {
m_isLoaded = loaded;
emit isLoadedChanged();
}
}
signals:
void isLoadedChanged();
private:
bool m_isLoaded; //should probably be initialized to false
};
Of course, the catalog reference provided by your context should be memorize somewhere (like in a QHash<QString, Catalog*>), and be updated accordingly when its status changed.

Handling errors in QWebView / QWebPage

I wish to get more information than just success = false in loadFinished (this is most often just a canceled load). From the documentation and other posts on this site, I gathered I should subclass QWebPage and override the extension() method to handle the ErrorPageExtension.
However, I'm not getting it to work, i.e., no matter what I try my extension method does not get called. I'm probably doing something really stupid but not seeing it. Basically my class looks like this:
class MyWebPage : public QWebPage
{
Q_OBJECT
public:
MyWebPage(QObject* parent = 0) : QWebPage(parent) {}
virtual bool extension(Extension extension,
const ExtensionOption* option = 0,
ExtensionReturn* output = 0)
{
// blah
}
virtual bool supportsExtension(Extension extension)
{
// blah
}
};
The implementation of the methods is not the problem, I have a breakpoint there and it never gets called. I create an instance like
MyWebPage* page = new MyWebPage(this);
mUi.WebView->setPage(page);
I'm a bit uncertain about the life time of a QWebPage object in QWebView, but from my tests it seems the QWebPage always remains the same instance and simply loads new content. So I assumed I should simply give my page to the QWebView, I didn't see another way to make it use my derived class. But when loading bogus URLs, non-existing local files, or unsupported content, either via the WebView or directly via the mainframe of the page, I never get the call with ErrorPageExtension information.
Any help is appreciated. This is using Qt 4.8.2.
There is a bit mistake:
...
virtual bool supportsExtension(Extension extension) const // const!!!
{
return QWebPage::ErrorPageExtension === extension;
}
...
You forgot to copy the const modifier.

Qt QWebView class custom User-Agent

Is there an easy way to setup the User-Agent the QWebView class is using?
The only relevant link I found searching was this
http://www.qtforum.org/article/27073/how-to-set-user-agent-in-qwebview.html
I'm learning C++/Qt right now and I don't really understant what's explained on that website. Maybe someone knows an easy way to do it? Or can help me understand that code?
Qt allows you to provide a user agent based on the URL rather than a single user agent no matter what the URL is. The idea then is to return the user agent any time a new webpage is created:
class UserAgentWebPage : public QWebPage {
QString userAgentForUrl(const QUrl &url ) const {
return QString("My User Agent");
}
};
In order to use that page instead of the standard page that is created, you can set that page on the browser control object before making the request:
yourWebView->setPage(new UserAgentWebPage(parent));
I would actually expect a factory to be present somewhere that will guarantee that the webpage created is always of a certain type, but I didn't see one.
Yet another option should be to set the user agent header within the QNetworkRequest:
QNetworkRequest request = new QNetworkRequest();
request->setRawHeader(
QString("User-Agent").toAscii(),
QString("Your User Agent").toAscii()
);
// ... set the URL, etc.
yourWebView->load(request);
You would actually want to check whether it's toAscii() or toUtf8() or one of the other variants as I'm not sure exactly what the HTTP standard allows.
simply,
class myWebPage : public QWebPage
{
virtual QString userAgentForUrl(const QUrl& url) const {
return "your user agent";
}
};
//Attention here is new myWebPage() not new myWebPage(parent)
UI->webView->setPage(new myWebPage());

Resources