Subversion Repositories svn.mios32

Rev

Rev 1594 | Rev 1726 | 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 1724 2013-03-28 20:23:40Z 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
 
1724 tk 69
    String getUniqueName() const
1542 tk 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
    {
1555 tk 126
        if( getOwnerView()->isEnabled() )
127
            browser->treeItemClicked(this);
1542 tk 128
    }
129
 
130
    void itemDoubleClicked (const MouseEvent& e)
131
    {
132
        TreeViewItem::itemDoubleClicked(e);
1555 tk 133
        if( getOwnerView()->isEnabled() )
134
            browser->treeItemDoubleClicked(this);
1542 tk 135
    }
136
 
1724 tk 137
    var getDragSourceDescription()
1542 tk 138
    {
139
        return "MIOS Filebrowser Items";
140
    }
141
 
142
private:
143
};
144
 
145
//==============================================================================
146
//==============================================================================
147
//==============================================================================
148
MiosFileBrowser::MiosFileBrowser(MiosStudio *_miosStudio)
149
    : miosStudio(_miosStudio)
150
    , rootItem(NULL)
151
    , rootFileItem(NULL)
1546 tk 152
    , currentDirOpenStates(NULL)
1554 tk 153
    , transferSelectionCtr(0)
154
    , openTextEditorAfterRead(false)
155
    , openHexEditorAfterRead(false)
1542 tk 156
    , currentReadInProgress(false)
1555 tk 157
    , currentReadFileBrowserItem(NULL)
1554 tk 158
    , currentReadFileStream(NULL)
1542 tk 159
    , currentReadError(false)
160
    , currentWriteInProgress(false)
161
    , currentWriteError(false)
1548 tk 162
    , writeBlockCtrDefault(32) // send 32 blocks (=two 512 byte SD Card Sectors) at once to speed-up write operations
163
    , writeBlockSizeDefault(32) // send 32 bytes per block
1542 tk 164
{
1554 tk 165
    addAndMakeVisible(editLabel = new Label(T("Edit"), String::empty));
166
    editLabel->setJustificationType(Justification::left);
167
    editLabel->setText(String::empty, true);
168
 
1542 tk 169
    addAndMakeVisible(statusLabel = new Label(T("Status"), String::empty));
170
    statusLabel->setJustificationType(Justification::left);
171
    statusLabel->setText(T("Please connect to MIOS32 core by pressing the Update button!"), true);
172
 
1554 tk 173
    addAndMakeVisible(updateButton = new TextButton(T("Update")));
1542 tk 174
    updateButton->addListener(this);
175
 
1554 tk 176
    addAndMakeVisible(uploadButton = new TextButton(T("Upload")));
1542 tk 177
    uploadButton->addListener(this);
178
 
1554 tk 179
    addAndMakeVisible(downloadButton = new TextButton(T("Download")));
1542 tk 180
    downloadButton->addListener(this);
181
 
1554 tk 182
    addAndMakeVisible(editTextButton = new TextButton(T("Edit Text")));
1542 tk 183
    editTextButton->addListener(this);
184
 
1554 tk 185
    addAndMakeVisible(editHexButton = new TextButton(T("Edit Hex")));
1542 tk 186
    editHexButton->addListener(this);
187
 
1554 tk 188
    addAndMakeVisible(createDirButton = new TextButton(T("Create Dir")));
1542 tk 189
    createDirButton->addListener(this);
190
 
1555 tk 191
    addAndMakeVisible(createFileButton = new TextButton(T("Create File")));
192
    createFileButton->addListener(this);
193
 
1542 tk 194
    addAndMakeVisible(removeButton = new TextButton(T("Remove Button")));
195
    removeButton->setButtonText(T("Remove"));
196
    removeButton->addListener(this);
197
 
1554 tk 198
    addAndMakeVisible(cancelButton = new TextButton(T("Cancel")));
199
    cancelButton->addListener(this);
200
    cancelButton->setEnabled(false);
201
 
202
    addAndMakeVisible(saveButton = new TextButton(T("Save")));
203
    saveButton->addListener(this);
204
    saveButton->setEnabled(false);
205
 
1545 tk 206
    addAndMakeVisible(treeView = new TreeView(T("SD Card")));
1554 tk 207
    treeView->setMultiSelectEnabled(true);
1542 tk 208
 
1554 tk 209
    addAndMakeVisible(hexEditor = new HexTextEditor(statusLabel));
210
    hexEditor->setReadOnly(true);
211
 
212
    addAndMakeVisible(textEditor = new TextEditor(String::empty));
213
    textEditor->setMultiLine(true);
214
    textEditor->setReturnKeyStartsNewLine(true);
215
    textEditor->setReadOnly(false);
216
    textEditor->setScrollbarsShown(true);
217
    textEditor->setCaretVisible(true);
218
    textEditor->setPopupMenuEnabled(true);
219
    textEditor->setReadOnly(true);
220
    textEditor->setVisible(false); // either hex or text editor visible
221
#if JUCE_MAJOR_VERSION==1 && JUCE_MINOR_VERSION<51
222
#if defined(JUCE_WIN32)
223
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 10.0, 0));
224
#else
225
    textEditor->setFont(Font(Typeface::defaultTypefaceNameMono, 13.0, 0));
226
#endif
227
#else
228
#if defined(JUCE_WIN32)
229
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 10.0, 0));
230
#else
231
    textEditor->setFont(Font(Font::getDefaultMonospacedFontName(), 13.0, 0));
232
#endif
233
#endif
234
    textEditor->addListener(this);
235
 
1545 tk 236
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
237
    currentDirItem = rootFileItem;
1542 tk 238
    updateTreeView(false);
239
 
1554 tk 240
    resizeLimits.setSizeLimits(500, 320, 2048, 2048);
1542 tk 241
    addAndMakeVisible(resizer = new ResizableCornerComponent(this, &resizeLimits));
242
 
1554 tk 243
    setSize(950, 500);
1542 tk 244
}
245
 
246
MiosFileBrowser::~MiosFileBrowser()
247
{
248
}
249
 
