Subversion Repositories svn.mios32

Rev

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