Subversion Repositories svn.mios32

Rev

Rev 1545 | Rev 1548 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1542 tk 1
/* -*- mode:C++; tab-width:4; c-basic-offset:4; indent-tabs-mode:nil -*- */
2
// $Id: MiosFileBrowser.cpp 1546 2012-11-26 17:43:15Z tk $
3
/*
4
 * File browser for MIOS32 applications
5
 *
6
 * ==========================================================================
7
 *
8
 *  Copyright (C) 2012 Thorsten Klose (tk@midibox.org)
9
 *  Licensed for personal non-commercial use only.
10
 *  All other rights reserved.
11
 *
12
 * ==========================================================================
13
 */
14
 
15
#include "MiosFileBrowser.h"
16
#include "MiosStudio.h"
17
 
18
//==============================================================================
19
class MiosFileBrowserFileItem
20
{
21
public:
1545 tk 22
    String parentPath;
1542 tk 23
    String name;
24
    bool isDirectory;
25
 
26
    OwnedArray<MiosFileBrowserFileItem> childs;
27
 
1545 tk 28
    MiosFileBrowserFileItem(String _parentPath, String _itemName, bool _isDirectory)
29
        : parentPath(_parentPath)
30
        , name(_itemName)
1542 tk 31
        , isDirectory(_isDirectory)
32
    {
33
    }
34
 
35
    ~MiosFileBrowserFileItem()
36
    {
37
    }
38
 
1545 tk 39
    MiosFileBrowserFileItem* createChild(String parentPath, String childName, bool isDirectory) {
40
        MiosFileBrowserFileItem* child = new MiosFileBrowserFileItem(parentPath, childName, isDirectory);
1542 tk 41
        childs.add(child);
1545 tk 42
        return child;
1542 tk 43
    }
44
};
45
 
46
 
47
//==============================================================================
48
class MiosFileBrowserItem : public TreeViewItem
49
{
50
public:
51
    MiosFileBrowserFileItem *fileItem;
52
    MiosFileBrowser* browser;
53
 
54
    MiosFileBrowserItem(MiosFileBrowserFileItem *_fileItem, MiosFileBrowser* _browser)
55
        : fileItem(_fileItem)
56
        , browser(_browser)
57
    {
58
    }
59
 
60
    ~MiosFileBrowserItem()
61
    {
62
    }
63
 
64
    int getItemWidth() const
65
    {
66
        return 100;
67
    }
68
 
69
    const String getUniqueName() const
70
    {
1545 tk 71
        if( fileItem->parentPath.compare(T("/")) == 0 ) {
72
            return T("/") + fileItem->name;
73
        } else {
74
            if( fileItem->name.compare(T("/")) == 0 )
75
                return T("/");
76
            else
77
                return fileItem->parentPath + T("/") + fileItem->name;
78
        }
1542 tk 79
    }
80
 
81
    bool mightContainSubItems()
82
    {
83
        return fileItem->isDirectory;
84
    }
85
 
86
    void paintItem (Graphics& g, int width, int height)
87
    {
88
        // if this item is selected, fill it with a background colour..
89
        if( isSelected() )
90
            g.fillAll(Colours::blue.withAlpha (0.3f));
91
 
92
        // use a "colour" attribute in the xml tag for this node to set the text colour..
93
        g.setColour(Colour(0xff000000));
94
 
95
        g.setFont(height * 0.7f);
96
 
97
        // draw the item name
98
        String name(fileItem->name);
99
        g.drawText(name,
100
                   4, 0, width - 4, height,
101
                   Justification::centredLeft, true);
102
    }
103
 
104
    void itemOpennessChanged (bool isNowOpen)
105
    {
106
        if( isNowOpen ) {
107
            // if we've not already done so, we'll now add the tree's sub-items. You could
108
            // also choose to delete the existing ones and refresh them if that's more suitable
109
            // in your app.
110
            if( getNumSubItems() == 0 ) {
111
                for(int i=0; i<fileItem->childs.size(); ++i) {
1545 tk 112
                    MiosFileBrowserItem* item;
113
                    addSubItem(item = new MiosFileBrowserItem(fileItem->childs[i], browser));
1542 tk 114
                }
115
            }
116
        } else {
117
            // in this case, we'll leave any sub-items in the tree when the node gets closed,
118
            // though you could choose to delete them if that's more appropriate for
119
            // your application.
120
        }
121
    }
122
 
123
 
124
    void itemClicked (const MouseEvent& e)
125
    {
126
        browser->treeItemClicked(this);
127
    }
128
 
129
    void itemDoubleClicked (const MouseEvent& e)
130
    {
131
        TreeViewItem::itemDoubleClicked(e);
132
        browser->treeItemDoubleClicked(this);
133
    }
134
 
135
    const String getDragSourceDescription()
136
    {
137
        return "MIOS Filebrowser Items";
138
    }
139
 
140
private:
141
};
142
 