250
//==============================================================================
251
void MiosFileBrowser::paint (Graphics& g)
252
{
253
    //g.fillAll(Colour(0xffc1d0ff));
254
    g.fillAll(Colour(0xffffffff));
255
}
256
 
257
void MiosFileBrowser::resized()
258
{
259
    int sendButtonY = 16;
260
    int sendButtonWidth = 72;
1555 tk 261
 
262
    updateButton->setBounds    (10 , sendButtonY + 0*32 + 0*16, sendButtonWidth, 24);
263
    downloadButton->setBounds  (10 , sendButtonY + 1*32 + 1*16, sendButtonWidth, 24);
264
    uploadButton->setBounds    (10 , sendButtonY + 2*32 + 1*16, sendButtonWidth, 24);
265
    createDirButton->setBounds (10 , sendButtonY + 3*32 + 3*16, sendButtonWidth, 24);
266
    createFileButton->setBounds(10 , sendButtonY + 4*32 + 3*16, sendButtonWidth, 24);
267
    removeButton->setBounds    (10 , sendButtonY + 5*32 + 4*16, sendButtonWidth, 24);
1542 tk 268
 
1555 tk 269
    treeView->setBounds        (10 + 80, 16, 210, getHeight()-32-24);
1542 tk 270
 
1555 tk 271
    hexEditor->setBounds       (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
272
    textEditor->setBounds      (10+80+220, 48, getWidth()-10-80-220-10, getHeight()-32-32-24);
1542 tk 273
 
1555 tk 274
    editTextButton->setBounds  (10+80+220 + 0*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
275
    editHexButton->setBounds   (10+80+220 + 1*(sendButtonWidth+10), sendButtonY, sendButtonWidth, 24);
276
    cancelButton->setBounds    (getWidth()-10-sendButtonWidth, sendButtonY, sendButtonWidth, 24);
277
    saveButton->setBounds      (getWidth()-10-2*sendButtonWidth-10, sendButtonY, sendButtonWidth, 24);
1554 tk 278
 
279
    unsigned editLabelLeft  = editHexButton->getX()+editHexButton->getWidth() + 10;
280
    unsigned editLabelRight = saveButton->getX() - 10;
1555 tk 281
    editLabel->setBounds       (editLabelLeft, sendButtonY, editLabelRight-editLabelLeft, 24);
1554 tk 282
 
1542 tk 283
    statusLabel->setBounds(10, getHeight()-24, getWidth()-20, 24);
284
    resizer->setBounds(getWidth()-16, getHeight()-16, 16, 16);
285
}
286
 
287
//==============================================================================
288
void MiosFileBrowser::buttonClicked(Button* buttonThatWasClicked)
289
{
290
    if( buttonThatWasClicked == updateButton ) {
1546 tk 291
        // ensure that we see the first position of the treeview
292
        treeView->clearSelectedItems();
293
        treeView->scrollToKeepItemVisible(rootItem);
1548 tk 294
        // change label
295
        statusLabel->setText(T(""), true);
1546 tk 296
        // request update
297
        requestUpdateTreeView();
1542 tk 298
    } else if( buttonThatWasClicked == downloadButton ||
299
               buttonThatWasClicked == editTextButton ||
300
               buttonThatWasClicked == editHexButton ) {
301
 
1554 tk 302
        // extra: if data is edited, switch between hex/text view
303
        if( saveButton->isEnabled() ) {
1555 tk 304
            // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
305
            if( currentReadFileBrowserItem ) {
306
                currentReadFileBrowserItem->setSelected(true, true);
307
                treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
308
            }
309
 
1554 tk 310
            if( buttonThatWasClicked == editTextButton && hexEditor->isVisible() ) {
1555 tk 311
                openTextEditor(hexEditor->getBinary());
1554 tk 312
                statusLabel->setText(T("Editing ") + currentReadFileName + T(" in text mode."), true);
313
            } else if( buttonThatWasClicked == editHexButton && textEditor->isVisible() ) {
1555 tk 314
                if( textEditor->isVisible() && !textEditor->isReadOnly() ) {
315
                    // visible & read only mode means, that binary data is edited -> transfer to Hex Editor only in this case!
316
                    String tmpStr(textEditor->getText());
1724 tk 317
                    Array<uint8> data((uint8 *)tmpStr.toUTF8().getAddress(), tmpStr.length());
1555 tk 318
                    openHexEditor(data);
319
                } else {
320
                    // otherwise re-use data in hex editor
321
                    openHexEditor(hexEditor->getBinary());
322
                }
1554 tk 323
                statusLabel->setText(T("Editing ") + currentReadFileName + T(" in hex mode."), true);
324
            }
325
        } else {
326
            if( treeView->getNumSelectedItems() ) {
327
                openTextEditorAfterRead = buttonThatWasClicked == editTextButton;
328
                openHexEditorAfterRead = buttonThatWasClicked == editHexButton;
329
                transferSelectionCtr = 0;
330
                downloadFileSelection(transferSelectionCtr);
331
            }
1542 tk 332
        }
333
    } else if( buttonThatWasClicked == uploadButton ) {
1554 tk 334
        uploadFile();
1542 tk 335
    } else if( buttonThatWasClicked == createDirButton ) {
1554 tk 336
        createDir();
1555 tk 337
    } else if( buttonThatWasClicked == createFileButton ) {
338
        createFile();
1542 tk 339
    } else if( buttonThatWasClicked == removeButton ) {
340
        if( treeView->getNumSelectedItems() ) {
1554 tk 341
            transferSelectionCtr = 0;
342
            deleteFileSelection(transferSelectionCtr);
343
        }
344
    } else if( buttonThatWasClicked == cancelButton ||
345
               buttonThatWasClicked == saveButton ) {
346
 
347
        if( buttonThatWasClicked == cancelButton ) {
1594 tk 348
            openHexEditorAfterRead = false;
349
            openTextEditorAfterRead = false;
1554 tk 350
            enableFileButtons();
351
            hexEditor->clear();
352
            hexEditor->setReadOnly(true);
353
            textEditor->clear();
354
            textEditor->setReadOnly(true);
355
            editLabel->setText(String::empty, true);
356
 
357
            disableFileButtons(); // to disable also editor buttons
358
            enableFileButtons();
359
        } else if( buttonThatWasClicked == saveButton ) {
360
            if( hexEditor->isVisible() ) {
361
                // write back the read file
362
                uploadBuffer(currentReadFileName, hexEditor->getBinary());
363
            } else if( textEditor->isVisible() ) {
364
                // write back the read file
365
                String txt(textEditor->getText());
1724 tk 366
                Array<uint8> tmp((uint8 *)txt.toUTF8().getAddress(), txt.length());
1554 tk 367
                uploadBuffer(currentReadFileName, tmp);
1542 tk 368
            }
369
        }
370
    }
371
}
372
 
373
 
374
//==============================================================================
1554 tk 375
void MiosFileBrowser::textEditorTextChanged(TextEditor &editor)
1542 tk 376
{
1554 tk 377
    // unfortunately not updated on any cursor move...
378
#if 0
379
    int pos = editor.getCaretPosition();
380
    String txt(editor.getText());
381
    statusLabel->setText(String::formatted(T("(%d/%d)"), pos, txt.length()), true);
382
#endif
1542 tk 383
}
384
 
1554 tk 385
void MiosFileBrowser::textEditorReturnKeyPressed(TextEditor &editor)
386
{
387
}
388
 
389
void MiosFileBrowser::textEditorEscapeKeyPressed(TextEditor &editor)
390
{
391
}
392
 
393
void MiosFileBrowser::textEditorFocusLost(TextEditor &editor)
394
{
395
}
396
 
397
 
1542 tk 398
//==============================================================================
1545 tk 399
String MiosFileBrowser::getSelectedPath(void)
400
{
401
    String selectedPath(T("/"));
402
 
403
    TreeViewItem* selectedItem = treeView->getSelectedItem(0);
404
    if( selectedItem ) {
405
        selectedPath = selectedItem->getUniqueName();
406
        if( selectedPath.compare(T("/")) != 0 ) {
407
            if( !selectedItem->mightContainSubItems() ) {
408
                selectedPath = selectedPath.substring(0, selectedPath.lastIndexOfChar('/')) + T("/");
409
            } else {
410
                selectedPath += T("/");
411
            }
412
        }
413
    }
414
 
415
    //std::cout << "Selected Path: " << selectedPath << std::endl;
416
 
417
    return selectedPath;
418
}
419
 
420
//==============================================================================
1542 tk 421
void MiosFileBrowser::disableFileButtons(void)
422
{
1554 tk 423
    updateButton->setEnabled(true);
1542 tk 424
    uploadButton->setEnabled(false);
425
    downloadButton->setEnabled(false);
426
    createDirButton->setEnabled(false);
1555 tk 427
    createFileButton->setEnabled(false);
1542 tk 428
    removeButton->setEnabled(false);
1554 tk 429
 
430
    // important: don't disable save/cancel button as long as an open editor has content
431
    // (in case of write error)
432
    if( !(textEditor->isVisible() && textEditor->getText().length()) &&
433
        !(hexEditor->isVisible() && hexEditor->getBinary().size()) ) {
434
        editTextButton->setEnabled(false);
435
        editHexButton->setEnabled(false);
436
        hexEditor->setReadOnly(true);
437
        textEditor->setReadOnly(true);
438
        saveButton->setEnabled(false);
439
        cancelButton->setEnabled(false);
440
    }
1542 tk 441
}
442
 
443
void MiosFileBrowser::enableFileButtons(void)
444
{
1724 tk 445
    treeView->setEnabled(true);
446
 
1554 tk 447
    updateButton->setEnabled(true);
1542 tk 448
    uploadButton->setEnabled(true);
449
    downloadButton->setEnabled(true);
450
    editTextButton->setEnabled(true);
451
    editHexButton->setEnabled(true);
452
    createDirButton->setEnabled(true);
1555 tk 453
    createFileButton->setEnabled(true);
1542 tk 454
    removeButton->setEnabled(true);
455
}
456
 
457
void MiosFileBrowser::enableDirButtons(void)
458
{
1554 tk 459
    updateButton->setEnabled(true);
1545 tk 460
    uploadButton->setEnabled(true);
1542 tk 461
    createDirButton->setEnabled(true);
1555 tk 462
    createFileButton->setEnabled(true); // no error: we want to create a file in the selected directory
1542 tk 463
    removeButton->setEnabled(true);
464
}
465
 
1554 tk 466
void MiosFileBrowser::enableEditorButtons(void)
467
{
468
    treeView->setEnabled(false);
1555 tk 469
 
1554 tk 470
    updateButton->setEnabled(false);
471
    editTextButton->setEnabled(true);
472
    editHexButton->setEnabled(true);
473
    cancelButton->setEnabled(true);
474
    saveButton->setEnabled(true);
475
}
476
 
1555 tk 477
//==============================================================================
478
String MiosFileBrowser::convertToString(const Array<uint8>& data, bool& hasBinaryData)
479
{
480
    String str;
481
    hasBinaryData = false;
482
 
483
    uint8 *ptr = (uint8 *)&data.getReference(0);
484
    for(int i=0; i<data.size(); ++i, ++ptr) {
485
        if( *ptr == 0 ) {
486
            hasBinaryData = true; // full conversion to string not possible
1724 tk 487
            str += "\\0"; // show \0 instead
1555 tk 488
        } else {
1724 tk 489
            str += (const wchar_t)*ptr;
1555 tk 490
        }
491
    }
1554 tk 492
 
1555 tk 493
    return str;
494
}
495
 
496
bool MiosFileBrowser::updateEditors(const Array<uint8>& data)
497
{
498
    // transfer data into both editors, make them read-only and invisible
499
    hexEditor->setReadOnly(false);
500
    hexEditor->clear();
501
    hexEditor->addBinary((uint8 *)&data.getReference(0), data.size());
502
    hexEditor->setReadOnly(true);
503
    hexEditor->setVisible(false);
504
 
505
    bool hasBinaryData = false;
506
    String tmpStr(convertToString(data, hasBinaryData));
507
    textEditor->setReadOnly(false);
508
    textEditor->clear();
509
    textEditor->setText(tmpStr, true);
510
    textEditor->setReadOnly(true);
511
    textEditor->setVisible(false);
512
 
513
    // ensure that no tree item is selected to avoid confusion (selection is possible even if treeView is disabled!)
514
    if( currentReadFileBrowserItem ) {
515
        currentReadFileBrowserItem->setSelected(true, true);
516
        treeView->scrollToKeepItemVisible(currentReadFileBrowserItem);
517
    }
518
 
519
    return hasBinaryData;
520
}
521
 
522
void MiosFileBrowser::openTextEditor(const Array<uint8>& data)
523
{
524
    // transfer data to both editors
525
    bool hasBinaryData = updateEditors(data);
526
 
527
    disableFileButtons();
528
    enableEditorButtons();
529
 
530
    // make text editor visible and enable read access if no binary data
531
    textEditor->setVisible(true);
532
    if( !hasBinaryData ) {
533
        textEditor->setReadOnly(false);
534
    } else {
535
        AlertWindow::showMessageBox(AlertWindow::WarningIcon,
536
                                    T("Found binary data!"),
537
                                    T("This file contains binary data, therefore it\nisn't possible modify it with the text editor!\nPlease use the hex editor instead!"),
538
                                    T("Ok"));
539
    }
540
}
541
 
542
void MiosFileBrowser::openHexEditor(const Array<uint8>& data)
543
{
544
    // transfer data to both editors
545
    updateEditors(data);
546
 
547
    disableFileButtons();
548
    enableEditorButtons();
549
 
550
    hexEditor->setVisible(true);
551
    hexEditor->setReadOnly(false);
552
}
553
 
1542 tk 554
//==============================================================================
1546 tk 555
void MiosFileBrowser::requestUpdateTreeView(void)
556
{
1554 tk 557
    treeView->setEnabled(true);
1546 tk 558
    currentDirOpenStates = treeView->getOpennessState(true); // including scroll position
559
 
560
    if( rootFileItem )
561
        delete rootFileItem;
562
    rootFileItem = new MiosFileBrowserFileItem(T(""), T("/"), true);
563
    currentDirItem = rootFileItem;
564
 
565
    updateTreeView(false);
566
 
567
    disableFileButtons();
568
    currentDirFetchItems.clear();
569
    currentDirPath = T("/");
570
    sendCommand(T("dir ") + currentDirPath);
571
}
572
 
1542 tk 573
void MiosFileBrowser::updateTreeView(bool accessPossible)
574
{
575
    disableFileButtons();
576
 
577
    if( rootItem )
578
        treeView->deleteRootItem();
579
 
580
    if( rootFileItem ) {
581
        rootItem = new MiosFileBrowserItem(rootFileItem, this);
582
        rootItem->setOpen(true);
583
        treeView->setRootItem(rootItem);
584
 
1546 tk 585
        if( accessPossible ) {
586
            if( currentDirOpenStates ) {
1724 tk 587
                treeView->restoreOpennessState(*currentDirOpenStates, true);
1546 tk 588
                deleteAndZero(currentDirOpenStates);
589
            }
1545 tk 590
 
1542 tk 591
            uploadButton->setEnabled(true);
592
            createDirButton->setEnabled(true);
1555 tk 593
            createFileButton->setEnabled(true);
1542 tk 594
        }
595
    }
596
}
597
 
598
void MiosFileBrowser::treeItemClicked(MiosFileBrowserItem* item)
599
{
600
    disableFileButtons();
601
 
602
    if( item->fileItem->isDirectory ) {
603
        enableDirButtons();
604
    } else {
605
        enableFileButtons();
606
    }
607
}
608
 
609
void MiosFileBrowser::treeItemDoubleClicked(MiosFileBrowserItem* item)
610
{
611
}
612
 
613
//==============================================================================
1554 tk 614
bool MiosFileBrowser::downloadFileSelection(unsigned selection)
1542 tk 615
{
1554 tk 616
    treeView->setEnabled(false);
617
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
1555 tk 618
    currentReadFileBrowserItem = selectedItem;
1542 tk 619
 
1554 tk 620
    if( selectedItem ) {
621
        currentReadFileName = selectedItem->getUniqueName();
1542 tk 622
 
1554 tk 623
        if( openHexEditorAfterRead || openTextEditorAfterRead ) {
624
            disableFileButtons();
625
            sendCommand(T("read ") + currentReadFileName);
626
            return true;
627
        } else {
628
            // restore default path
629
            String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
1724 tk 630
            PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1554 tk 631
            if( propertiesFile ) {
632
                defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
633
            }
634
 
635
            String readFileName(currentReadFileName.substring(currentReadFileName.lastIndexOfChar('/')+1));
636
            File defaultPathFile(defaultPath + "/" + readFileName);
637
            FileChooser myChooser(T("Store ") + currentReadFileName, defaultPathFile);
638
            if( !myChooser.browseForFileToSave(true) ) {
639
                statusLabel->setText(T("Cancled save operation for ") + currentReadFileName, true);
640
            } else {
641
                currentReadFile = myChooser.getResult();
642
 
643
                // store default path
644
                if( propertiesFile ) {
645
                    propertiesFile->setValue(T("defaultFilebrowserPath"), currentReadFile.getParentDirectory().getFullPathName());
646
                }
647
 
648
                currentReadFileStream = NULL;
649
                currentReadFile.deleteFile();
650
                if( !(currentReadFileStream=currentReadFile.createOutputStream()) ||
651
                    currentReadFileStream->failedToOpen() ) {
652
                    AlertWindow::showMessageBox(AlertWindow::WarningIcon,
653
                                                String::empty,
654
                                                T("File cannot be created!"),
655
                                                String::empty);
656
                    statusLabel->setText(T("Failed to open ") + currentReadFile.getFullPathName(), true);
657
                } else {
658
                    disableFileButtons();
659
                    sendCommand(T("read ") + currentReadFileName);
660
                    return true;
661
                }
662
            }
1542 tk 663
        }
1554 tk 664
    }
1542 tk 665
 
1554 tk 666
    // operation not successfull (or no more files)
667
    treeView->setEnabled(true);
668
    enableFileButtons();
669
 
670
    return false;
671
}
672
 
673
bool MiosFileBrowser::downloadFinished(void)
674
{
675
    if( openHexEditorAfterRead ) {
1555 tk 676
        openHexEditor(currentReadData);
1554 tk 677
        statusLabel->setText(T("Editing ") + currentReadFileName, true);
678
        editLabel->setText(currentReadFileName, true);
679
    } else if( openTextEditorAfterRead ) {
1555 tk 680
        openTextEditor(currentReadData);
1554 tk 681
        statusLabel->setText(T("Editing ") + currentReadFileName, true);
682
        editLabel->setText(currentReadFileName, true);
683
    } else if( currentReadFileStream ) {
684
        currentReadFileStream->write((uint8 *)&currentReadData.getReference(0), currentReadData.size());
685
        delete currentReadFileStream;
686
        statusLabel->setText(T("Saved ") + currentReadFile.getFullPathName(), true);
687
 
688
        // try next file (if there is still another selection
689
        downloadFileSelection(++transferSelectionCtr);
690
    }
691
 
692
    return true;
693
}
694
 
695
//==============================================================================
696
bool MiosFileBrowser::deleteFileSelection(unsigned selection)
697
{
698
    treeView->setEnabled(false);
699
    TreeViewItem* selectedItem = treeView->getSelectedItem(selection);
700
 
701
    if( selectedItem ) {
702
        String fileName(selectedItem->getUniqueName());
703
        if( AlertWindow::showOkCancelBox(AlertWindow::WarningIcon,
704
                                         T("Removing ") + fileName,
705
                                         T("Do you really want to remove\n") + fileName + T("?"),
706
                                         T("Remove"),
707
                                         T("Cancel")) ) {
708
            disableFileButtons();
709
            sendCommand(T("del ") + fileName);
710
            return true;
1542 tk 711
        }
712
    }
713
 
1554 tk 714
    // operation finished
715
    requestUpdateTreeView();
716
 
717
    return false;
718
}
719
 
720
bool MiosFileBrowser::deleteFinished(void)
721
{
722
    statusLabel->setText(T("File has been removed!"), true);
723
 
724
    // try next file (if there is still another selection
725
    deleteFileSelection(++transferSelectionCtr);
726
 
1542 tk 727
    return true;
728
}
729
 
1554 tk 730
//==============================================================================
731
bool MiosFileBrowser::createDir(void)
732
{
733
    AlertWindow enterName(T("Creating new Directory"),
734
                          T("Please enter directory name:"),
735
                          AlertWindow::QuestionIcon);
736
 
737
    enterName.addButton(T("Create"), 1);
738
    enterName.addButton(T("Cancel"), 0);
739
    enterName.addTextEditor(T("Name"), String::empty);
740
 
741
    if( enterName.runModalLoop() ) {
742
        String name(enterName.getTextEditorContents(T("Name")));
743
        if( name.length() ) {
1555 tk 744
            if( name[0] == '/' )
745
                sendCommand(T("mkdir ") + name);
746
            else
747
                sendCommand(T("mkdir ") + getSelectedPath() + name);
1554 tk 748
        }        
749
    }
750
 
751
    return false;
752
}
753
 
754
bool MiosFileBrowser::createDirFinished(void)
755
{
756
    statusLabel->setText(T("Directory has been created!"), true);
757
 
758
    requestUpdateTreeView();
759
 
760
    return true;
761
}
762
 
763
//==============================================================================
1555 tk 764
bool MiosFileBrowser::createFile(void)
765
{
766
    AlertWindow enterName(T("Creating new File"),
767
                          T("Please enter filename:"),
768
                          AlertWindow::QuestionIcon);
769
 
770
    enterName.addButton(T("Create"), 1);
771
    enterName.addButton(T("Cancel"), 0);
772
    enterName.addTextEditor(T("Name"), String::empty);
773
 
774
    if( enterName.runModalLoop() ) {
775
        String name(enterName.getTextEditorContents(T("Name")));
776
        if( name.length() ) {
777
            Array<uint8> emptyBuffer;
778
            if( name[0] == '/' )
779
                return uploadBuffer(name, emptyBuffer);
780
            else
781
                return uploadBuffer(getSelectedPath() + name, emptyBuffer);
782
        }        
783
    }
784
 
785
    return false;
786
}
787
 
788
//==============================================================================
1542 tk 789
bool MiosFileBrowser::uploadFile(void)
790
{
791
    // restore default path
792
    String defaultPath(File::getSpecialLocation(File::userHomeDirectory).getFullPathName());
1724 tk 793
    PropertiesFile *propertiesFile = MiosStudioProperties::getInstance()->getCommonSettings(true);
1542 tk 794
    if( propertiesFile ) {
795
        defaultPath = propertiesFile->getValue(T("defaultFilebrowserPath"), defaultPath);
796
    }
797
    File defaultPathFile(defaultPath);
798
    FileChooser myChooser(T("Upload File to Core"), defaultPathFile);
799
    if( !myChooser.browseForFileToOpen() ) {
800
        return false;
801
    } else {
802
        File inFile(myChooser.getResult());
803
 
804
        // store default path
805
        if( propertiesFile ) {
806
            propertiesFile->setValue(T("defaultFilebrowserPath"), inFile.getParentDirectory().getFullPathName());
807
        }
808
 
809
        FileInputStream *inFileStream = inFile.createInputStream();
810
        if( !inFileStream || inFileStream->isExhausted() || !inFileStream->getTotalLength() ) {
811
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
812
                                        T("The file ") + inFile.getFileName(),
813
                                        T("doesn't exist!"),
814
                                        String::empty);
1555 tk 815
        } else if( inFileStream->isExhausted() ) { // || !inFileStream->getTotalLength() -> disabled, we also want to handle zero-length files
1542 tk 816
            AlertWindow::showMessageBox(AlertWindow::WarningIcon,
817
                                        T("The file ") + inFile.getFileName(),
1555 tk 818
                                        T("can't be read!"),
1542 tk 819
                                        String::empty);
820
        } else {
1554 tk 821
            disableFileButtons();
822
 
1542 tk 823
            uint64 size = inFileStream->getTotalLength();
824
            uint8 *buffer = (uint8 *)juce_malloc(size);
1554 tk 825
            size = inFileStream->read(buffer, size);
1542 tk 826
            //currentWriteData.resize(currentWriteSize); // doesn't exist in Juce 1.53
1554 tk 827
            Array<uint8> tmp(buffer, size);
1542 tk 828
            juce_free(buffer);
1554 tk 829
            uploadBuffer(getSelectedPath() + inFile.getFileName(), tmp);
1542 tk 830
        }
1544 tk 831
 
832
        if( inFileStream )
833
            delete inFileStream;
1542 tk 834
    }
835
 
836
    return true;
837
}
838
 
1554 tk 839
bool MiosFileBrowser::uploadBuffer(String filename, const Array<uint8>& buffer)
840
{
841
    currentWriteFileName = filename;
842
    currentWriteData = buffer;
843
    currentWriteSize = buffer.size();
844
 
845
    statusLabel->setText(T("Uploading ") + currentWriteFileName + T(" (") + String(currentWriteSize) + T(" bytes)"), true);
846
 
847
    currentWriteInProgress = true;
848
    currentWriteError = false;
849
    currentWriteFirstBlockOffset = 0;
850
    currentWriteBlockCtr = writeBlockCtrDefault;
851
    currentWriteStartTime = Time::currentTimeMillis();
852
    sendCommand(T("write ") + currentWriteFileName + T(" ") + String(currentWriteSize));
1564 tk 853
    startTimer(5000);
1554 tk 854
 
855
    return true;
856
}
857
 
858
bool MiosFileBrowser::uploadFinished(void)
859
{
860
    currentWriteInProgress = false;
1594 tk 861
    String extraText;
1554 tk 862
 
863
    // finished edit operation?
864
    if( openHexEditorAfterRead || openTextEditorAfterRead ) {
1594 tk 865
#if 0
1554 tk 866
        openHexEditorAfterRead = false;
867
        openTextEditorAfterRead = false;
868
        hexEditor->clear();
869
        hexEditor->setReadOnly(true);
870
        textEditor->clear();
871
        textEditor->setReadOnly(true);
872
        editLabel->setText(String::empty, true);
1594 tk 873
#else
874
        extraText = T(" - you can continue editing; click CANCEL to close editor!");
875
        // don't close editor
876
#endif
1554 tk 877
    }
878
 
879
    uint32 currentWriteFinished = Time::currentTimeMillis();
880
    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
881
    float dataRate = ((float)currentWriteSize/1000.0) / downloadTime;
882
 
1594 tk 883
 
1554 tk 884
    statusLabel->setText(T("Upload of ") + currentWriteFileName +
885
                         T(" (") + String(currentWriteSize) + T(" bytes) completed in ") +
1594 tk 886
                         String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate) +
887
                         extraText, true);
1554 tk 888
 
1594 tk 889
#if 0 // not required
1554 tk 890
    requestUpdateTreeView();
1594 tk 891
#else
892
    if( !openHexEditorAfterRead && !openTextEditorAfterRead ) {
893
        enableFileButtons();
894
    }
895
#endif
1554 tk 896
 
1594 tk 897
 
1554 tk 898
    return true;
899
}
900
 
