root/src/preferences/repositories/RepositoriesWindow.cpp
/*
 * Copyright 2017 Haiku Inc. All rights reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Brian Hill
 */


#include "RepositoriesWindow.h"

#include <Alert.h>
#include <Application.h>
#include <Catalog.h>
#include <FindDirectory.h>
#include <LayoutBuilder.h>
#include <NodeMonitor.h>
#include <Region.h>
#include <Screen.h>

#include "AddRepoWindow.h"
#include "constants.h"


#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "RepositoriesWindow"


RepositoriesWindow::RepositoriesWindow()
        :
        BWindow(BRect(50, 50, 500, 400), B_TRANSLATE_SYSTEM_NAME("Repositories"),
                B_TITLED_WINDOW, B_NOT_ZOOMABLE | B_ASYNCHRONOUS_CONTROLS
                        | B_AUTO_UPDATE_SIZE_LIMITS),
        fAddWindow(NULL),
        fPackageNodeStatus(B_ERROR)
{
        fView = new RepositoriesView();
        BLayoutBuilder::Group<>(this, B_VERTICAL).Add(fView).End();

        // Size and location on screen
        BRect frame = fSettings.GetFrame();
        ResizeTo(frame.Width(), frame.Height());
        BScreen screen;
        BRect screenFrame = screen.Frame();
        if (screenFrame.right < frame.right || screenFrame.left > frame.left
                || screenFrame.top > frame.top || screenFrame.bottom < frame.bottom) {
                CenterOnScreen();
        }
        else
                MoveTo(frame.left, frame.top);
        Show();

        fMessenger.SetTo(this);

        // Find the pkgman settings or cache directory
        BPath packagePath;
        // /boot/system/settings/package-repositories
        status_t status = find_directory(B_SYSTEM_SETTINGS_DIRECTORY,
                &packagePath);
        if (status == B_OK)
                status = packagePath.Append("package-repositories");
        else {
                // /boot/system/cache/package-repositories
                status = find_directory(B_SYSTEM_CACHE_DIRECTORY, &packagePath);
                if (status == B_OK)
                        status = packagePath.Append("package-repositories");
        }
        if (status == B_OK) {
                BNode packageNode(packagePath.Path());
                if (packageNode.InitCheck()==B_OK && packageNode.IsDirectory())
                        fPackageNodeStatus = packageNode.GetNodeRef(&fPackageNodeRef);
        }

        // watch the pkgman settings or cache directory for changes
        _StartWatching();
}


RepositoriesWindow::~RepositoriesWindow()
{
        _StopWatching();
}


void
RepositoriesWindow::_StartWatching()
{
        if (fPackageNodeStatus == B_OK) {
                status_t result = watch_node(&fPackageNodeRef, B_WATCH_DIRECTORY, this);
                fWatchingPackageNode = (result == B_OK);
        }
}


void
RepositoriesWindow::_StopWatching()
{
        if (fPackageNodeStatus == B_OK && fWatchingPackageNode) {
                watch_node(&fPackageNodeRef, B_STOP_WATCHING, this);
                fWatchingPackageNode = false;
        }
}


bool
RepositoriesWindow::QuitRequested()
{
        if (fView->IsTaskRunning()) {
                BAlert *alert = new BAlert("tasks",
                        B_TRANSLATE_COMMENT("Some tasks are still running. Stop these "
                                "tasks and quit?", "Application quit alert message"),
                        B_TRANSLATE_COMMENT("Stop and quit", "Button label"),
                        kCancelLabel, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
                alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
                int32 result = alert->Go();
                if (result != 0)
                        return false;
        }
        fSettings.SetFrame(Frame());
        be_app->PostMessage(B_QUIT_REQUESTED);
        return BWindow::QuitRequested();
}


void
RepositoriesWindow::MessageReceived(BMessage* message)
{
        switch (message->what)
        {
                case ADD_REPO_WINDOW:
                {
                        BRect frame = Frame();
                        fAddWindow = new AddRepoWindow(frame, fMessenger);
                        break;
                }
                
                case ADD_REPO_URL:
                {
                        BString url;
                        status_t result = message->FindString(key_url, &url);
                        if (result == B_OK)
                                fView->AddManualRepository(url);
                        break;
                }
                
                case ADD_WINDOW_CLOSED:
                {
                        fAddWindow = NULL;
                        break;
                }
                
                case DELETE_KEY_PRESSED:
                {
                        BMessage message(REMOVE_REPOS);
                        fView->MessageReceived(&message);
                        break;
                }
                
                // captures pkgman changes while the Repositories application is running
                case B_NODE_MONITOR:
                {
                        // This preflet is making the changes, so ignore this message
                        if (fView->IsTaskRunning())
                                break;

                        int32 opcode;
                        if (message->FindInt32("opcode", &opcode) == B_OK) {
                                switch (opcode)
                                {
                                        case B_ATTR_CHANGED:
                                        case B_ENTRY_CREATED:
                                        case B_ENTRY_REMOVED:
                                        {
                                                PostMessage(UPDATE_LIST, fView);
                                                break;
                                        }
                                }
                        }
                        break;
                }
                
                default:
                        BWindow::MessageReceived(message);
        }
}