143
//==============================================================================
144
//==============================================================================
145
//==============================================================================
146
MiosFileBrowser::MiosFileBrowser(MiosStudio *_miosStudio)
147
    : miosStudio(_miosStudio)
148
    , rootItem(NULL)
149
    , rootFileItem(NULL)
1546 tk 150
    , currentDirOpenStates(NULL)
1542 tk 151
    , currentReadInProgress(false)
152
    , currentReadError(false)
153
    , currentWriteInProgress(false)
154
    , currentWriteError(false)
155
{
156
    addAndMakeVisible(statusLabel = new Label(T("Status"), String::empty));
157
    statusLabel->setJustificationType(Justification::left);
158
    statusLabel->setText(T("Please connect to MIOS32 core by pressing the Update button!"), true);
159
 
160
    addAndMakeVisible(updateButton = new TextButton(T("Update Button")));
161
    updateButton->setButtonText(T("Update"));
162
    updateButton->addListener(this);
163
 
164
    addAndMakeVisible(uploadButton = new TextButton(T("Upload Button")));
165
    uploadButton->setButtonText(T("Upload"));
166
    uploadButton->addListener(this);
167
 
168
    addAndMakeVisible(downloadButton = new TextButton(T("Download Button")));
169
    downloadButton->setButtonText(T("Download"));
170
    downloadButton->addListener(this);
171
 
172
    addAndMakeVisible(editTextButton = new TextButton(T("EditText Button")));
173
    editTextButton->setButtonText(T("Edit Text"));
174
    editTextButton->addListener(this);
175
 
176
    addAndMakeVisible(editHexButton = new TextButton(T("EditHex Button")));
177
    editHexButton->setButtonText(T("Edit Hex"));
178
    editHexButton->addListener(this);
179
 
180
    addAndMakeVisible(createDirButton = new TextButton(T("CreateDir Button")));
181
    createDirButton->setButtonText(T("Create Dir"));
182
    createDirButton->addListener(this);
183
 
184
    addAndMakeVisible(removeButton = new TextButton(T("Remove Button")));
185
    removeButton->setButtonText(T("Remove"));
186
    removeButton->addListener(this);
187
 
1545 tk 188
    addAndMakeVisible(treeView = new TreeView(T("SD Card")));
1542 tk 189
    treeView->setMultiSelectEnabled(false);
190
 
1545 tk 191
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
192
    currentDirItem = rootFileItem;
1542 tk 193
    updateTreeView(false);
194
 
195
    resizeLimits.setSizeLimits(100, 300, 2048, 2048);
196
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
197
 
198
    setSize(860, 500);
199
}
200
 
201
MiosFileBrowser::~MiosFileBrowser()
202
{
203
}
204
 
205
//==============================================================================
206
void MiosFileBrowser::paint (Graphics& g)
207
{
208
    //g.fillAll(Colour(0xffc1d0ff));
209
    g.fillAll(Colour(0xffffffff));
210
}
211
 