1542 tk 901
//==============================================================================
902
void MiosFileBrowser::timerCallback()
903
{
904
    if( currentReadInProgress ) {
905
        if( currentReadError ) {
906
            statusLabel->setText(T("Invalid response from MIOS32 core during read operation!"), true);
907
        } else {
908
            statusLabel->setText(T("No response from MIOS32 core during read operation!"), true);
909
        }
910
    } else {
911
        statusLabel->setText(T("No response from MIOS32 core!"), true);
912
    }
913
}
914
 
915
//==============================================================================
916
void MiosFileBrowser::sendCommand(const String& command)
917
{
918
    Array<uint8> dataArray = SysexHelper::createMios32DebugMessage(miosStudio->uploadHandler->getDeviceId());
919
    dataArray.add(0x01); // filebrowser string
920
    for(int i=0; i<command.length(); ++i)
921
        dataArray.add(command[i] & 0x7f);
922
    dataArray.add('\n');
923
    dataArray.add(0xf7);
924
    MidiMessage message = SysexHelper::createMidiMessage(dataArray);
925
    miosStudio->sendMidiMessage(message);
1564 tk 926
    startTimer(5000);
1542 tk 927
}
928
 
929
//==============================================================================
930
void MiosFileBrowser::receiveCommand(const String& command)
931
{
932
    String statusMessage;
933
 
934
    stopTimer(); // will be restarted if required
935
 
936
    if( command.length() ) {
937
        switch( command[0] ) {
938
 
939
        ////////////////////////////////////////////////////////////////////
940
        case '?': {
941
            statusMessage = String(T("Command not supported by MIOS32 application - please check if a firmware update is available!"));
942
        } break;
943
 
944
        ////////////////////////////////////////////////////////////////////
945
        case 'D': {
946
            if( command[1] == '!' ) {
947
                statusMessage = String(T("SD Card not mounted!"));
948
            } else if( command[1] == '-' ) {
949
                statusMessage = String(T("Failed to access directory!"));
950
            } else {
1548 tk 951
                //statusMessage = String(T("Received directory structure."));
1542 tk 952
 
953
                int posStartName = 2;
954
                for(int pos=2; pos<command.length(); ++pos) {
955
                    if( command[pos] == 'F' || command[pos] == 'D' ) {
956
                        for(++pos; pos < command.length() && command[pos] != ','; ++pos);
957
                        String fileName(command.substring(posStartName, pos));
958
                        //std::cout << "XXX " << fileName << std::endl;
959
                        if( fileName[0] == 'F' ) {
1545 tk 960
                            currentDirItem->createChild(currentDirPath, fileName.substring(1), false);
1542 tk 961
                        } else if( fileName[0] == 'D' ) {
1545 tk 962
                            currentDirFetchItems.add(currentDirItem->createChild(currentDirPath, fileName.substring(1), true));
1542 tk 963
                        } else {
1545 tk 964
                            std::cout << "INVALID Response: " << currentDirPath << fileName << std::endl;
1542 tk 965
                            statusMessage = String(T("Invalid Response!"));
966
                            break;
967
                        }
968
                        posStartName = pos+1;
969
                    } else {
970
                        statusMessage = String(T("Invalid Response!"));
971
                        break;
972
                    }
973
                }
974
            }
1545 tk 975
 
976
            // do we have to fetch some additional subdirectories?
977
            if( currentDirFetchItems.size() ) {
978
                currentDirItem = currentDirFetchItems.remove(0);
979
                if( currentDirItem->parentPath.compare(T("/")) == 0 )
980
                    currentDirPath = currentDirItem->parentPath + currentDirItem->name;
981
                else
982
                    currentDirPath = currentDirItem->parentPath + T("/") + currentDirItem->name;
983
                //std::cout << "Fetch " << currentDirPath << std::endl;
984
                sendCommand(T("dir ") + currentDirPath);
985
            } else {
986
                updateTreeView(true);
987
            }
1542 tk 988
        } break;
989
 
990
        ////////////////////////////////////////////////////////////////////
991
        case 'R': {
992
            if( command[1] == '!' ) {
993
                statusMessage = String(T("SD Card not mounted!"));
994
            } else if( command[1] == '-' ) {
1554 tk 995
                statusMessage = String(T("Failed to access " + currentReadFileName + "!"));
1542 tk 996
            } else {
997
                currentReadSize = (command.substring(1)).getIntValue();
998
                currentReadData.clear();
999
                if( currentReadSize ) {
1554 tk 1000
                    statusMessage = String(T("Receiving ") + currentReadFileName + T(" with ") + String(currentReadSize) + T(" bytes."));
1542 tk 1001
                    currentReadInProgress = true;
1002
                    currentReadError = false;
1003
                    currentReadStartTime = Time::currentTimeMillis();
1564 tk 1004
                    startTimer(5000);
1542 tk 1005
                } else {
1554 tk 1006
                    statusMessage = String(currentReadFileName + T(" is empty!"));
1555 tk 1007
                    // ok, we accept this to edit zero-length files
1008
                    // fake transfer:
1009
                    currentReadInProgress = false;
1010
                    currentReadData.clear();
1011
                    statusLabel->setText(statusMessage, true);
1012
                    downloadFinished();
1013
                    statusMessage = String::empty; // status has been updated by downloadFinished()
1542 tk 1014
                }
1015
            }
1016
        } break;
1017
 
1018
        ////////////////////////////////////////////////////////////////////
1019
        case 'r': {
1020
            if( !currentReadInProgress ) {
1021
                statusMessage = String(T("There is a read operation in progress - please wait!"));
1022
            } else {
1023
                String strAddress = command.substring(1, 9);
1024
                String strPayload = command.substring(10);
1025
 
1026
                unsigned address = strAddress.getHexValue32();
1027
 
1028
                if( address >= currentReadSize ) {
1554 tk 1029
                    statusMessage = String(currentReadFileName + T(" received invalid payload!"));
1542 tk 1030
                    currentReadError = true;
1031
                } else {
1032
                    for(int pos=0; pos<strPayload.length(); pos+=2) {
1033
                        uint8 b = (strPayload.substring(pos, pos+2)).getHexValue32();
1034
                        currentReadData.set(address + (pos/2), b);
1035
                    }
1036
 
1037
                    unsigned receivedSize = currentReadData.size();
1038
                    uint32 currentReadFinished = Time::currentTimeMillis();
1039
                    float downloadTime = (float)(currentReadFinished-currentReadStartTime) / 1000.0;
1040
                    float dataRate = ((float)receivedSize/1000.0) / downloadTime;
1041
                    if( receivedSize >= currentReadSize ) {
1554 tk 1042
                        statusMessage = String(T("Download of ") + currentReadFileName +
1542 tk 1043
                                               T(" (") + String(receivedSize) + T(" bytes) completed in ") +
1044
                                               String::formatted(T("%2.1fs (%2.1f kb/s)"), downloadTime, dataRate));
1045
                        currentReadInProgress = false;
1046
 
1047
                        statusLabel->setText(statusMessage, true);
1554 tk 1048
                        downloadFinished();
1049
                        statusMessage = String::empty; // status has been updated by downloadFinished()
1542 tk 1050
                    } else {
1554 tk 1051
                        statusMessage = String(T("Downloading ") + currentReadFileName + T(": ") +
1542 tk 1052
                                               String(receivedSize) + T(" bytes received") +
1053
                                               String::formatted(T(" (%d%%, %2.1f kb/s)"),
1054
                                                                 (int)(100.0*(float)receivedSize/(float)currentReadSize),
1055
                                                                 dataRate));
1564 tk 1056
                        startTimer(5000);
1542 tk 1057
                    }
1058
                }
1059
            }
1060
        } break;
1061
 
1062
        ////////////////////////////////////////////////////////////////////
1063
        case 'W': {
1548 tk 1064
            if( currentWriteError ) {
1065
                // ignore
1066
            } else if( !currentWriteInProgress ) {
1542 tk 1067
                statusMessage = String(T("There is a write operation in progress - please wait!"));
1068
            } else if( command[1] == '!' ) {
1069
                statusMessage = String(T("SD Card not mounted!"));
1070
            } else if( command[1] == '-' ) {
1554 tk 1071
                statusMessage = String(T("Failed to access " + currentWriteFileName + "!"));
1542 tk 1072
            } else if( command[1] == '~' ) {
1073
                statusMessage = String(T("FATAL: invalid parameters for write operation!"));
1074
            } else if( command[1] == '#' ) {
1554 tk 1075
                uploadFinished();
1076
                statusMessage = String::empty; // status has been updated by uploadFinished()
1542 tk 1077
            } else {
1078
                unsigned addressOffset = command.substring(1).getHexValue32();
1079
 
1548 tk 1080
                if( currentWriteBlockCtr < writeBlockCtrDefault ) {
1081
                    // check for valid response
1082
                    unsigned expectedOffset = currentWriteFirstBlockOffset + (writeBlockSizeDefault*(currentWriteBlockCtr+1));
1083
                    if( addressOffset != expectedOffset ) {
1084
                        currentWriteError = true;
1085
                        statusLabel->setText(String::formatted(T("ERROR: the application has requested file position 0x%08X, but filebrowser expected 0x%08X! Please check with TK!"), addressOffset, expectedOffset), true);
1086
                    } else {
1087
                        ++currentWriteBlockCtr; // block received
1088
                    }                    
1542 tk 1089
                }
1090
 
1548 tk 1091
                // new burst?
1092
                if( currentWriteBlockCtr >= writeBlockCtrDefault ) {
1093
                    currentWriteFirstBlockOffset = addressOffset;
1094
                    currentWriteBlockCtr = 0;
1542 tk 1095
 
1548 tk 1096
                    for(unsigned block=0; block<writeBlockCtrDefault; ++block, addressOffset += writeBlockSizeDefault) {
1097
                        String writeCommand(String::formatted(T("writedata %08X "), addressOffset));
1098
                        for(int i=0; i<writeBlockSizeDefault && (i+addressOffset)<currentWriteSize; ++i) {
1099
                            writeCommand += String::formatted(T("%02X"), currentWriteData[addressOffset + i]);
1100
                        }
1101
                        sendCommand(writeCommand);
1102
 
1103
                        if( (writeBlockSizeDefault+addressOffset) >= currentWriteSize )
1104
                            break;
1105
                    }
1106
 
1107
                    uint32 currentWriteFinished = Time::currentTimeMillis();
1108
                    float downloadTime = (float)(currentWriteFinished-currentWriteStartTime) / 1000.0;
1109
                    float dataRate = ((float)addressOffset/1000.0) / downloadTime;
1110
 
1554 tk 1111
                    statusMessage = String(T("Uploading ") + currentWriteFileName + T(": ") +
1548 tk 1112
                                           String(addressOffset) + T(" bytes transmitted") +
1113
                                           String::formatted(T(" (%d%%, %2.1f kb/s)"),
1114
                                                             (int)(100.0*(float)addressOffset/(float)currentWriteSize),
1115
                                                             dataRate));
1564 tk 1116
                    startTimer(5000);
1548 tk 1117
                }
1542 tk 1118
            }
1119
        } break;
1120
 
1121
 
1122
        ////////////////////////////////////////////////////////////////////
1123
        case 'M': {
1124
            if( command[1] == '!' ) {
1125
                statusMessage = String(T("SD Card not mounted!"));
1126
            } else if( command[1] == '-' ) {
1127
                statusMessage = String(T("Failed to create directory!"));
1128
            } else if( command[1] == '#' ) {
1554 tk 1129
                createDirFinished();
1130
                statusMessage = String::empty; // status has been updated by createDirFinished()
1542 tk 1131
            } else {
1132
                statusMessage = String(T("Unsupported response from mkdir command!"));
1133
            }
1134
        } break;
1135
 
1136
 
1137
        ////////////////////////////////////////////////////////////////////
1138
        case 'X': {
1139
            if( command[1] == '!' ) {
1140
                statusMessage = String(T("SD Card not mounted!"));
1141
            } else if( command[1] == '-' ) {
1142
                statusMessage = String(T("Failed to delete file!"));
1143
            } else if( command[1] == '#' ) {
1554 tk 1144
                deleteFinished();
1145
                statusMessage = String::empty; // status has been updated by deleteFinished()
1542 tk 1146
            } else {
1147
                statusMessage = String(T("Unsupported response from del command!"));
1148
            }
1149
        } break;
1150
 
1151
 
1152
        ////////////////////////////////////////////////////////////////////
1153
        default:
1154
            statusMessage = String(T("Received unsupported Filebrowser Command! Please update your MIOS Studio installation!"));
1155
        }
1156
    }
1157
 
1158
    if( statusMessage.length() ) {
1159
        statusLabel->setText(statusMessage, true);
1160
    }
1161
}
1162
 
