mirror of
https://gitflic.ru/project/astankevich/mtpview.git
synced 2024-11-23 06:58:25 +01:00
Initial commit. It includes a batch of changes because develop starts without git.
This commit is contained in:
commit
c6b7eea1b5
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
(Objects.mtpview)
|
||||
mtpview
|
||||
mtpview.hpkg
|
||||
pkg/apps/mtpview
|
326
App.cpp
Normal file
326
App.cpp
Normal file
@ -0,0 +1,326 @@
|
||||
#include "App.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
//#include "common.h"
|
||||
#include <libmtp.h>
|
||||
//#include "util.h"
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
App *app;
|
||||
MainWindow *mainwin;
|
||||
LIBMTP_mtpdevice_t *detected_device=0;
|
||||
|
||||
int progress (uint64_t const sent, uint64_t const total,
|
||||
void const * const data)
|
||||
{
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find the file type based on extension */
|
||||
LIBMTP_filetype_t
|
||||
find_filetype (const char * filename)
|
||||
{
|
||||
char *ptype;
|
||||
LIBMTP_filetype_t filetype;
|
||||
|
||||
#ifdef __WIN32__
|
||||
ptype = strrchr(filename, '.');
|
||||
#else
|
||||
ptype = rindex(filename,'.');
|
||||
#endif
|
||||
// This accounts for the case with a filename without any "." (period).
|
||||
if (!ptype) {
|
||||
ptype = "";
|
||||
} else {
|
||||
++ptype;
|
||||
}
|
||||
|
||||
/* This need to be kept constantly updated as new file types arrive. */
|
||||
if (!strcasecmp (ptype, "wav")) {
|
||||
filetype = LIBMTP_FILETYPE_WAV;
|
||||
} else if (!strcasecmp (ptype, "mp3")) {
|
||||
filetype = LIBMTP_FILETYPE_MP3;
|
||||
} else if (!strcasecmp (ptype, "wma")) {
|
||||
filetype = LIBMTP_FILETYPE_WMA;
|
||||
} else if (!strcasecmp (ptype, "ogg")) {
|
||||
filetype = LIBMTP_FILETYPE_OGG;
|
||||
} else if (!strcasecmp (ptype, "mp4")) {
|
||||
filetype = LIBMTP_FILETYPE_MP4;
|
||||
} else if (!strcasecmp (ptype, "wmv")) {
|
||||
filetype = LIBMTP_FILETYPE_WMV;
|
||||
} else if (!strcasecmp (ptype, "avi")) {
|
||||
filetype = LIBMTP_FILETYPE_AVI;
|
||||
} else if (!strcasecmp (ptype, "mpeg") || !strcasecmp (ptype, "mpg")) {
|
||||
filetype = LIBMTP_FILETYPE_MPEG;
|
||||
} else if (!strcasecmp (ptype, "asf")) {
|
||||
filetype = LIBMTP_FILETYPE_ASF;
|
||||
} else if (!strcasecmp (ptype, "qt") || !strcasecmp (ptype, "mov")) {
|
||||
filetype = LIBMTP_FILETYPE_QT;
|
||||
} else if (!strcasecmp (ptype, "wma")) {
|
||||
filetype = LIBMTP_FILETYPE_WMA;
|
||||
} else if (!strcasecmp (ptype, "jpg") || !strcasecmp (ptype, "jpeg")) {
|
||||
filetype = LIBMTP_FILETYPE_JPEG;
|
||||
} else if (!strcasecmp (ptype, "jfif")) {
|
||||
filetype = LIBMTP_FILETYPE_JFIF;
|
||||
} else if (!strcasecmp (ptype, "tif") || !strcasecmp (ptype, "tiff")) {
|
||||
filetype = LIBMTP_FILETYPE_TIFF;
|
||||
} else if (!strcasecmp (ptype, "bmp")) {
|
||||
filetype = LIBMTP_FILETYPE_BMP;
|
||||
} else if (!strcasecmp (ptype, "gif")) {
|
||||
filetype = LIBMTP_FILETYPE_GIF;
|
||||
} else if (!strcasecmp (ptype, "pic") || !strcasecmp (ptype, "pict")) {
|
||||
filetype = LIBMTP_FILETYPE_PICT;
|
||||
} else if (!strcasecmp (ptype, "png")) {
|
||||
filetype = LIBMTP_FILETYPE_PNG;
|
||||
} else if (!strcasecmp (ptype, "wmf")) {
|
||||
filetype = LIBMTP_FILETYPE_WINDOWSIMAGEFORMAT;
|
||||
} else if (!strcasecmp (ptype, "ics")) {
|
||||
filetype = LIBMTP_FILETYPE_VCALENDAR2;
|
||||
} else if (!strcasecmp (ptype, "exe") || !strcasecmp (ptype, "com") ||
|
||||
!strcasecmp (ptype, "bat") || !strcasecmp (ptype, "dll") ||
|
||||
!strcasecmp (ptype, "sys")) {
|
||||
filetype = LIBMTP_FILETYPE_WINEXEC;
|
||||
} else if (!strcasecmp (ptype, "aac")) {
|
||||
filetype = LIBMTP_FILETYPE_AAC;
|
||||
} else if (!strcasecmp (ptype, "mp2")) {
|
||||
filetype = LIBMTP_FILETYPE_MP2;
|
||||
} else if (!strcasecmp (ptype, "flac")) {
|
||||
filetype = LIBMTP_FILETYPE_FLAC;
|
||||
} else if (!strcasecmp (ptype, "m4a")) {
|
||||
filetype = LIBMTP_FILETYPE_M4A;
|
||||
} else if (!strcasecmp (ptype, "doc")) {
|
||||
filetype = LIBMTP_FILETYPE_DOC;
|
||||
} else if (!strcasecmp (ptype, "xml")) {
|
||||
filetype = LIBMTP_FILETYPE_XML;
|
||||
} else if (!strcasecmp (ptype, "xls")) {
|
||||
filetype = LIBMTP_FILETYPE_XLS;
|
||||
} else if (!strcasecmp (ptype, "ppt")) {
|
||||
filetype = LIBMTP_FILETYPE_PPT;
|
||||
} else if (!strcasecmp (ptype, "mht")) {
|
||||
filetype = LIBMTP_FILETYPE_MHT;
|
||||
} else if (!strcasecmp (ptype, "jp2")) {
|
||||
filetype = LIBMTP_FILETYPE_JP2;
|
||||
} else if (!strcasecmp (ptype, "jpx")) {
|
||||
filetype = LIBMTP_FILETYPE_JPX;
|
||||
} else if (!strcasecmp (ptype, "bin")) {
|
||||
filetype = LIBMTP_FILETYPE_FIRMWARE;
|
||||
} else if (!strcasecmp (ptype, "vcf")) {
|
||||
filetype = LIBMTP_FILETYPE_VCARD3;
|
||||
} else {
|
||||
/* Tagging as unknown file type */
|
||||
filetype = LIBMTP_FILETYPE_UNKNOWN;
|
||||
}
|
||||
printf("type: %s, %d\n", ptype, filetype);
|
||||
return filetype;
|
||||
}
|
||||
|
||||
static char *basename(char *in) {
|
||||
char *p;
|
||||
|
||||
if (in == NULL)
|
||||
return NULL;
|
||||
p = in + strlen(in) - 1;
|
||||
while (*p != '\\' && *p != '/' && *p != ':')
|
||||
{ p--; }
|
||||
return ++p;
|
||||
}
|
||||
|
||||
int sendfile_function(char * from_path, int32_t parent_id)
|
||||
{
|
||||
//printf("Sending %s to %s\n",from_path,to_path);
|
||||
char *filename;
|
||||
uint64_t filesize;
|
||||
struct stat sb;
|
||||
LIBMTP_file_t *genfile;
|
||||
int ret;
|
||||
//uint32_t parent_id = 0;
|
||||
|
||||
if ( stat(from_path, &sb) == -1 ) {
|
||||
fprintf(stderr, "%s: ", from_path);
|
||||
perror("stat");
|
||||
return 1;
|
||||
}
|
||||
|
||||
filesize = sb.st_size;
|
||||
filename = basename(from_path);
|
||||
//parent_id = parse_path (to_path,files,folders);
|
||||
if (parent_id == -1) {
|
||||
printf("Parent folder could not be found, skipping\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
genfile = LIBMTP_new_file_t();
|
||||
genfile->filesize = filesize;
|
||||
genfile->filename = strdup(filename);
|
||||
genfile->filetype = find_filetype (filename);
|
||||
genfile->parent_id = parent_id;
|
||||
genfile->storage_id = 0;
|
||||
|
||||
printf("Sending file...\n");
|
||||
ret = LIBMTP_Send_File_From_File(detected_device, from_path, genfile, progress, NULL);
|
||||
printf("\n");
|
||||
if (ret != 0) {
|
||||
printf("Error sending file.\n");
|
||||
LIBMTP_Dump_Errorstack(detected_device);
|
||||
LIBMTP_Clear_Errorstack(detected_device);
|
||||
ret = 1;
|
||||
} else {
|
||||
printf("New file ID: %d\n", genfile->item_id);
|
||||
}
|
||||
|
||||
LIBMTP_destroy_file_t(genfile);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Clever prototype to be able to recurse */
|
||||
void recursive_file_tree(LIBMTP_mtpdevice_t *,
|
||||
LIBMTP_devicestorage_t *,
|
||||
uint32_t,
|
||||
int);
|
||||
|
||||
void recursive_file_tree(LIBMTP_mtpdevice_t *device,
|
||||
LIBMTP_devicestorage_t *storage,
|
||||
uint32_t leaf,
|
||||
int depth)
|
||||
{
|
||||
LIBMTP_file_t *files;
|
||||
LIBMTP_file_t *file;
|
||||
|
||||
files = LIBMTP_Get_Files_And_Folders(device,
|
||||
storage->id,
|
||||
leaf);
|
||||
if (files == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Iterate over the filelisting */
|
||||
file = files;
|
||||
while (file != NULL) {
|
||||
LIBMTP_file_t *oldfile;
|
||||
if (strcmp(file->filename, "Android")!=0) //skip system folder
|
||||
{
|
||||
|
||||
/* Indent */
|
||||
/*
|
||||
int i;
|
||||
for (i = 0; i < depth; i++) {
|
||||
printf(" ");
|
||||
}
|
||||
printf("%u %s\n", file->item_id, file->filename);*/
|
||||
mainwin->listView()->AddItem(new FileItem(device,
|
||||
file->item_id,
|
||||
file->filename,
|
||||
file->filetype != LIBMTP_FILETYPE_FOLDER,
|
||||
depth));
|
||||
if (file->filetype == LIBMTP_FILETYPE_FOLDER) {
|
||||
recursive_file_tree(device, storage, file->item_id, depth+2);
|
||||
}
|
||||
}
|
||||
oldfile = file;
|
||||
file = file->next;
|
||||
LIBMTP_destroy_file_t(oldfile);
|
||||
}
|
||||
}
|
||||
|
||||
int init_mtp (/*int argc, char **argv*/)
|
||||
{
|
||||
LIBMTP_raw_device_t * rawdevices;
|
||||
int numrawdevices;
|
||||
LIBMTP_error_number_t err;
|
||||
int i;
|
||||
|
||||
|
||||
LIBMTP_Init();
|
||||
|
||||
err = LIBMTP_Detect_Raw_Devices(&rawdevices, &numrawdevices);
|
||||
switch(err) {
|
||||
case LIBMTP_ERROR_NO_DEVICE_ATTACHED:
|
||||
fprintf(stdout, " No raw devices found.\n");
|
||||
return 0;
|
||||
case LIBMTP_ERROR_CONNECTING:
|
||||
fprintf(stderr, "Detect: There has been an error connecting. Exiting\n");
|
||||
return 1;
|
||||
case LIBMTP_ERROR_MEMORY_ALLOCATION:
|
||||
fprintf(stderr, "Detect: Encountered a Memory Allocation Error. Exiting\n");
|
||||
return 1;
|
||||
case LIBMTP_ERROR_NONE:
|
||||
break;
|
||||
case LIBMTP_ERROR_GENERAL:
|
||||
default:
|
||||
fprintf(stderr, "Unknown connection error.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Iterate over connected MTP devices */
|
||||
fprintf(stdout, "Attempting to connect device(s)\n");
|
||||
for (i = 0; i < numrawdevices; i++) {
|
||||
LIBMTP_mtpdevice_t *device;
|
||||
LIBMTP_devicestorage_t *storage;
|
||||
char *friendlyname;
|
||||
int ret;
|
||||
|
||||
device = LIBMTP_Open_Raw_Device_Uncached(&rawdevices[i]);
|
||||
if (device == NULL) {
|
||||
fprintf(stderr, "Unable to open raw device %d\n", i);
|
||||
continue;
|
||||
}
|
||||
detected_device = device;
|
||||
LIBMTP_Dump_Errorstack(device);
|
||||
LIBMTP_Clear_Errorstack(device);
|
||||
|
||||
friendlyname = LIBMTP_Get_Friendlyname(device);
|
||||
if (friendlyname == NULL) {
|
||||
printf("Device: (NULL)\n");
|
||||
} else {
|
||||
printf("Device: %s\n", friendlyname);
|
||||
//LIBMTP_FreeMemory(friendlyname);
|
||||
}
|
||||
|
||||
/* Get all storages for this device */
|
||||
ret = LIBMTP_Get_Storage(device, LIBMTP_STORAGE_SORTBY_NOTSORTED);
|
||||
if (ret != 0) {
|
||||
perror("LIBMTP_Get_Storage()");
|
||||
goto bailout;
|
||||
}
|
||||
|
||||
/* Loop over storages */
|
||||
for (storage = device->storage; storage != 0; storage = storage->next) {
|
||||
fprintf(stdout, "Storage: %s\n", storage->StorageDescription);
|
||||
recursive_file_tree(device, storage, LIBMTP_FILES_AND_FOLDERS_ROOT, 0);
|
||||
}
|
||||
continue; //do not release device because later use
|
||||
bailout:
|
||||
LIBMTP_Release_Device(device);
|
||||
|
||||
} /* End For Loop */
|
||||
|
||||
//LIBMTP_FreeMemory(rawdevices); missing in current libmtp.h
|
||||
|
||||
printf("OK.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
App::App(void)
|
||||
: BApplication("application/x-vnd.dw-ListColors")
|
||||
{
|
||||
mainwin = new MainWindow();
|
||||
init_mtp();
|
||||
mainwin->Show();
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
app = new App();
|
||||
app->Run();
|
||||
delete app;
|
||||
return 0;
|
||||
}
|
12
App.h
Normal file
12
App.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef APP_H
|
||||
#define APP_H
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
class App : public BApplication
|
||||
{
|
||||
public:
|
||||
App(void);
|
||||
};
|
||||
|
||||
#endif
|
244
MainWindow.cpp
Normal file
244
MainWindow.cpp
Normal file
@ -0,0 +1,244 @@
|
||||
#include <libmtp.h>
|
||||
#include "App.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <Button.h>
|
||||
#include <ListItem.h>
|
||||
#include <ScrollView.h>
|
||||
#include <Path.h>
|
||||
|
||||
//extern LIBMTP_mtpdevice_t * detected_device;
|
||||
//extern App *app;
|
||||
//extern LIBMTP_mtpdevice_t *detected_device=0;
|
||||
int sendfile_function(char * from_path, int32_t parent_id);
|
||||
int progress (uint64_t const sent, uint64_t const total,
|
||||
void const * const data);
|
||||
|
||||
enum
|
||||
{
|
||||
M_DOWNLOAD_FILE = 'dlfl',
|
||||
M_UPLOAD_FILE = 'upfl',
|
||||
M_SET_TITLE = 'sttl'
|
||||
};
|
||||
|
||||
FileItem::FileItem(LIBMTP_mtpdevice_t * device, int id, BString filename, bool isFile, int depth)
|
||||
:BStringItem(filename, depth, false)
|
||||
{
|
||||
this->fDevice=device;
|
||||
this->fId=id;
|
||||
this->fIsFile=isFile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
MainWindow::MainWindow(void)
|
||||
: BWindow(BRect(100,100,500,400),"MTP view",B_TITLED_WINDOW,
|
||||
B_ASYNCHRONOUS_CONTROLS | B_QUIT_ON_WINDOW_CLOSE)
|
||||
{
|
||||
// Here we will make a BView that covers the white area so that we can set the
|
||||
// "background color"
|
||||
BRect r(Bounds());
|
||||
BView *top = new BView(r,"topview",B_FOLLOW_ALL,B_WILL_DRAW);
|
||||
AddChild(top);
|
||||
|
||||
// ui_color() returns a system color, such as the window tab color, menu text color,
|
||||
// and so forth.
|
||||
top->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
|
||||
|
||||
// Create a button and place it at the bottom right corner of the window. The empty BRect
|
||||
// that we use for the BButton's frame is because we're going to have it resize itself and
|
||||
// then move it to the corner based on the actual size of the button
|
||||
download = new BButton(BRect(),"downloadbutton","Download", new BMessage(M_DOWNLOAD_FILE),
|
||||
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
|
||||
download->SetEnabled(false);
|
||||
top->AddChild(download);
|
||||
download->ResizeToPreferred();
|
||||
|
||||
upload = new BButton(BRect(),"uploadbutton","Upload", new BMessage(M_UPLOAD_FILE),
|
||||
B_FOLLOW_RIGHT | B_FOLLOW_BOTTOM);
|
||||
top->AddChild(upload);
|
||||
upload->ResizeToPreferred();
|
||||
|
||||
// Bottom right corner of the window with 10 pixels of padding between the button and the
|
||||
// window edge. 10 pixels is kind of a de facto standard for control padding.
|
||||
download->MoveTo(Bounds().right - download->Bounds().Width() - 10.0,
|
||||
Bounds().bottom - download->Bounds().Height() - 10.0);
|
||||
|
||||
upload->MoveTo(Bounds().right - download->Bounds().Width()-upload->Bounds().Width() - 20.0,
|
||||
Bounds().bottom - upload->Bounds().Height() - 10.0);
|
||||
|
||||
r = Bounds();
|
||||
r.InsetBy(10.0,10.0);
|
||||
|
||||
// When working with BScrollViews, you must compensate for the width/height of the scrollbars.
|
||||
// B_V_SCROLL_BAR_WIDTH is a defined constant for the width of the vertical scroll bar.
|
||||
r.right -= B_V_SCROLL_BAR_WIDTH;
|
||||
|
||||
// Frame() works like Bounds() except that it returns the size and location of the control
|
||||
// in the coordinate space of the parent view. This will make fListView's bottom stop 10
|
||||
// pixels above the button.
|
||||
r.bottom = download->Frame().top - 10.0 - B_H_SCROLL_BAR_HEIGHT;
|
||||
|
||||
// Most of these parameters are exactly the same as for BView except that we can also
|
||||
// specify whether the user is able to select just 1 item in the list or multiple items by
|
||||
// clicking on items while holding a modifier key on the keyboard.
|
||||
fListView = new BOutlineListView(r,"sportlist",B_SINGLE_SELECTION_LIST,B_FOLLOW_ALL);
|
||||
|
||||
// We didn't call AddChild on fListView because our BScrollView will do that for us. When
|
||||
// created, it creates scrollbars and targets the specified view for any scrolling they do.
|
||||
// When the BScrollView is attached to the window, it calls AddChild on fListView for us.
|
||||
|
||||
// If we call AddChild on fListView before we create this scrollview, our program will drop
|
||||
// to the debugger when we call AddChild on the BScrollView -- a BView can have only one parent.
|
||||
BScrollView *scrollView = new BScrollView("scrollview",fListView, B_FOLLOW_ALL, 0,true,true);
|
||||
top->AddChild(scrollView);
|
||||
|
||||
// A BListView's selection message is sent to the window any time that the list's selection
|
||||
// changes.
|
||||
fListView->SetSelectionMessage(new BMessage(M_SET_TITLE));
|
||||
|
||||
messenger = new BMessenger(this);
|
||||
|
||||
openPanel = new BFilePanel(B_OPEN_PANEL, messenger, NULL, B_FILE_NODE, false);
|
||||
//savePanel = new BFilePanel(B_SAVE_PANEL, messenger, NULL, B_DIRECTORY_NODE, false); //B_DIRECTORY_NODE has no effect
|
||||
savePanel = new BFilePanel(B_SAVE_PANEL, messenger, NULL, B_FILE_NODE, false);
|
||||
selectedItem = NULL;
|
||||
|
||||
//openPanel->SetTarget(messenger);
|
||||
//savePanel->SetTarget(messenger);
|
||||
printf("MainWindow created\n" );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
MainWindow::MessageReceived(BMessage *msg)
|
||||
{
|
||||
switch (msg->what)
|
||||
{
|
||||
case M_DOWNLOAD_FILE:
|
||||
{
|
||||
int32 selection = fListView->CurrentSelection();
|
||||
|
||||
if (selection < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
selectedItem = (FileItem*)fListView->ItemAt(selection);
|
||||
if (selectedItem) {
|
||||
printf("Show save dialog\n" );
|
||||
savePanel->SetSaveText(selectedItem->Text());
|
||||
savePanel->Show();
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
case M_UPLOAD_FILE:
|
||||
{
|
||||
int32 selection = fListView->CurrentSelection();
|
||||
|
||||
if (selection < 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
selectedItem = (FileItem*)fListView->ItemAt(selection);
|
||||
if (selectedItem) {
|
||||
printf("Show open dialog\n" );
|
||||
openPanel->Show();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case M_SET_TITLE:
|
||||
{
|
||||
int32 selection = fListView->CurrentSelection();
|
||||
|
||||
if (selection < 0)
|
||||
{
|
||||
// This code is here because when we press the Reset button, the selection
|
||||
// changes and an M_SET_TITLE message is sent, but because nothing is
|
||||
// selected, CurrentSelection() returns -1.
|
||||
SetTitle("MTP view");
|
||||
selectedItem = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
//BStringItem *item = dynamic_cast<BStringItem*>(fListView->ItemAt(selection));
|
||||
selectedItem = (FileItem*)fListView->ItemAt(selection);
|
||||
if (selectedItem)
|
||||
{
|
||||
SetTitle(selectedItem->Text());
|
||||
download->SetEnabled(selectedItem->isFile());
|
||||
upload->SetEnabled(!selectedItem->isFile());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case B_REFS_RECEIVED:{
|
||||
printf(" User select Open\n" );
|
||||
if (selectedItem) {
|
||||
entry_ref ref;
|
||||
if (msg->FindRef("refs", &ref) == B_OK) {
|
||||
BEntry entry;
|
||||
if (entry.SetTo(&ref) == B_OK) {
|
||||
BPath path;
|
||||
entry.GetPath(&path);
|
||||
char openFileName[B_FILE_NAME_LENGTH];
|
||||
strcpy(openFileName, path.Path());
|
||||
|
||||
printf("Try to upload %s to dir %d %s\n", openFileName, selectedItem->fileId(), selectedItem->Text());
|
||||
sendfile_function(openFileName, selectedItem->fileId());
|
||||
}
|
||||
}
|
||||
else
|
||||
printf(" No refs in message\n" );
|
||||
}
|
||||
break;
|
||||
}
|
||||
case B_SAVE_REQUESTED:
|
||||
{
|
||||
printf(" User select Save\n" );
|
||||
|
||||
if (selectedItem) {
|
||||
entry_ref ref;
|
||||
if (msg->FindRef("directory", &ref) == B_OK) {
|
||||
BEntry entry;
|
||||
if (entry.SetTo(&ref) == B_OK) {
|
||||
BPath path;
|
||||
entry.GetPath(&path);
|
||||
char fullSaveFileName [B_FILE_NAME_LENGTH];
|
||||
const char * shortSaveFileName = NULL;// [B_FILE_NAME_LENGTH];
|
||||
strcpy (fullSaveFileName, path.Path());
|
||||
strcat(fullSaveFileName, "/");
|
||||
|
||||
if (msg->FindString("name", &shortSaveFileName) == B_OK) {
|
||||
strcat(fullSaveFileName, shortSaveFileName);
|
||||
}
|
||||
//strcat(fullSaveFileName, selectedItem->Text());
|
||||
|
||||
printf("Try to download %d %s to %s\n", selectedItem->fileId(), selectedItem->Text(), fullSaveFileName);
|
||||
if (LIBMTP_Get_File_To_File(selectedItem->device(), selectedItem->fileId(),
|
||||
/*selectedItem->Text()*/ fullSaveFileName, progress, NULL) != 0 ){
|
||||
printf("\nError getting file from MTP device.\n");
|
||||
LIBMTP_Dump_Errorstack(selectedItem->device());
|
||||
LIBMTP_Clear_Errorstack(selectedItem->device());
|
||||
|
||||
} else
|
||||
printf("OK\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case B_CANCEL:
|
||||
{
|
||||
printf(" User select Cancel\n" );
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
BWindow::MessageReceived(msg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
41
MainWindow.h
Normal file
41
MainWindow.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <Window.h>
|
||||
#include <OutlineListView.h>
|
||||
#include <FilePanel.h>
|
||||
#include <Messenger.h>
|
||||
#include <libmtp.h>
|
||||
|
||||
class FileItem: public BStringItem
|
||||
{
|
||||
public:
|
||||
FileItem(LIBMTP_mtpdevice_t * device, int id, BString filename, bool isFile, int depth);
|
||||
inline int fileId(){return fId;}
|
||||
inline bool isFile(){return fIsFile;}
|
||||
inline LIBMTP_mtpdevice_t * device(){return this->fDevice;}
|
||||
private:
|
||||
int fId;
|
||||
bool fIsFile;
|
||||
LIBMTP_mtpdevice_t * fDevice;
|
||||
};
|
||||
|
||||
class MainWindow : public BWindow
|
||||
{
|
||||
public:
|
||||
MainWindow(void);
|
||||
void MessageReceived(BMessage *msg);
|
||||
inline BOutlineListView * listView(){return this->fListView;};
|
||||
|
||||
private:
|
||||
BOutlineListView *fListView;
|
||||
BButton *download;
|
||||
BButton *upload;
|
||||
BFilePanel* openPanel;
|
||||
BFilePanel* savePanel;
|
||||
BMessenger * messenger;
|
||||
|
||||
FileItem * selectedItem;
|
||||
};
|
||||
|
||||
#endif
|
130
Makefile
Normal file
130
Makefile
Normal file
@ -0,0 +1,130 @@
|
||||
## Haiku Generic Makefile v2.6 ##
|
||||
|
||||
## Fill in this file to specify the project being created, and the referenced
|
||||
## Makefile-Engine will do all of the hard work for you. This handles any
|
||||
## architecture of Haiku.
|
||||
|
||||
# The name of the binary.
|
||||
NAME = mtpview
|
||||
TARGET_DIR = .
|
||||
|
||||
# The type of binary, must be one of:
|
||||
# APP: Application
|
||||
# SHARED: Shared library or add-on
|
||||
# STATIC: Static library archive
|
||||
# DRIVER: Kernel driver
|
||||
TYPE = APP
|
||||
|
||||
# If you plan to use localization, specify the application's MIME signature.
|
||||
APP_MIME_SIG =
|
||||
|
||||
# The following lines tell Pe and Eddie where the SRCS, RDEFS, and RSRCS are
|
||||
# so that Pe and Eddie can fill them in for you.
|
||||
#%{
|
||||
# @src->@
|
||||
|
||||
# Specify the source files to use. Full paths or paths relative to the
|
||||
# Makefile can be included. All files, regardless of directory, will have
|
||||
# their object files created in the common object directory. Note that this
|
||||
# means this Makefile will not work correctly if two source files with the
|
||||
# same name (source.c or source.cpp) are included from different directories.
|
||||
# Also note that spaces in folder names do not work well with this Makefile.
|
||||
SRCS = App.cpp \
|
||||
MainWindow.cpp
|
||||
|
||||
# Specify the resource definition files to use. Full or relative paths can be
|
||||
# used.
|
||||
RDEFS =
|
||||
|
||||
# Specify the resource files to use. Full or relative paths can be used.
|
||||
# Both RDEFS and RSRCS can be utilized in the same Makefile.
|
||||
RSRCS =
|
||||
|
||||
# End Pe/Eddie support.
|
||||
# @<-src@
|
||||
#%}
|
||||
|
||||
# Specify libraries to link against.
|
||||
# There are two acceptable forms of library specifications:
|
||||
# - if your library follows the naming pattern of libXXX.so or libXXX.a,
|
||||
# you can simply specify XXX for the library. (e.g. the entry for
|
||||
# "libtracker.so" would be "tracker")
|
||||
#
|
||||
# - for GCC-independent linking of standard C++ libraries, you can use
|
||||
# $(STDCPPLIBS) instead of the raw "stdc++[.r4] [supc++]" library names.
|
||||
#
|
||||
# - if your library does not follow the standard library naming scheme,
|
||||
# you need to specify the path to the library and it's name.
|
||||
# (e.g. for mylib.a, specify "mylib.a" or "path/mylib.a")
|
||||
LIBS = /boot/system/develop/lib/libbe.so \
|
||||
/boot/system/develop/lib/libmtp.so \
|
||||
/boot/system/develop/lib/libtracker.so
|
||||
|
||||
# Specify additional paths to directories following the standard libXXX.so
|
||||
# or libXXX.a naming scheme. You can specify full paths or paths relative
|
||||
# to the Makefile. The paths included are not parsed recursively, so
|
||||
# include all of the paths where libraries must be found. Directories where
|
||||
# source files were specified are automatically included.
|
||||
LIBPATHS =
|
||||
|
||||
# Additional paths to look for system headers. These use the form
|
||||
# "#include <header>". Directories that contain the files in SRCS are
|
||||
# NOT auto-included here.
|
||||
SYSTEM_INCLUDE_PATHS = /boot/system/develop/headers \
|
||||
/boot/system/develop/headers/be \
|
||||
/boot/system/develop/headers/cpp \
|
||||
/boot/system/develop/headers/posix
|
||||
|
||||
# Additional paths paths to look for local headers. These use the form
|
||||
# #include "header". Directories that contain the files in SRCS are
|
||||
# automatically included.
|
||||
LOCAL_INCLUDE_PATHS = .
|
||||
|
||||
# Specify the level of optimization that you want. Specify either NONE (O0),
|
||||
# SOME (O1), FULL (O2), or leave blank (for the default optimization level).
|
||||
OPTIMIZE := NONE
|
||||
|
||||
# Specify the codes for languages you are going to support in this
|
||||
# application. The default "en" one must be provided too. "make catkeys"
|
||||
# will recreate only the "locales/en.catkeys" file. Use it as a template
|
||||
# for creating catkeys for other languages. All localization files must be
|
||||
# placed in the "locales" subdirectory.
|
||||
LOCALES =
|
||||
|
||||
# Specify all the preprocessor symbols to be defined. The symbols will not
|
||||
# have their values set automatically; you must supply the value (if any) to
|
||||
# use. For example, setting DEFINES to "DEBUG=1" will cause the compiler
|
||||
# option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" would pass
|
||||
# "-DDEBUG" on the compiler's command line.
|
||||
DEFINES =
|
||||
|
||||
# Specify the warning level. Either NONE (suppress all warnings),
|
||||
# ALL (enable all warnings), or leave blank (enable default warnings).
|
||||
WARNINGS =
|
||||
|
||||
# With image symbols, stack crawls in the debugger are meaningful.
|
||||
# If set to "TRUE", symbols will be created.
|
||||
SYMBOLS :=
|
||||
|
||||
# Includes debug information, which allows the binary to be debugged easily.
|
||||
# If set to "TRUE", debug info will be created.
|
||||
DEBUGGER :=
|
||||
|
||||
# Specify any additional compiler flags to be used.
|
||||
COMPILER_FLAGS =
|
||||
|
||||
# Specify any additional linker flags to be used.
|
||||
LINKER_FLAGS =
|
||||
|
||||
# (Only used when "TYPE" is "DRIVER"). Specify the desired driver install
|
||||
# location in the /dev hierarchy. Example:
|
||||
# DRIVER_PATH = video/usb
|
||||
# will instruct the "driverinstall" rule to place a symlink to your driver's
|
||||
# binary in ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will
|
||||
# appear at /dev/video/usb when loaded. The default is "misc".
|
||||
DRIVER_PATH =
|
||||
|
||||
## Include the Makefile-Engine
|
||||
DEVEL_DIRECTORY := \
|
||||
$(shell findpaths -r "makefile_engine" B_FIND_PATH_DEVELOP_DIRECTORY)
|
||||
include $(DEVEL_DIRECTORY)/etc/makefile-engine
|
7
README.md
Normal file
7
README.md
Normal file
@ -0,0 +1,7 @@
|
||||
## Description
|
||||
Haiku's app to show a MTP-compilant device context and download/upload selected file to/from choosed location.
|
||||
Note: Skip Android folder on device for perfomance.
|
||||
|
||||
## Compiling
|
||||
Required: libmtp
|
||||
Open moex_view.pld with Paladin. Choose Build->Make project.
|
13
changelog_ru.txt
Normal file
13
changelog_ru.txt
Normal file
@ -0,0 +1,13 @@
|
||||
5 июля 2023:
|
||||
Убран вывод дерева файлов в консоль в целях повышения производительности.
|
||||
Добавлено включение/выключение кнопки Download в зависимости от того что выбрано : файл или каталог.
|
||||
Добавлен тестовый функционал для загрузки файлов на устройство.
|
||||
|
||||
18 июля 2023:
|
||||
Добавлены диалоги открытия и сохранения файлов, а также соответствующие обработчики событий.
|
||||
|
||||
31 июля 2023:
|
||||
Создана директория pkg с .PackageInfo и соотвествующей структурой. Файл mtpview в настоящее время нужно скопировать вручную в директорию apps.
|
||||
|
||||
9 сентября 2024:
|
||||
Реализованы корректные обрабочики событий от диалогов загрузки и сохранения.
|
3
compile_commands.json
Normal file
3
compile_commands.json
Normal file
@ -0,0 +1,3 @@
|
||||
[
|
||||
|
||||
]
|
9
create_package.sh
Executable file
9
create_package.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/usr/bin/sh
|
||||
|
||||
#Update binary
|
||||
cp mtpview pkg/apps/mtpview
|
||||
|
||||
#Create package
|
||||
pushd pkg
|
||||
package create -C ./ ../mtpview.hpkg
|
||||
popd
|
26
mtpview.pld
Normal file
26
mtpview.pld
Normal file
@ -0,0 +1,26 @@
|
||||
NAME=MTP_view
|
||||
TARGETNAME=mtpview
|
||||
PLATFORM=HaikuGCC4
|
||||
SCM=none
|
||||
GROUP=Source files
|
||||
EXPANDGROUP=yes
|
||||
SOURCEFILE=App.cpp
|
||||
DEPENDENCY=MainWindow.h
|
||||
SOURCEFILE=MainWindow.cpp
|
||||
DEPENDENCY=App.h MainWindow.h
|
||||
LOCALINCLUDE=.
|
||||
SYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY
|
||||
SYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY/be
|
||||
SYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY/cpp
|
||||
SYSTEMINCLUDE=B_FIND_PATH_DEVELOP_HEADERS_DIRECTORY/posix
|
||||
LIBRARY=B_FIND_PATH_DEVELOP_LIB_DIRECTORY/libbe.so
|
||||
LIBRARY=B_FIND_PATH_DEVELOP_LIB_DIRECTORY/libmtp.so
|
||||
LIBRARY=B_FIND_PATH_DEVELOP_LIB_DIRECTORY/libtracker.so
|
||||
RUNARGS=
|
||||
CCDEBUG=yes
|
||||
CCPROFILE=no
|
||||
CCOPSIZE=no
|
||||
CCOPLEVEL=0
|
||||
CCTARGETTYPE=0
|
||||
CCEXTRA=
|
||||
LDEXTRA=
|
32
pkg/.PackageInfo
Normal file
32
pkg/.PackageInfo
Normal file
@ -0,0 +1,32 @@
|
||||
name mtpview
|
||||
version 0.1.1-1
|
||||
architecture x86_64
|
||||
summary "View android device contents"
|
||||
description "View android content through MTP protocol.
|
||||
* Upload file. Select dir in list and click UPload button. In dialog appeared select file on disk."
|
||||
packager "Anton Stankevich <ashc@mail.ru>"
|
||||
vendor "Anton Stankevich"
|
||||
licenses {
|
||||
"Apache v2"
|
||||
}
|
||||
copyrights {
|
||||
"2024 Anton Stankevich"
|
||||
}
|
||||
provides {
|
||||
mtpview = 0.1.1
|
||||
app:mtpview = 0.1.1
|
||||
}
|
||||
requires {
|
||||
haiku >= r1~beta4_hrev56578_4-1
|
||||
libmtp >= 1.1.19-2
|
||||
|
||||
}
|
||||
urls {
|
||||
"https://example.com"
|
||||
}
|
||||
source-urls {
|
||||
# Download
|
||||
"https://example.com"
|
||||
# Location 2
|
||||
"https://example.com"
|
||||
}
|
Loading…
Reference in New Issue
Block a user