212
void MiosFileBrowser::resized()
213
{
214
    int sendButtonY = 16;
215
    int sendButtonWidth = 72;
216
 
217
    updateButton->setBounds   (10 , sendButtonY + 0*32 + 0*16, sendButtonWidth, 24);
218
    downloadButton->setBounds (10 , sendButtonY + 1*32 + 1*16, sendButtonWidth, 24);
219
    uploadButton->setBounds   (10 , sendButtonY + 2*32 + 1*16, sendButtonWidth, 24);
220
    editTextButton->setBounds (10 , sendButtonY + 3*32 + 2*16, sendButtonWidth, 24);
221
    editHexButton->setBounds  (10 , sendButtonY + 4*32 + 2*16, sendButtonWidth, 24);
222
    createDirButton->setBounds(10 , sendButtonY + 5*32 + 3*16, sendButtonWidth, 24);
223
    removeButton->setBounds   (10 , sendButtonY + 6*32 + 4*16, sendButtonWidth, 24);
224
 
225
    treeView->setBounds(10 + 80, 16, getWidth(), getHeight()-32-24);
226
 
227
    statusLabel->setBounds(10, getHeight()-24, getWidth()-20, 24);
228
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
229
}
230
 
231
//==============================================================================
232
void MiosFileBrowser::buttonClicked(Button* buttonThatWasClicked)
233
{
234
    if( buttonThatWasClicked == updateButton ) {
1546 tk 235
        // ensure that we see the first position of the treeview
236
        treeView->clearSelectedItems();
237
        treeView->scrollToKeepItemVisible(rootItem);
238
        // request update
239
        requestUpdateTreeView();
1542 tk 240
    } else if( buttonThatWasClicked == downloadButton ||
241
               buttonThatWasClicked == editTextButton ||
242
               buttonThatWasClicked == editHexButton ) {
243
 
244
        if( treeView->getNumSelectedItems() ) {
245
            TreeViewItem* selectedItem = treeView->getSelectedItem(0);
246
            currentReadFile = selectedItem->getUniqueName();
247
            disableFileButtons();
248
            sendCommand(T("read ") + currentReadFile);
249
        }
250
    } else if( buttonThatWasClicked == uploadButton ) {
251
        disableFileButtons();
252
        if( !uploadFile() ) {
253
            enableFileButtons();
254
        }
255
    } else if( buttonThatWasClicked == createDirButton ) {
256
        disableFileButtons();
1545 tk 257
        sendCommand(T("mkdir ") + getSelectedPath() + T("test")); // tmp.
1542 tk 258
    } else if( buttonThatWasClicked == removeButton ) {
259
        if( treeView->getNumSelectedItems() ) {
260
            TreeViewItem* selectedItem = treeView->getSelectedItem(0);
261
            String fileName(selectedItem->getUniqueName());
262
            if( AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
263
                                             T("Removing ") + fileName,
264
                                             T("Do you really want to remove\n") + fileName + T("?"),
265
                                             T("Remove"),
266
                                             T("Cancel")) ) {
267
                disableFileButtons();
268
                sendCommand(T("del ") + fileName);
269
            }
270
        }
271
    }
272
}
273
 
274
 
275
//==============================================================================
276
void MiosFileBrowser::filenameComponentChanged(FilenameComponent *fileComponentThatHasChanged)
277
{
278
}
279
 
280
//==============================================================================
1545 tk 281
String MiosFileBrowser::getSelectedPath(void)
282
{
283
    String selectedPath(T("/"));
284
 
285
    TreeViewItem* selectedItem = treeView->getSelectedItem(0);
286
    if( selectedItem ) {
287
        selectedPath = selectedItem->getUniqueName();
288
        if( selectedPath.compare(T("/")) != 0 ) {
289
            if( !selectedItem->mightContainSubItems() ) {
290
                selectedPath = selectedPath.substring(0, selectedPath.lastIndexOfChar('/')) + T("/");
291
            } else {
292
                selectedPath += T("/");
293
            }
294
        }
295
    }
296
 
297
    //std::cout << "Selected Path: " << selectedPath << std::endl;
298
 
299
    return selectedPath;
300
}
301
 
