0

I'm writing an app to tranfer files between an Android device and Mac. Tha File transfer is working but in terms of user experience I would like to add a progressbar to be able to see when the transfer is ended.

AS I'm transfering to an android device, I had to use a mtp stack. The function used to copy file is

LIBMTP_Send_File_From_File(device, path, genfile, ProgressBar, NULL);

ProgressBar is a callback function and the MTP stack is wrote in C.

My App is wrote in C++/Qt.

I have firstly design a progress bar and expected using a CONNECT/SIGNAL/SLOT Mecanism to update the progress bar but it's not working.

What I have done is in the dialog.h defined my callback:

extern "C" int ProgressBar(const uint64_t data_sent, const uint64_t data_total, void const * const data);

and a Class to design the Dialog box.

class Dialog : public QWidget
{
    Q_OBJECT
public:
    Dialog();
    void CreateProgressBar();
    void DestroyProgressBar();

private:
    QWidget *ProgressDialog;
    QProgressBar *ProgressIndicator;
    QVBoxLayout *ProgressLayout;

    QPushButton *CancelButton;

private slots:
    void onCancelButtonAction();
};

In the Dialog.c,

Dialog::Dialog()
{
}

void Dialog::CreateProgressBar() {
    ProgressDialog = new QWidget(this);
    ProgressDialog->setWindowTitle("Progress");

    ProgressLayout = new QVBoxLayout(this);

    ProgressIndicator = new QProgressBar();
    ProgressIndicator->resize(200,25);
    //ProgressIndicator->setrange(0,100);
    ProgressIndicator->setValue(0);
    ProgressIndicator->setOrientation(Qt::Horizontal);
    connect(ProgressIndicator,SIGNAL(ProgressBar(const uint64_t, const uint64_t, void const * const)),ProgressIndicator,SLOT(setValue(int)));

    CancelButton = new QPushButton();
    CancelButton->setFixedSize(25,25);
    CancelButton->setText("Cancel");
    CancelButton->setFlat(true);
    CancelButton->setAutoFillBackground(true);
    CancelButton->setStyleSheet("QPushButton { background-color : white;}");
    connect(CancelButton, SIGNAL(clicked()), this, SLOT(onCancelButtonAction()));

    ProgressLayout->addWidget(ProgressIndicator);
    ProgressLayout->addWidget(CancelButton);

    ProgressDialog->setLayout(ProgressLayout);
    ProgressDialog->show();
}

void Dialog::DestroyProgressBar() {
    ProgressDialog->close();
}

void Dialog::onCancelButtonAction() {
    DestroyProgressBar();
}

and the C code for "ProgressBar"

int ProgressBar(const uint64_t data_sent, const uint64_t data_total, void const * const data) {
    return (data_sent * 100) / data_total;
}

This basically not working because the connect reject to connect SIGNAL to ProgressBar because it's not a part of the class.

On other side, if I move ProgressBar in my class, the connect is ok but the code do not build because LIBMTP_Send reject the use of a class.

I'm calling the ProgressBar in LIBMTP_Send... using MyProgress.ProgressBar

    Dialog MyProgress;
    MyProgress.CreateProgressBar();

LIBMTP_Send_File_From_File(device, path, genfile, MyProgress.ProgressBar, NULL);

It's not working because I use a call to a method if my class instead of C callback

My method when trying to use the class instead of C code is defined as below:

int Dialog::ProgressBar(const uint64_t data_sent, const uint64_t data_total, void const * const data) {
    char* tmp_string;
    char* tmp_sent;
    char* tmp_total;

    if(ProgressIndicator.destroyed() == true)
        return true;

    if (ProgressIndicator != NULL) {

        ProgressIndicator->setValue();
    }

    if (progressDialog != NULL) {
        return (data_sent * 100) / data_total;
    }
    return 0;
}

In that case, I'm doing :

ret = LIBMTP_Send_File_From_File(PulsDeviceMngr->device, strdup(AbsolutePath), genfile, MyProgress.ProgressBar, NULL);

but the build error is : reference to non-static member function must be called

I'm creating the instance of the Dialog in the code who called the LIBMTP function as shown below:

  Dialog MyProgress;
  MyProgress.CreateProgressBar();

  genfile = LIBMTP_new_file_t();
  ...

  ret = LIBMTP_Send_File_From_File(PulsDeviceMngr->device, strdup(AbsolutePath), genfile, MyProgress.ProgressBar, NULL);

I'm really stucked... empty :-)

Seb
  • 2,929
  • 4
  • 30
  • 73

1 Answers1

1

To do that you will have to pass a pointer to the class as the argument of the callback in

LIBMTP_Send_File_From_File(device, path, genfile, MyProgress.ProgressBar, NULL);

the NULL argument is the callback argument

Dialog *MyProgress = new Dialog(parentWindow);
LIBMTP_Send_File_From_File(device, path, genfile, ProgressBar, MyProgress);
                                                              /* ^ here a pointer to */
                                                              /*   progress dialog   */

Note: parentWindow could be your QMainWindow and it's very important or you will have a memory leak.

then in the callback the data argument will point to the dialog, so you can do

Dialog *dialog = reinterpret_cast<Dialog *>(data);
dialog->setValue((data_sent * 100) / data_total);
Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • I have updated my code, but I do not see where to add the *dialog. Do I have to do it in the LIBMTP caller or my dialog.c code ? – Seb Jan 17 '15 at 01:05
  • @Seb where are you calling `LIBMTP_Send_File_From_File()`? – Iharob Al Asimi Jan 17 '15 at 01:05
  • in a file called mtp_wrapper.c the dialog box is also called here. and all data_sent. data, data_total are defined in the class dialog in dialog.h in the private section – Seb Jan 17 '15 at 01:06
  • is it a c file, how are you creating an instance of the dialog there? – Iharob Al Asimi Jan 17 '15 at 01:07
  • let me add the code. everything is C++ code event the wrapper. The wrapper include a call to the header of the MTP stack. I use a dynamic lib to have the mtp stack embedded in the app – Seb Jan 17 '15 at 01:08
  • code added to the description to show how it's called – Seb Jan 17 '15 at 01:11
  • the wrapper is used to create a c++ class/methods to connect the C stack for MTP and the C++/Qt app. – Seb Jan 17 '15 at 01:18
  • thanks but ProgressBar should be the C call or the method inside the Dialog class ? – Seb Jan 17 '15 at 02:01
  • it failed to build : Dialog *dialog = reinterpret_cast(data); reinterpret_cast from 'const void *' to Dialog * casts away qualifiers. the code is added in progressbar which is not inside the class but defined by the extern "C" – Seb Jan 17 '15 at 02:13
  • @Seb use `const_cast` instead. – Iharob Al Asimi Jan 17 '15 at 03:03
  • @Seb it doesn't matter you can also try to change both `const` qualifiers in the function signature... – Iharob Al Asimi Jan 17 '15 at 14:41