1163
//==============================================================================
1164
void MiosFileBrowser::handleIncomingMidiMessage(const MidiMessage& message, uint8 runningStatus)
1165
{
1724 tk 1166
    uint8 *data = (uint8 *)message.getRawData();
1542 tk 1167
    uint32 size = message.getRawDataSize();
1168
    int messageOffset = 0;
1169
 
1170
    bool messageReceived = false;
1171
    if( runningStatus == 0xf0 &&
1172
        SysexHelper::isValidMios32DebugMessage(data, size, -1) &&
1173
        data[7] == 0x41 ) {
1174
            messageOffset = 8;
1175
            messageReceived = true;
1176
    } else if( runningStatus == 0xf0 &&
1177
        SysexHelper::isValidMios32Error(data, size, -1) &&
1178
        data[7] == 0x10 ) {
1179
        stopTimer();
1180
        statusLabel->setText(T("Filebrowser access not implemented by this application!"), true);
1181
    }
1182
 
1183
    if( messageReceived ) {
1184
        String command;
1185
 
1186
        for(int i=messageOffset; i<size; ++i) {
1187
            if( data[i] < 0x80 ) {
1188
                if( data[i] != '\n' || size < (i+1) )
1189
                    command += String::formatted(T("%c"), data[i] & 0x7f);
1190
            }
1191
        }
1192
        receiveCommand(command);
1193
    }
1194
}