302
//==============================================================================
1542 tk 303
void MiosFileBrowser::disableFileButtons(void)
304
{
305
    uploadButton->setEnabled(false);
306
    downloadButton->setEnabled(false);
307
    editTextButton->setEnabled(false);
308
    editHexButton->setEnabled(false);
309
    createDirButton->setEnabled(false);
310
    removeButton->setEnabled(false);
311
}
312
 
313
void MiosFileBrowser::enableFileButtons(void)
314
{
315
    uploadButton->setEnabled(true);
316
    downloadButton->setEnabled(true);
317
    editTextButton->setEnabled(true);
318
    editHexButton->setEnabled(true);
319
    createDirButton->setEnabled(true);
320
    removeButton->setEnabled(true);
321
}
322
 
323
void MiosFileBrowser::enableDirButtons(void)
324
{
1545 tk 325
    uploadButton->setEnabled(true);
1542 tk 326
    createDirButton->setEnabled(true);
327
    removeButton->setEnabled(true);
328
}
329
 
330
//==============================================================================
1546 tk 331
void MiosFileBrowser::requestUpdateTreeView(void)
332
{
333
    currentDirOpenStates = treeView->getOpennessState(true); // including scroll position
334
 
335
    if( rootFileItem )
336
        delete rootFileItem;
337
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
338
    currentDirItem = rootFileItem;
339
 
340
    updateTreeView(false);
341
 
342
    disableFileButtons();
343
    currentDirFetchItems.clear();
344
    currentDirPath = T("/");
345
    sendCommand(T("dir ") + currentDirPath);
346
}
347
 
1542 tk 348
void MiosFileBrowser::updateTreeView(bool accessPossible)
349
{
350
    disableFileButtons();
351
 
352
    if( rootItem )
353
        treeView->deleteRootItem();
354
 
355
    if( rootFileItem ) {
356
        rootItem = new MiosFileBrowserItem(rootFileItem, this);
357
        rootItem->setOpen(true);
358
        treeView->setRootItem(rootItem);
359
 
1546 tk 360
        if( accessPossible ) {
361
            if( currentDirOpenStates ) {
362
                printf("Restore\n");
363
                treeView->restoreOpennessState(*currentDirOpenStates);
364
                deleteAndZero(currentDirOpenStates);
365
            }
1545 tk 366
 
1542 tk 367
            uploadButton->setEnabled(true);
368
            createDirButton->setEnabled(true);
369
        }
370
    }
371
}
372
 
373
void MiosFileBrowser::treeItemClicked(MiosFileBrowserItem* item)
374
{
375
    disableFileButtons();
376
 
377
    if( item->fileItem->isDirectory ) {
378
        enableDirButtons();
379
    } else {
380
        enableFileButtons();
381
    }
382
}
383
 
384
void MiosFileBrowser::treeItemDoubleClicked(MiosFileBrowserItem* item)
385
{
386
}
387
 
388
//==============================================================================
389
bool MiosFileBrowser::storeDownloadedFile(void)
390
{
391
    if( !currentReadData.size() )
392
        return false;
393
 
394
    // restore default path
395
    String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
396
    PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
397
    if( propertiesFile ) {
398
        defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
399
    }
400
    String readFileName(currentReadFile.substring(currentReadFile.lastIndexOfChar('/')+1));
401
    File defaultPathFile(defaultPath + "/" + readFileName);
402
    FileChooser myChooser(T("Store ") + currentReadFile, defaultPathFile);
403
    if( !myChooser.browseForFileToSave(true) ) {
404
        statusLabel->setText(T("Cancled save operation for ") + currentReadFile, true);
405
        return false;
406
    } else {
407
        File outFile(myChooser.getResult());
408
 
409
        // store default path
410
        if( propertiesFile ) {
411
            propertiesFile->setValue(T("defaultFilebrowserPath"), outFile.getParentDirectory().getFullPathName());
412
        }
413
 
414
        FileOutputStream *outFileStream = NULL;
415
        outFile.deleteFile();
416
        if( !(outFileStream=outFile.createOutputStream()) ||
417
            outFileStream->failedToOpen() ) {
418
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
419
                                        String::empty,
420
                                        T("File cannot be created!"),
421
                                        String::empty);
422
            statusLabel->setText(T("Failed to save ") + defaultPathFile.getFullPathName(), true);
423
            return false;
424
        } else {
425
            outFileStream->write((uint8 *)&currentReadData.getReference(0), currentReadData.size());
426
            delete outFileStream;
427
            statusLabel->setText(T("Saved ") + defaultPathFile.getFullPathName(), true);
428
        }
429
    }
430
 
431
    return true;
432
}
433
 
434
bool MiosFileBrowser::uploadFile(void)
435
{
436
    // restore default path
437
    String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
438
    PropertiesFile *propertiesFile = ApplicationProperties::getInstance()->getCommonSettings(true);
439
    if( propertiesFile ) {
440
        defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
441
    }
442
    File defaultPathFile(defaultPath);
443
    FileChooser myChooser(T("Upload File to Core"), defaultPathFile);
444
    if( !myChooser.browseForFileToOpen() ) {
445
        return false;
446
    } else {
447
        File inFile(myChooser.getResult());
448
 
449
        // store default path
450
        if( propertiesFile ) {
451
            propertiesFile->setValue(T("defaultFilebrowserPath"), inFile.getParentDirectory().getFullPathName());
452
        }
453
 
454
        FileInputStream *inFileStream = inFile.createInputStream();
455
        if( !inFileStream || inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
456
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
457
                                        T("The file ") + inFile.getFileName(),
458
                                        T("doesn't exist!"),
459
                                        String::empty);
460
        } else if( inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
461
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
462
                                        T("The file ") + inFile.getFileName(),
463
                                        T("is empty!"),
464
                                        String::empty);
465
        } else {
466
            uint64 size = inFileStream->getTotalLength();
467
            uint8 *buffer = (uint8 *)juce_malloc(size);
468
            currentWriteSize = inFileStream->read(buffer, size);
1545 tk 469
            currentWriteFile = getSelectedPath() + inFile.getFileName();
1542 tk 470
            //currentWriteData.resize(currentWriteSize); // doesn't exist in Juce 1.53
471
            Array<uint8> dummy(buffer, currentWriteSize);
472
            currentWriteData = dummy;
473
            juce_free(buffer);
474
            statusLabel->setText(T("Uploading ") + currentWriteFile + T(" (") + String(currentWriteSize) + T(" bytes)"), true);
475
 
476
            currentWriteInProgress = true;
477
            currentWriteError = false;
478
            currentWriteStartTime = Time::currentTimeMillis();
479
            sendCommand(T("write ") + currentWriteFile + T(" ") + String(currentWriteSize));
1544 tk 480
            startTimer(3000);
1542 tk 481
        }
1544 tk 482
 
483
        if( inFileStream )
484
            delete inFileStream;
1542 tk 485
    }
486
 
487
    return true;
488
}
489
 
490
//==============================================================================
491
void MiosFileBrowser::timerCallback()
492
{
493
    if( currentReadInProgress ) {
494
        if( currentReadError ) {
495
            statusLabel->setText(T("Invalid response from MIOS32 core during read operation!"), true);
496
        } else {
497
            statusLabel->setText(T("No response from MIOS32 core during read operation!"), true);
498
        }
499
    } else {
500
        statusLabel->setText(T("No response from MIOS32 core!"), true);
501
    }
502
}
503
 
504
//==============================================================================
505
void MiosFileBrowser::sendCommand(const String& command)
506
{
507
    Array<uint8> dataArray = SysexHelper::createMios32DebugMessage(miosStudio->uploadHandler->getDeviceId());
508
    dataArray.add(0x01); // filebrowser string
509
    for(int i=0; i<command.length(); ++i)
510
        dataArray.add(command[i] & 0x7f);
511
    dataArray.add('\n');
512
    dataArray.add(0xf7);
513
    MidiMessage message = SysexHelper::createMidiMessage(dataArray);
514
    miosStudio->sendMidiMessage(message);
1544 tk 515
    startTimer(3000);
1542 tk 516
}
517
 
518
//==============================================================================
519
void MiosFileBrowser::receiveCommand(const String& command)
520
{
521
    String statusMessage;
522
 
523
    stopTimer(); // will be restarted if required
524
 
525
    if( command.length() ) {
526
        switch( command[0] ) {
527
 
528
        ////////////////////////////////////////////////////////////////////
529
        case '?': {
530
            statusMessage = String(T("Command not supported by MIOS32 application - please check if a firmware update is available!"));
531
        } break;
532
 
533
        ////////////////////////////////////////////////////////////////////
534
        case 'D': {
535
            if( command[1] == '!' ) {
536
                statusMessage = String(T("SD Card not mounted!"));
537
            } else if( command[1] == '-' ) {
538
                statusMessage = String(T("Failed to access directory!"));
539
            } else {
540
                statusMessage = String(T("Received directory structure."));
541
 
542
                int posStartName = 2;
543
                for(int pos=2; pos<command.length(); ++pos) {
544
                    if( command[pos] == 'F' || command[pos] == 'D' ) {
545
                        for(++pos; pos < command.length() && command[pos] != ','; ++pos);
546
                        String fileName(command.substring(posStartName, pos));
547
                        //std::cout << "XXX " << fileName << std::endl;
548
                        if( fileName[0] == 'F' ) {
1545 tk 549
                            currentDirItem->createChild(currentDirPath, fileName.substring(1), false);
1542 tk 550
                        } else if( fileName[0] == 'D' ) {
1545 tk 551
                            currentDirFetchItems.add(currentDirItem->createChild(currentDirPath, fileName.substring(1), true));
1542 tk 552
                        } else {
1545 tk 553
                            std::cout << "INVALID Response: " << currentDirPath << fileName << std::endl;
1542 tk 554
                            statusMessage = String(T("Invalid Response!"));
555
                            break;
556
                        }
557
                        posStartName = pos+1;
558
                    } else {
559
                        statusMessage = String(T("Invalid Response!"));
560
                        break;
561
                    }
562
                }
563
            }
1545 tk 564
 
565
            // do we have to fetch some additional subdirectories?
566
            if( currentDirFetchItems.size() ) {
567
                currentDirItem = currentDirFetchItems.remove(0);
568
                if( currentDirItem->parentPath.compare(T("/")) == 0 )
569
                    currentDirPath = currentDirItem->parentPath + currentDirItem->name;
570
                else
571
                    currentDirPath = currentDirItem->parentPath + T("/") + currentDirItem->name;
572
                //std::cout << "Fetch " << currentDirPath << std::endl;
573
                sendCommand(T("dir ") + currentDirPath);
574
            } else {
575
                updateTreeView(true);
576
            }
1542 tk 577
        } break;
578
 
579
        ////////////////////////////////////////////////////////////////////
580
        case 'R': {
581
            if( command[1] == '!' ) {
582
                statusMessage = String(T("SD Card not mounted!"));
583
            } else if( command[1] == '-' ) {
584
                statusMessage = String(T("Failed to access " + currentReadFile + "!"));
585
            } else {
586
                currentReadSize = (command.substring(1)).getIntValue();
587
                currentReadData.clear();
588
                if( currentReadSize ) {
589
                    statusMessage = String(T("Receiving ") + currentReadFile + T(" with ") + String(currentReadSize) + T(" bytes."));
590
                    currentReadInProgress = true;
591
                    currentReadError = false;
592
                    currentReadStartTime = Time::currentTimeMillis();
1544 tk 593
                    startTimer(3000);
1542 tk 594
                } else {
595
                    statusMessage = String(currentReadFile + T(" is empty!"));
596
                }
597
            }
598
        } break;
599
 
600
        ////////////////////////////////////////////////////////////////////
601
        case 'r': {
602
            if( !currentReadInProgress ) {
603
                statusMessage = String(T("There is a read operation in progress - please wait!"));
604
            } else {
605
                String strAddress = command.substring(1, 9);
606
                String strPayload = command.substring(10);
607
 
608
                unsigned address = strAddress.getHexValue32();
609
 
610
                if( address >= currentReadSize ) {
611
                    statusMessage = String(currentReadFile + T(" received invalid payload!"));
612
                    currentReadError = true;
613
                } else {
614
                    for(int pos=0; pos<strPayload.length(); pos+=2) {
615
                        uint8 b = (strPayload.substring(pos, pos+2)).getHexValue32();
616
                        currentReadData.set(address + (pos/2), b);
617
                    }
618
 
619
                    unsigned receivedSize = currentReadData.size();
620
                    uint32 currentReadFinished = Time::currentTimeMillis();
621
                    float downloadTime = (float)(currentReadFinished-currentReadStartTime) / 1000.0;
622
                    float dataRate = ((float)receivedSize/1000.0) / downloadTime;
623
                    if( receivedSize >= currentReadSize ) {
624
                        statusMessage = String(T("Download of ") + currentReadFile +
625
                                               T(" (") + String(receivedSize) + T(" bytes) completed in ") +
626
                                               String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate));
627
                        currentReadInProgress = false;
628
 
629
                        statusLabel->setText(statusMessage, true);
630
                        storeDownloadedFile();
631
                        statusMessage = String::empty; // status has been updated by storeDownloadedFile()
632
 
633
                        enableFileButtons();
634
                    } else {
635
                        statusMessage = String(T("Downloading ") + currentReadFile + T(": ") +
636
                                               String(receivedSize) + T(" bytes received") +
637
                                               String::formatted(T(" (%d%%, %2.1f kb/s)"),
638
                                                                 (int)(100.0*(float)receivedSize/(float)currentReadSize),
639
                                                                 dataRate));
1544 tk 640
                        startTimer(3000);
1542 tk 641
                    }
642
                }
643
            }
644
        } break;
645
 
646
        ////////////////////////////////////////////////////////////////////
647
        case 'W': {
648
            if( !currentWriteInProgress ) {
649
                statusMessage = String(T("There is a write operation in progress - please wait!"));
650
            } else if( command[1] == '!' ) {
651
                statusMessage = String(T("SD Card not mounted!"));
652
            } else if( command[1] == '-' ) {
653
                statusMessage = String(T("Failed to access " + currentWriteFile + "!"));
654
            } else if( command[1] == '~' ) {
655
                statusMessage = String(T("FATAL: invalid parameters for write operation!"));
656
            } else if( command[1] == '#' ) {
657
                currentWriteInProgress = false;
658
 
659
                uint32 currentWriteFinished = Time::currentTimeMillis();
660
                float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
661
                float dataRate = ((float)currentWriteSize/1000.0) / downloadTime;
662
 
663
                statusMessage = String(T("Upload of ") + currentWriteFile +
664
                                       T(" (") + String(currentWriteSize) + T(" bytes) completed in ") +
665
                                       String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate));
666
 
1546 tk 667
                requestUpdateTreeView();
1542 tk 668
            } else {
669
                unsigned addressOffset = command.substring(1).getHexValue32();
670
 
671
                String writeCommand(String::formatted(T("writedata %08X "), addressOffset));
672
                for(int i=0; i<32 && (i+addressOffset)<currentWriteSize; ++i) {
673
                    writeCommand += String::formatted(T("%02X"), currentWriteData[addressOffset + i]);
674
                }
675
                sendCommand(writeCommand);
676
 
677
                uint32 currentWriteFinished = Time::currentTimeMillis();
678
                float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
679
                float dataRate = ((float)addressOffset/1000.0) / downloadTime;
680
 
681
                statusMessage = String(T("Uploading ") + currentWriteFile + T(": ") +
682
                                       String(addressOffset) + T(" bytes transmitted") +
683
                                       String::formatted(T(" (%d%%, %2.1f kb/s)"),
684
                                                         (int)(100.0*(float)addressOffset/(float)currentWriteSize),
685
                                                         dataRate));
1544 tk 686
                startTimer(3000);
1542 tk 687
            }
688
        } break;
689
 
690
 
691
        ////////////////////////////////////////////////////////////////////
692
        case 'M': {
693
            if( command[1] == '!' ) {
694
                statusMessage = String(T("SD Card not mounted!"));
695
            } else if( command[1] == '-' ) {
696
                statusMessage = String(T("Failed to create directory!"));
697
            } else if( command[1] == '#' ) {
698
                statusMessage = String(T("Directory has been created!"));
1546 tk 699
                requestUpdateTreeView();
1542 tk 700
            } else {
701
                statusMessage = String(T("Unsupported response from mkdir command!"));
702
            }
703
        } break;
704
 
705
 
706
        ////////////////////////////////////////////////////////////////////
707
        case 'X': {
708
            if( command[1] == '!' ) {
709
                statusMessage = String(T("SD Card not mounted!"));
710
            } else if( command[1] == '-' ) {
711
                statusMessage = String(T("Failed to delete file!"));
712
            } else if( command[1] == '#' ) {
713
                statusMessage = String(T("File has been removed!"));
1546 tk 714
                requestUpdateTreeView();
1542 tk 715
            } else {
716
                statusMessage = String(T("Unsupported response from del command!"));
717
            }
718
        } break;
719
 
720
 
721
        ////////////////////////////////////////////////////////////////////
722
        default:
723
            statusMessage = String(T("Received unsupported Filebrowser Command! Please update your MIOS Studio installation!"));
724
        }
725
    }
726
 
727
    if( statusMessage.length() ) {
728
        statusLabel->setText(statusMessage, true);
729
    }
730
}
731
 
732
//==============================================================================
733
void MiosFileBrowser::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
734
{
735
    uint8 *data = message.getRawData();
736
    uint32 size = message.getRawDataSize();
737
    int messageOffset = 0;
738
 
739
    bool messageReceived = false;
740
    if( runningStatus == 0xf0 &&
741
        SysexHelper::isValidMios32DebugMessage(data, size, -1) &&
742
        data[7] == 0x41 ) {
743
            messageOffset = 8;
744
            messageReceived = true;
745
    } else if( runningStatus == 0xf0 &&
746
        SysexHelper::isValidMios32Error(data, size, -1) &&
747
        data[7] == 0x10 ) {
748
        stopTimer();
749
        statusLabel->setText(T("Filebrowser access not implemented by this application!"), true);
750
    }
751
 
752
    if( messageReceived ) {
753
        String command;
754
 
755
        for(int i=messageOffset; i<size; ++i) {
756
            if( data[i] < 0x80 ) {
757
                if( data[i] != '\n' || size < (i+1) )
758
                    command += String::formatted(T("%c"), data[i] & 0x7f);
759
            }
760
        }
761
        receiveCommand(command);
762
    }
763
}